aboutsummaryrefslogtreecommitdiff
blob: adea7d4051d095b232cec5efcd0ed8f11a787d21 (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
# Check for implicit function declaration warnings in configure logs
#
# ebuilds should set the QA_CONFIG_IMPL_DECL_SKIP array to skip known false
# positives.
#
# Some examples of logs to look for:
# bash: work/bash-5.1/config.log
#       ^---  easy
# python: work/Python-3.10.9/config.log
#         ^---  easy
# gcc: work/build/config.log
#      ^---  can be out-of-tree
# clang: work/x/y/clang-abi_x86_64.amd64/CMakeFiles/CMakeError.log
#        ^---  can be non-autotools (and very deep)
# systemd-utils: work/systemd-stable-251.10-abi_x86_64.amd64/meson-logs/meson-log.txt
#                ^---  can be non-autotools
#
# Adapted from macports portconfigure.tcl with love.
#
# See also: bug 892651

# Same as the "has" function, but allows wildcards in the array
is_in() {
	local needle=$1
	shift

	local x
	for x in "$@"; do
		[[ "${needle}" = ${x} ]] && return 0
	done
	return 1
}

add_default_skips() {
	# Skip built-in functions provided by the compiler
	QA_CONFIG_IMPL_DECL_SKIP+=(
		"__builtin_*"
		# https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html
		"__sync_*"
		# https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
		"__atomic_*"
	)

	# Functions not available on Linux
	[[ ${CHOST} == *linux* ]] && QA_CONFIG_IMPL_DECL_SKIP+=(
		acl
		acl_get_perm_np
		res_getservers
		res_ndestroy
		statacl
	)

	QA_CONFIG_IMPL_DECL_SKIP+=(
		# Available in c23, these gnulib checks are expected to fail
		alignof
		static_assert
		unreachable
		# also gnulib, but checks both linux/non-linux headers
		MIN
	)
}

find_log_targets() {
	local log_targets=(
		'config.log'
		'CMakeError.log'
		'meson-log.txt'
	)
	local find_args=()
	local log

	# Find config logs. Assume the dirs can have spaces in them, even though
	# that is hella evil and goes against good filesystem manners!
	for log in "${log_targets[@]}"; do
		find_args+=( '-name' "${log}" '-o' )
	done
	unset -v 'find_args[-1]'
	printf '%s\0' "${WORKDIR}" |
		find -files0-from - -type f \( "${find_args[@]}" \) -print0
}

has_utf8_ctype() {
	# Use python to check if the locale is UTF-8 since tools like locale(1) may
	# not exist (eg, musl systems).
	[[ "$("${PORTAGE_PYTHON:-/usr/bin/python}" -c 'import locale; print(locale.getlocale()[1])')" == UTF-8 ]]
}

config_impl_decl_check() {
	local files=()
	local lines=()
	local funcs=()
	local l
	local entry
	local line
	local func
	local re_uni
	local re_asc
	local is_utf8

	add_default_skips

	# Given the UTF-8 character type, both gcc and clang may enclose the
	# function name between the LEFT SINGLE QUOTATION MARK and RIGHT SINGLE
	# QUOTATION MARK codepoints.
	re_uni=$' function \u2018([^\u2019]+)\u2019'

	# This variant matches ASCII single quotes.
	re_asc=$' function \x27([^\x27]+)\x27'

	# Is UTF-8 the effective character type?
	has_utf8_ctype; is_utf8=$(( $? == 0 ))

	# Iterate over every log file found and check for '-Wimplicit-function-declaration'
	while IFS= read -rd '' l; do
		while IFS= read -ru3 entry; do
			# Strip ANSI codes (color and erase in line have been seen at least)
			entry="$(printf '%s\n' "${entry}" | LC_ALL='C' sed -E -e $'s/\033\[[0-9;]*[A-Za-z]//g')"

			line="${entry%%:*}"
			if [[ ${is_utf8} -eq 1 && ${entry} =~ ${re_uni} ]] || [[ ${entry} =~ ${re_asc} ]]; then
				func="${BASH_REMATCH[1]}"
			else
				continue
			fi

			is_in "${func}" "${QA_CONFIG_IMPL_DECL_SKIP[@]}" && continue

			files+=( "${l}" )
			lines+=( "${line}" )
			funcs+=( "${func}" )
		# Using -I to ignore binary files is a GNU extension for grep
		done 3< <(grep -nEI -e '-W(error=)?implicit-function-declaration' "${l}")
	done < <(find_log_targets)

	# Drop out early if no impl decls found (all the arrays are the same size)
	[[ ${#files[@]} -eq 0 ]] && return

	eqawarn 'QA Notice: Found the following implicit function declarations in configure logs:'
	for l in "${!files[@]}"; do
		eqawarn "  ${files[l]}:${lines[l]} - ${funcs[l]}"
		eqatag 'config.log-impl-decl' "line=${lines[l]}" "func=${funcs[l]}" "${files[l]}"
	done
	eqawarn 'Check that no features were accidentally disabled.'
	eqawarn 'See https://wiki.gentoo.org/wiki/Modern_C_porting.'
}

config_impl_decl_check
: # guarantee successful exit

# vim:ft=sh noexpandtab: