summaryrefslogtreecommitdiff
path: root/utils/abi-compat.sh
blob: c936ac05b37c504006ad1c023e10074efa62a871 (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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#!/bin/bash

# SPDX-License-Identifier: GPL-2.0-or-later
# Generate and compare the ABI compatibilty of two libcamera versions

name=$(basename "$0")

usage() {
	cat << EOF
$name: Determine the ABI/API compatibility of two build versions

  $name [--help] [--abi-dir=<PATH>] [--tmp-dir=<PATH>] ARGS

The positional arguments (ARGS) determine the versions that will be compared and
take three variants:

  - No positional arguments:
      $name [optional arguments]

      It is assumed to compare the current git HEAD against the most recent TAG

  - One positional argument:
      $name [optional aguments] COMMITISH

      The given COMMITISH is compared against it's most recent TAG

  - Two positional arguments:
      $name [optional aguments] BASE COMMITISH

      The given COMMITISH is compared against the given BASE.

Optional Arguments:
  --abi-dir <path> Use <path> for storing (or retrieving existing) ABI data
                   files

  --tmp-dir <path> Specify temporary build location for building ABI data.
                   This could be a tmpfs/RAM disk to save on disk writes.
EOF
}

dbg () {
	echo "$@" >&2
}

die () {
	echo "$name: $*" >&2
	exit 1
}

describe () {
	git describe --tags "$1" \
		|| die "Failed to describe $1"
}

prev_release () {
	git describe --tags --abbrev=0 "$1"^ \
		|| die "Failed to identify previous release tag from $1"
}

# Make sure we exit on errors during argument parsing.
set -Eeuo pipefail

positional=()
while [[ $# -gt 0 ]] ; do
	option="$1"
	shift

	case $option in
	-h|--help)
		usage
		exit 0
	        ;;

	--abi-dir)
		abi_dir=$1
		shift
		;;

	--tmp-dir)
		tmp=$1
		shift
		;;

	-*)
		die "Unrecognised argument $option"
		;;

	*) # Parse unidentified arguments based on position.
		positional+=("$option")
		;;
	esac
done
set -- "${positional[@]}" # restore positional parameters.

# Parse positional arguments.
case $# in
	0) 	# Check HEAD against previous 'release'.
		from=$(prev_release HEAD)
		to=$(describe HEAD)
		;;

	1)	# Check COMMIT against previous release.
		from=$(prev_release "$1")
		to=$(describe "$1")
		;;

	2)	# Check ABI between FROM and TO explicitly.
		from=$(describe "$1")
		to=$(describe "$2")
		;;

	*)
		die "Invalid arguments"
		;;
esac

if ! which abi-compliance-checker; then
	die "This tool requires 'abi-compliance-checker' to be installed."
fi


abi_dir=${abi_dir:-abi}
tmp=${tmp:-"$abi_dir/tmp/"}

echo "Validating ABI compatibility between $from and $to"

mkdir -p "$abi_dir"
mkdir -p "$tmp"

# Generate an abi-compliance-checker xml description file.
create_xml() {
	local output="$1"
	local version="$2"
	local root="$3"

	echo "<version>$version</version>" > "$output"
	echo "<headers>$root/usr/local/include/</headers>" >> "$output"
	echo "<libs>$root/usr/local/lib/</libs>" >> "$output"
}

# Check if an ABI dump file exists, and if not create one by building a minimal
# configuration of libcamera at the specified version using a clean worktree.
create_abi_dump() {
	local version="$1"
	local abi_file="$abi_dir/$version.abi.dump"
	local worktree="$tmp/$version"
	local build="$tmp/$version-build"

	# Use a fully qualified path when calling ninja -C.
	install=$(realpath "$tmp/$version-install")

	if [[ ! -e "$abi_file" ]] ; then
		dbg "Creating ABI dump for $version in $abi_dir"
		git worktree add --force "$worktree" "$version"

		# Generate a minimal libcamera build. "lib" and "prefix" are
		# defined explicitly to avoid system default ambiguities.
		meson setup "$build" "$worktree" \
			-Dlibdir=lib \
			-Dprefix=/usr/local/ \
			-Ddocumentation=disabled \
			-Dcam=disabled \
			-Dqcam=disabled \
			-Dgstreamer=disabled \
			-Dlc-compliance=disabled \
			-Dtracing=disabled \
			-Dpipelines=

		ninja -C "$build"
		DESTDIR="$install" ninja -C "$build" install

		# Create an xml descriptor with parameters to generate the dump file.
		create_xml \
			"$install/libcamera-abi-dump.xml" \
			"$version" \
			"$install"

		abi-compliance-checker \
			-lib libcamera \
			-v1 "$version" \
			-dump "$install/libcamera-abi-dump.xml" \
			-dump-path "$abi_file"

		dbg Created "$abi_file"

		dbg Removing Worktree "$worktree"
		git worktree remove -f "$worktree"

		dbg Removing "$build"
		rm -r "$build"

		dbg Removing "$install"
		rm -r "$install"
	fi
}

# Create the requested ABI dump files if they don't yet exist.
create_abi_dump "$from"
create_abi_dump "$to"

# TODO: Future iterations and extensions here could add "-stdout -xml" and
# parse the results automatically.
abi-compliance-checker -l libcamera \
	-old "$abi_dir/$from.abi.dump" \
	-new "$abi_dir/$to.abi.dump"

# On (far too many) occasions, the tools keep running leaving a cpu core @ 100%
# CPU usage. Perhaps some subprocess gets launched but never rejoined. Stop
# them all.
#
# TODO: Investigate this and report upstream.
killall abi-compliance-checker 2>/dev/null