summaryrefslogtreecommitdiff
blob: 20acaa7fbdfdf486fee65075fb1ddf589f446f39 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# Check for pkg-config file issues

pkgconfig_check() {
	local files=()
	# Make a list of .pc files and bail out if there aren't any
	mapfile -d '' files < <(
		find "${ED}"/usr/{lib*,share}/pkgconfig -maxdepth 1 -type f -name '*.pc' -print0 2>/dev/null
	)
	[[ -z "${files[@]}" ]] && return

	local f

	# Look for leaking LDFLAGS into pkg-config files
	f=$(grep -E -zsH '^Libs.*-Wl,(-O[012]|--hash-style)' "${files[@]}")
	if [[ -n ${f} ]] ; then
		eqawarn "QA Notice: pkg-config files with wrong LDFLAGS detected:"
		eqatag -v pkgconfig.bad-ldlags "${f//${D}}"
	fi

	# Bail out now so we can rely on pkgconfig in subsequent checks if we want.
	if ! type -P pkg-config >/dev/null ; then
		return
	fi

	# Validate using pkgconfig
	# Some less common implementations may not support this?
	# seems like f.d.o, OpenBSD, and of course pkgconf do though.
	# Need --maximum-traverse-depth=1 to avoid checking deps and giving
	# unrelated warnings/errors.
	if ! pkg-config --maximum-traverse-depth=1 --with-path="${ED}"/usr/{lib*,share}/pkgconfig --validate "${files[@]}" ; then
		eqawarn "QA Notice: pkg-config files which fail validation found!"
		eqawarn "Run 'pkg-config --validate ...' for more information"
	fi

	# Check for unexpected paths
	# e.g. https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=c90ab38e3577aae61fac2341b34ad593948de1cd
	if [[ -n ${EPREFIX} ]] ; then
		for f in "${files[@]}" ; do
			local key
			for key in prefix exec_prefix libdir includedir ; do
				# Check if the variable is even in there (bug #860825)
				grep -E -q "^${key}" "${f}" || continue

				local value=$(pkg-config --variable="${key}" "${f}")

				if [[ ${value} != "${EPREFIX}"* ]] ; then
					eqawarn "QA Notice: pkg-config files not respecting EPREFIX found"
					eqawarn "key=${key} does not respect EPREFIX:"
					eqawarn "${key}=${value}"
					eqatag -v pkgconfig.bad-paths ${key}="${value}" "${f//${D}}"

					# Don't bother repeating for every variable in the same file
					break
				fi
			done
		done
	fi

	# TODO: Generalise for non-lib64 libdir? Not that this is very common now
	# that riscv chose a more standard layout.
	#
	# If we're installing to ${ED}/usr/lib/pkgconfig, let's make sure
	# we're not referencing lib64.
	#
	# e.g. https://bugs.gentoo.org/729642
	local bad_libdir=()
	for f in "${files[@]}" ; do
		if [[ ${f} == *lib/pkgconfig* ]] ; then
			if [[ -d "${ED}"/usr/lib && -L "${ED}"/usr/lib ]] ; then
				# (Don't bother if /usr/lib is a symlink to /usr/lib64)
				continue
			fi

			# In ${ED}/usr/lib, we shouldn't reference lib64
			if grep -E -q "=(/usr)?/lib64" ${f} ; then
				bad_libdir+=( "${f//${D}}" )
			fi
		elif [[ ${f} == *lib64/pkgconfig* ]] ; then
			# We want to match /lib/, /lib/foo/, but not e.g. /lib64 or /lib64/, or libfoo
			if grep -qP '=(/usr)?/lib\b' ${f} ; then
				bad_libdir+=( "${f//${D}}" )
			fi
		fi
	done

	if [[ -n "${bad_libdir[@]}" ]] ; then
		eqawarn "QA Notice: pkg-config files not respecting libdir found"
		eqawarn "(contains reference to either lib or lib64 in wrong directory)"
		eqatag -v pkgconfig.bad-libdir "${bad_libdir[@]}"
	fi

	# Check for mismatched Version field vs ${PV}
	# To be safe, let's make sure _all_ installed .pcs have a bad Version
	# before warning, as this should catch the general cases we're worried
	# about, while avoiding any pathological cases e.g. multiple libraries
	# with different versioning within one package.
	# Example bugs: bug #833895, bug #833887.

	# Default to PV if QA_PKGCONFIG_VERSION is unset.
	if [[ -z ${QA_PKGCONFIG_VERSION+set} ]]; then
		local QA_PKGCONFIG_VERSION=${PV}
	fi

	# Skip the check if QA_PKGCONFIG_VERSION is set to empty string.
	if [[ -n ${QA_PKGCONFIG_VERSION} ]]; then
		local pms_ver_re="^([0-9]+(\.[0-9]+)*)([a-z]?)((_(alpha|beta|pre|rc|p)[0-9]*)*)(-r[0-9]+)?$"
		local -A bad_files

		local is_pms_ver=false
		if [[ ${QA_PKGCONFIG_VERSION} =~ ${pms_ver_re} ]] ; then
			# Ensure that ver_test is available.
			[[ $(type -t ver_test) == function ]] || inherit eapi7-ver
			is_pms_ver=true
		fi

		for f in "${files[@]}" ; do
			local file_version=$(pkg-config --modversion "${f}")
			if [[ -n ${file_version} ]] ; then
				if ${is_pms_ver} && [[ ${file_version} =~ ${pms_ver_re} ]]; then
					# If both versions comply to PMS, then we can use ver_test to compare them.
					ver_test ${QA_PKGCONFIG_VERSION} -eq ${file_version} && continue
				else
					# Otherwise, we resort to string comparision.
					[[ ${QA_PKGCONFIG_VERSION} == ${file_version} ]] && continue
				fi
			else
				# Record a special value if the .pc file has no version set at all.
				file_version="<no-set>"
			fi

			bad_files["${f//${D}}"]="${file_version}"
		done

		# Skip result reporting if *_p* because for both _pN and _preN, we
		# don't generally expect the versions to be exactly accurate, and
		# we want to avoid false positives.
		if [[ ${#bad_files[@]} -gt 0 && ${PV} != *_p* ]] && ! has live ${PROPERTIES} ; then
			eqawarn "QA Notice: pkg-config files with mismatched Version found!"
			eqawarn "The Version field of the following files does not match ${PV}"
			local bad_file
			for bad_file in "${!bad_files[@]}"; do
				local bad_file_version="${bad_files[${bad_file}]}"
				eqawarn "- ${bad_file}: ${bad_file_version}"
			done
			eqawarn "Please check all .pc files installed by this package."
			eqawarn "You can use QA_PKGCONFIG_VERSION to set the expected version,"
			eqawarn "or set to the empty string to disable this QA check."
			eqatag pkgconfig.unexpected-version ${!bad_files[@]}
		fi
	fi
}

pkgconfig_check
: # guarantee successful exit

# vim:ft=sh