Files
IfcOpenShell/.github/workflows/build_rocky_arm.yml
T
Dion Moult de7520418b Build the Bonsai Viewer in CI with the Autodesk connector bundled
Compile the Bonsai Viewer as part of the Linux and Windows binary builds,
and ship the Autodesk connector alongside the viewer executable.

Qt6 dependencies:
- The viewer links Qt6::Svg for runtime icon tinting. Svg is a separate
  base-Qt archive, so aqt now installs "qtbase qtsvg" (plus icu on Linux)
  rather than qtbase alone, on both Linux and Windows.
- Qt6::CorePrivate is exposed differently across Qt versions: Qt 6.8 ships
  the target inside Qt6Core, while Qt 6.10 provides it only as a separate
  CorePrivate config package. The viewer CMakeLists requests it via
  OPTIONAL_COMPONENTS so it resolves on both.
- When cross-compiling Windows ARM64, windeployqt runs from the host x64
  Qt, so qtsvg is installed into the host Qt as well.

Windows build:
- build-all-win.py passed -DBUILD_IFCVIEWER, a flag since renamed to
  BUILD_BONSAIVIEWER, so the Windows build compiled no viewer at all. It
  now passes -DBUILD_BONSAIVIEWER.
- The Autodesk connector is bundled under connectors/ next to
  BonsaiViewer.exe in the packaged archive, mirroring the Linux builds.
- The Windows workflow builds the connector (PyInstaller) before the main
  build so it is available to bundle.

Connector bundling:
- The Linux rocky workflows build the connector and bundle it into the
  BonsaiViewer archive; the Windows build now does the same.

Generated with the assistance of an AI coding tool.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 16:34:19 +10:00

237 lines
9.4 KiB
YAML

