[libcamera-devel,v3,2/3] utils: ABI Compatibility checker
diff mbox series

Message ID 20230704142435.3490823-3-kieran.bingham@ideasonboard.com
State Accepted
Headers show
Series
  • Use x.y soname versioning
Related show

Commit Message

Kieran Bingham July 4, 2023, 2:24 p.m. UTC
Provide support to compare ABI compatibility between any two git commits
or by a commit and the most recent ancestral tag of that commit.

Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

---
v3
  - use '--force' for git worktree add to prevent issues on cancelled
    builds

  - define 'libdir' and 'prefix' explicitly to prevent reliance on
    system defaults.

  - many fixups thanks to Laurents review.

  - abi-compat now fails correctly in case of error. (This means it can
    only run on trees that have the patch 1/3 of this series applied).


 utils/abi-compat.sh | 212 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 212 insertions(+)
 create mode 100755 utils/abi-compat.sh

Comments

Laurent Pinchart July 4, 2023, 2:36 p.m. UTC | #1
Hi Kieran,

Thank you for the patch.

On Tue, Jul 04, 2023 at 03:24:34PM +0100, Kieran Bingham via libcamera-devel wrote:
> Provide support to compare ABI compatibility between any two git commits
> or by a commit and the most recent ancestral tag of that commit.
> 
> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> 
> ---
> v3
>   - use '--force' for git worktree add to prevent issues on cancelled
>     builds
> 
>   - define 'libdir' and 'prefix' explicitly to prevent reliance on
>     system defaults.
> 
>   - many fixups thanks to Laurents review.
> 
>   - abi-compat now fails correctly in case of error. (This means it can
>     only run on trees that have the patch 1/3 of this series applied).
> 
> 
>  utils/abi-compat.sh | 212 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 212 insertions(+)
>  create mode 100755 utils/abi-compat.sh
> 
> diff --git a/utils/abi-compat.sh b/utils/abi-compat.sh
> new file mode 100755
> index 000000000000..785d081d6e1c
> --- /dev/null
> +++ b/utils/abi-compat.sh
> @@ -0,0 +1,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 "$@" >> /dev/stderr

	echo "$@" >&2

Same below.

> +}
> +
> +die () {
> +	echo "$name: $*" >> /dev/stderr
> +	exit 128

The usual exit code in case of failure is 1.

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> +}
> +
> +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
Umang Jain July 4, 2023, 6:48 p.m. UTC | #2
Hi Kieran,

On 7/4/23 4:24 PM, Kieran Bingham via libcamera-devel wrote:
> Provide support to compare ABI compatibility between any two git commits
> or by a commit and the most recent ancestral tag of that commit.
>
> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
Tested-by: Umang Jain <umang.jain@ideasonboard.com>

>
> ---
> v3
>    - use '--force' for git worktree add to prevent issues on cancelled
>      builds
>
>    - define 'libdir' and 'prefix' explicitly to prevent reliance on
>      system defaults.
>
>    - many fixups thanks to Laurents review.
>
>    - abi-compat now fails correctly in case of error. (This means it can
>      only run on trees that have the patch 1/3 of this series applied).
>
>
>   utils/abi-compat.sh | 212 ++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 212 insertions(+)
>   create mode 100755 utils/abi-compat.sh
>
> diff --git a/utils/abi-compat.sh b/utils/abi-compat.sh
> new file mode 100755
> index 000000000000..785d081d6e1c
> --- /dev/null
> +++ b/utils/abi-compat.sh
> @@ -0,0 +1,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 "$@" >> /dev/stderr
> +}
> +
> +die () {
> +	echo "$name: $*" >> /dev/stderr
> +	exit 128
> +}
> +
> +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

Patch
diff mbox series

diff --git a/utils/abi-compat.sh b/utils/abi-compat.sh
new file mode 100755
index 000000000000..785d081d6e1c
--- /dev/null
+++ b/utils/abi-compat.sh
@@ -0,0 +1,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 "$@" >> /dev/stderr
+}
+
+die () {
+	echo "$name: $*" >> /dev/stderr
+	exit 128
+}
+
+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