Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ABI compatibility tasks to EVG config (CXX-641, CXX-2746) #1083

Merged
merged 5 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .evergreen/abi-compliance-check-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env bash

set -o errexit
set -o pipefail

declare working_dir
working_dir="$(pwd)"

export PATH
PATH="${working_dir:?}/install/bin:${PATH:-}"

# Install prefix to use for ABI compatibility scripts.
[[ -d "${working_dir}/install" ]]

declare parallel_level
parallel_level="$(("$(nproc)" + 1))"

# Obtain abi-compliance-checker.
echo "Fetching abi-compliance-checker..."
[[ -d checker ]] || {
git clone -b "2.3" --depth 1 https://github.com/lvc/abi-compliance-checker.git checker
pushd checker
make -j "${parallel_level:?}" --no-print-directory install prefix="${working_dir:?}/install"
popd # checker
} >/dev/null
echo "Fetching abi-compliance-checker... done."

# Obtain ctags.
echo "Fetching ctags..."
[[ -d ctags ]] || {
git clone -b "v6.0.0" --depth 1 https://github.com/universal-ctags/ctags.git ctags
pushd ctags
./autogen.sh
./configure --prefix="${working_dir}/install"
make -j "${parallel_level:?}"
make install
popd # ctags
} >/dev/null
echo "Fetching ctags... done."

command -V abi-compliance-checker
146 changes: 146 additions & 0 deletions .evergreen/abi-compliance-check-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#!/usr/bin/env bash

set -o errexit
set -o pipefail

declare working_dir
working_dir="$(pwd)"

declare base current
base="$(cat base-commit.txt)"
current="$(cat current-commit.txt)"

export PATH
PATH="${working_dir:?}/install/bin:${PATH:-}"

# Remove 'r' prefix in version string.
declare old_ver new_ver
old_ver="${base:1}-base"
new_ver="${current:1}-current"

command -V abi-compliance-checker >/dev/null

mkdir cxx-abi cxx-noabi

cat >cxx-abi/old.xml <<DOC
<version>
${old_ver:?}
</version>

<headers>
../install/old/include/bsoncxx/
../install/old/include/mongocxx/
</headers>

<skip_headers>
/v_noabi/
</skip_headers>

<libs>
../install/old/lib
</libs>

<add_include_paths>
../install/old/include/
</add_include_paths>

<skip_including>
bsoncxx/enums/
/config/
</skip_including>
DOC

cat >cxx-abi/new.xml <<DOC
<version>
${new_ver:?}
</version>

<headers>
../install/new/include/mongocxx/
../install/new/include/bsoncxx/
</headers>

<skip_headers>
/v_noabi/
</skip_headers>

<libs>
../install/new/lib
</libs>

<add_include_paths>
../install/new/include/
</add_include_paths>

<skip_including>
bsoncxx/enums/
/config/
</skip_including>
DOC

cat >cxx-noabi/old.xml <<DOC
<version>
${old_ver:?}
</version>

<headers>
../install/old/include/bsoncxx/v_noabi
../install/old/include/mongocxx/v_noabi
</headers>

<libs>
../install/old/lib
</libs>

<add_include_paths>
../install/old/include/
</add_include_paths>

<skip_including>
bsoncxx/enums/
/config/
</skip_including>
DOC

cat >cxx-noabi/new.xml <<DOC
<version>
${new_ver:?}
</version>

<headers>
../install/new/include/bsoncxx/v_noabi
../install/new/include/mongocxx/v_noabi
</headers>

<libs>
../install/new/lib
</libs>

<add_include_paths>
../install/new/include/
</add_include_paths>

<skip_including>
bsoncxx/enums/
/config/
</skip_including>
DOC

# Allow task to upload the HTML report despite failed status.
echo "Generating stable ABI report..."
pushd cxx-abi
if ! abi-compliance-checker -lib mongo-cxx-driver -old old.xml -new new.xml; then
: # CXX-2812: enable code below once stable ABI symbols exist in the base commit libraries.
# declare status
# status='{"status":"failed", "type":"test", "should_continue":true, "desc":"abi-compliance-checker emitted one or more errors"}'
# curl -sS -d "${status:?}" -H "Content-Type: application/json" -X POST localhost:2285/task_status || true
fi
popd # cxx-abi
echo "Generating stable ABI report... done."

# Also create a report for the unstable ABI. Errors are expected and OK.
echo "Generating unstable ABI report..."
pushd cxx-noabi
abi-compliance-checker -lib mongo-cxx-driver -old old.xml -new new.xml || true
popd # cxx-noabi
echo "Generating unstable ABI report... done."
44 changes: 44 additions & 0 deletions .evergreen/abi-prohibited-symbols-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env bash

set -o errexit
set -o pipefail

command -V nm >/dev/null

declare -a libs
libs=(
install/new/lib/libbsoncxx.so
install/new/lib/libmongocxx.so
)

for lib in "${libs[@]}"; do
[[ -f "${lib:?}" ]] || {
echo "error: missing ${lib:?}"
exit 1
} 1>&2
done

# Patterns for library symbols to check.
match_pattern=(
-e '(bsoncxx|mongocxx)::'
)

# Patterns for bad symbols.
bad_pattern=(
-e '(bsoncxx|mongocxx)::(.+::)?detail::'
-e '(bsoncxx|mongocxx)::(.+::)?test::'
)

# Ensure implementation details do not leak into the ABI.
mapfile -t bad_symbols < <(
nm --demangle --dynamic --defined-only --extern-only --just-symbols "${libs[@]}" |
grep -E "${match_pattern[@]}" |
grep -E "${bad_pattern[@]}"
)