name: Build IfcOpenShell Linux ARM
on:
workflow_dispatch:
jobs:
build_ifcopenshell:
runs-on: ubuntu-22.04-arm
container: arm64v8/rockylinux:9
steps:
- name: Install Dependencies
run: |
dnf update -y
dnf install -y epel-release
dnf install -y gcc gcc-c++ git autoconf automake bison make zip cmake python3 python3-pip \
bzip2 patch mesa-libGL-devel libffi-devel fontconfig-devel \
sqlite-devel bzip2-devel zlib-devel openssl-devel xz-devel \
readline-devel ncurses-devel libffi-devel libuuid-devel git-lfs \
findutils xz byacc patchelf libxkbcommon-devel \
python3.11 python3.11-pip python3.11-tkinter
python3 -m pip install typing_extensions aqtinstall
git config --global --add safe.directory '*'
python3.11 -c "import tkinter; print('Tk', tkinter.TkVersion)"
- name: Install aws cli
run: |
curl "https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
./aws/install
rm -rf awscliv2.zip aws
aws --version
- name: Checkout Repository
uses: actions/checkout@v6
with:
submodules: recursive
- name: Checkout Build Repository
uses: actions/checkout@v6
with:
repository: IfcOpenShell/build-outputs
path: ./build
ref: rockylinux9-arm64
lfs: true
token: ${{ secrets.BUILD_REPO_TOKEN }}
- name: Unpack Dependencies
run: |
cd build
python3 ../nix/cache_dependencies.py unpack
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2.22
with:
key: ubuntu-22.04-${{ runner.arch }}-rockylinux9
- name: Run Build Script
shell: bash
run: |
set -o pipefail
CXXFLAGS="-O3" CFLAGS="-O3 ${DARWIN_C_SOURCE}" ADD_COMMIT_SHA=1 BUILD_CFG=Release BUILD_BONSAIVIEWER=ON python3 ./nix/build-all.py -v --diskcleanup 2>&1 | tee build.log
- name: Upload Build Logs
if: always()
uses: actions/upload-artifact@v7
with:
name: build-logs-rocky-arm64
path: |
build.log
build/*/*/logs/*.log
retention-days: 30
- name: Pack Dependencies
run: |
cd build
python3 ../nix/cache_dependencies.py pack
- name: Commit and Push Changes to Build Repository
run: |
cd build
git config user.name "IfcOpenBot"
git config user.email "ifcopenbot@ifcopenshell.org"
git add "$(find . -maxdepth 4 -name install)/*.tar.gz"
git commit -m "Update build artifacts [skip ci]" || echo "No changes to commit"
git push || true
- name: Package .zip archives
shell: bash
run: |
VERSION=v`cat VERSION`
python3.11 -m pip install "src/bonsaiviewer-autodesk[build]"
python3.11 src/bonsaiviewer-autodesk/packaging/build.py
autodesk_connector_dir="$PWD/src/bonsaiviewer-autodesk/dist/autodesk"
test -d "$autodesk_connector_dir"
cd ./build/`uname`/*/install/ifcopenshell
mkdir -p ~/output
install_root="$PWD"
QT6_VERSION="${QT6_VERSION:-6.8.3}"
if [ -z "${QT_DIR:-}" ]; then
for qt_candidate in "$(dirname "$install_root")"/qt6-${QT6_VERSION}-*/${QT6_VERSION}/*; do
if [ -d "$qt_candidate/lib" ]; then
QT_DIR="$qt_candidate"
break
fi
done
fi
ensure_soname_links() {
dest="$1"
find "$dest" -maxdepth 1 -type f -name "*.so*" | while IFS= read -r shared_object; do
soname=$(readelf -d "$shared_object" 2>/dev/null | sed -n 's/.*(SONAME).*Shared library: \[\(.*\)\].*/\1/p' | head -n 1)
[ -n "$soname" ] || continue
[ -e "$dest/$soname" ] && continue
ln -s "$(basename "$shared_object")" "$dest/$soname"
done
}
stage_runtime_payload() {
dest="$1"
while IFS= read -r runtime_file; do
cp -P "$runtime_file" "$dest/"
done < <(
for runtime_dir in "$install_root/bin" "$install_root/lib" "$install_root/lib64"; do
[ -d "$runtime_dir" ] || continue
find "$runtime_dir" \( -type f -o -type l \) \( -name "*.so" -o -name "*.so.*" -o -name "*.dylib" -o -name "*.dll" \)
done
)
ensure_soname_links "$dest"
}
stage_qt_runtime_payload() {
exe_path="$1"
dest="$2"
[ -n "${QT_DIR:-}" ] && [ -d "$QT_DIR/lib" ] || return 0
if ! LD_LIBRARY_PATH="$QT_DIR/lib:${LD_LIBRARY_PATH:-}" ldd "$exe_path" 2>/dev/null | grep -q "libQt6"; then
return 0
fi
find "$QT_DIR/lib" -maxdepth 1 \( -type f -o -type l \) -name "*.so*" -exec cp -P {} "$dest/" \;
ensure_soname_links "$dest"
if [ -d "$QT_DIR/plugins" ]; then
pushd "$QT_DIR/plugins" > /dev/null
find . \( -type f -o -type l \) -name "*.so*" | while IFS= read -r plugin_file; do
mkdir -p "$dest/plugins/$(dirname "$plugin_file")"
cp -P "$plugin_file" "$dest/plugins/$plugin_file"
done
popd > /dev/null
if [ -d "$dest/plugins" ]; then
find "$dest/plugins" -type f -name "*.so*" -exec patchelf --set-rpath '$ORIGIN/../..:$ORIGIN' {} \;
fi
fi
find "$dest" -maxdepth 1 -type f -name "*.so*" -exec patchelf --set-rpath '$ORIGIN' {} \;
printf "[Paths]\nPrefix = .\n" > "$dest/qt.conf"
}
check_runtime_dependencies() {
package_dir="$1"
missing=0
while IFS= read -r binary_file; do
readelf -h "$binary_file" >/dev/null 2>&1 || continue
if ! env -u LD_LIBRARY_PATH ldd "$binary_file" > "$package_dir/.ldd.out" 2>&1; then
echo "ldd failed for $binary_file"
cat "$package_dir/.ldd.out"
missing=1
continue
fi
if grep -q "not found" "$package_dir/.ldd.out"; then
echo "Missing runtime dependencies for $binary_file"
grep "not found" "$package_dir/.ldd.out"
missing=1
fi
done < <(find "$package_dir" -type f \( -perm /111 -o -name "*.so" -o -name "*.so.*" \))
rm -f "$package_dir/.ldd.out"
if [ "$missing" -ne 0 ]; then
echo "Runtime dependency check found issues; continuing packaging."
fi
return 0
}
ls -d python-* | while read py_version; do
postfix=`echo ${py_version: -1} | sed s/[0-9]//`
numbers=`echo $py_version | grep -oE '[0-9]+\.[0-9]+' | tr -d '.'`
py_version_major=python-${numbers}$postfix
pushd . > /dev/null
cd $py_version
if [ ! -d ifcopenshell ]; then
mkdir ../ifcopenshell_
mv * ../ifcopenshell_
mv ../ifcopenshell_ ifcopenshell
fi
[ -d ifcopenshell/__pycache__ ] && rm -rf ifcopenshell/__pycache__
find ifcopenshell -name "*.pyc" -delete
stage_runtime_payload ifcopenshell
zip -y -r -qq ifcopenshell-${py_version_major}-${VERSION}-${GITHUB_SHA:0:7}-linuxarm64.zip ifcopenshell
mv *.zip ~/output
popd > /dev/null
done
rm -f "$install_root"/bin/*.zip
find "$install_root/bin" -maxdepth 1 -type f -perm /111 ! -name "*.zip" ! -name "*.so" ! -name "*.so.*" ! -name "*.dylib" ! -name "*.dll" | while read exe_path; do
exe=`basename "$exe_path"`
package_dir="$install_root/.package-${exe}"
rm -rf "$package_dir"
mkdir -p "$package_dir"
cp "$exe_path" "$package_dir/"
patchelf --set-rpath '$ORIGIN' "$package_dir/$exe"
stage_runtime_payload "$package_dir"
stage_qt_runtime_payload "$exe_path" "$package_dir"
if [ "$exe" = "BonsaiViewer" ]; then
mkdir -p "$package_dir/connectors"
cp -a "$autodesk_connector_dir" "$package_dir/connectors/"
fi
check_runtime_dependencies "$package_dir"
pushd "$package_dir" > /dev/null
zip -y -qq -r "$HOME/output/${exe}-${VERSION}-${GITHUB_SHA:0:7}-linuxarm64.zip" .
popd > /dev/null
rm -rf "$package_dir"
done
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v6
with:
aws-access-key-id: ${{ secrets.AWS_UPLOAD_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_UPLOAD_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Upload .zip archives to S3
run: |
aws s3 cp ~/output s3://ifcopenshell-builds/ --recursive