# Print list of bad symbols.
(("${#bad_symbols[*]}" == 0)) || {
echo "error: found ${#bad_symbols[@]} prohibited symbols in exported ABI:"
printf " - %s\n" "${bad_symbols[@]}"
exit 1
} 1>&2
115 changes: 115 additions & 0 deletions .evergreen/abi-stability-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env bash

set -o errexit
set -o pipefail

: "${cxx_standard:?}" # Set by abi-stability-checks-* build variant definition.

command -V git >/dev/null

# Files prepared by EVG config.
[[ -d "mongoc" ]] || {
echo "missing mongoc" 1>&2
exit 1
}
[[ -d "mongo-cxx-driver" ]] || {
echo "missing mongo-cxx-driver" 1>&2
exit 1
}

declare working_dir
working_dir="$(pwd)"

declare cmake_binary
# shellcheck source=/dev/null
. ./mongoc/.evergreen/scripts/find-cmake-latest.sh
cmake_binary="$(find_cmake_latest)"
command -V "${cmake_binary:?}"

# To use a different base commit, replace `--abbrev 0` with the intended commit.
# Note: EVG treat all changes relative to the EVG base commit as staged changes!
declare base current
base="$(git -C mongo-cxx-driver describe --tags --abbrev=0)"
current="$(git -C mongo-cxx-driver describe --tags)"

echo "Old Version (Base): ${base:?}"
echo "New Version (Current): ${current:?}"

printf "%s" "${base:?}" >base-commit.txt
printf "%s" "${current:?}" >current-commit.txt

# Remove 'r' prefix in version string.
declare old_ver new_ver
old_ver="${base:1}"
new_ver="${current:1}"

declare parallel_level
parallel_level="$(("$(nproc)" + 1))"

# Use Ninja if available.
if command -V ninja; then
export CMAKE_GENERATOR
CMAKE_GENERATOR="Ninja"
else
export CMAKE_BUILD_PARALLEL_LEVEL
CMAKE_BUILD_PARALLEL_LEVEL="${parallel_level:?}"
fi

# Use ccache if available.
if command -V ccache; then
export CMAKE_C_COMPILER_LAUNCHER CMAKE_CXX_COMPILER_LAUNCHER
CMAKE_C_COMPILER_LAUNCHER="ccache"
CMAKE_CXX_COMPILER_LAUNCHER="ccache"
fi

# Install prefix to use for ABI compatibility scripts.
mkdir -p "${working_dir}/install"

# As encouraged by ABI compatibility checkers.
export CFLAGS CXXFLAGS
CFLAGS="-g -Og"
CXXFLAGS="-g -Og"

# Build and install the base commit first.
git -C mongo-cxx-driver stash push -u
git -C mongo-cxx-driver reset --hard "${base:?}"

# Install old (base) to install/old.
echo "Building old libraries..."
[[ -d install/old ]] || {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect install/old is not expected to exist since the teardown task runs rm -rf *.

Consider changing to assert: [[ ! -d install/old ]], or removing the [[ -d install/old ]] since it suggests there is an expectation of reuse.

Same suggestion applies to install/new below.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftovers from when developing and debugging the setup/teardown task definitions. Will remove.

"${cmake_binary:?}" \
-S mongo-cxx-driver \
-B build/old \
-DCMAKE_INSTALL_PREFIX="install/old" \
-DCMAKE_PREFIX_PATH="${working_dir:?}/mongoc" \
-DBUILD_VERSION="${old_ver:?}-base" \
-DCMAKE_CXX_STANDARD="${cxx_standard:?}"
"${cmake_binary:?}" --build build/old
"${cmake_binary:?}" --install build/old
} &>old.log || {
cat old.log 1>&2
exit 1
}
echo "Building old libraries... done."

# Restore all pending changes.
git -C mongo-cxx-driver reset --hard "HEAD@{1}"
git -C mongo-cxx-driver stash pop
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check if a stash entry exists:

if git -C mongo-cxx-driver stash list | grep -q "stash"; then
    # Restore stash if one exists.
    git -C mongo-cxx-driver stash pop
fi

This may resolve the abi-compliance-check task failure on the PR:

[2024/01/18 16:20:10.380] No stash entries found.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed this patch vs. commit/waterfall build discrepancy. Addressed via a direct test for $is_patch (EVG expansion) to detect when stashing is necessary.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like I may have misunderstood the criteria for when a build is considered a patch (includes those triggered by GitHub PRs). Reverted and added a simple || true to the stash pop command to account for the "no stashed changes" scenario.


# Install new (current) to install/new.
echo "Building new libraries..."
[[ -d install/new ]] || {
"${cmake_binary:?}" \
-S mongo-cxx-driver \
-B build/new \
-DCMAKE_INSTALL_PREFIX="install/new" \
-DCMAKE_PREFIX_PATH="${working_dir:?}/mongoc" \
-DBUILD_VERSION="${new_ver:?}-current" \
-DCMAKE_CXX_STANDARD="${cxx_standard:?}"
"${cmake_binary:?}" --build build/new
"${cmake_binary:?}" --install build/new
} &>new.log || {
cat new.log 1>&2
exit 1
}
echo "Building new libraries... done."
24 changes: 24 additions & 0 deletions .evergreen/abidiff-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash

set -o errexit
set -o pipefail

declare working_dir
working_dir="$(pwd)"

export PATH
PATH="${working_dir:?}/install/bin:${PATH:-}"

# Install prefix to use for ABI compatibility scripts.
[[ -d "${working_dir}/install" ]]

if command -V abidiff 2>/dev/null; then
exit # Already available.
fi

# Expected to be run on Ubuntu.
echo "Installing abigail-tools..."
sudo apt-get install -q -y abigail-tools >/dev/null
echo "Installing abigail-tools... done."

command -V abidiff
Loading