mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 07:51:47 +00:00
5739a24808
Three related cleanups to how the bonsaiviewer-autodesk connector is built and shipped. build-bonsaiviewer-autodesk.yml no longer builds a bundle. Its four-runner matrix produced autodesk-<os>-<arch>.zip artifacts that nothing consumed — shipping happens in the platform pipelines, which each invoke packaging/build.py themselves. What is left is the crate's only lint and test coverage, so the workflow is renamed to match what it does and a header comment records where the shipped binary actually comes from. build_osx.yml now builds and bundles the connector, which it never did: macOS users have been getting a Bonsai Viewer with no Autodesk connector at all. ConnectorDiscovery resolves applicationDirPath()/connectors, which inside a bundle is Contents/MacOS, so that is where the folder lands. The tkinter probes in the Windows and Linux workflows are dropped. They guarded the old PyInstaller connector's Tk GUI (de7520418) and have been dead since the Rust rewrite (9d9f4054f); python3.11-tkinter goes with them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
280 lines
12 KiB
YAML
280 lines
12 KiB
YAML
name: Build IfcOpenShell Linux ARM
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
build_ifcopenshell:
|
|
runs-on: ubuntu-22.04-arm
|
|
# Rocky 10 (glibc 2.39) — aqt's official Qt6 ARM binaries are built
|
|
# against glibc 2.38, which Rocky 9 (glibc 2.34) can't run (moc fails to
|
|
# load). The legacy arm64v8/rockylinux Docker image stopped at 9; Rocky 10
|
|
# is published under the rockylinux/rockylinux namespace.
|
|
container:
|
|
image: rockylinux/rockylinux:10
|
|
# The community rockylinux image omits PATH from its config (the old
|
|
# Docker Official arm64v8/rockylinux set it), so GitHub Actions `run:`
|
|
# steps fail with `exec: "sh": not found` — docker exec has no /usr/bin
|
|
# to resolve the shell. Restore a standard PATH; GITHUB_PATH prepends
|
|
# (uv, cargo) are still layered on top by the runner.
|
|
env:
|
|
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
|
|
|
steps:
|
|
- name: Set up uv
|
|
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
|
|
- name: Install Python
|
|
# Installs latest Python version so it's preferred by uv over Rocky's system Python.
|
|
run: uv python install
|
|
|
|
- name: Install Dependencies
|
|
run: |
|
|
dnf update -y
|
|
dnf install -y epel-release
|
|
# --enablerepo=crb: libstdc++-static (libsupc++.a, needed by the
|
|
# bundled FLTK link) lives in Rocky's CodeReady Builder repo, which
|
|
# is disabled by default.
|
|
dnf install -y --enablerepo=crb 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 \
|
|
dbus-devel \
|
|
libXext-devel libXinerama-devel libXcursor-devel libXrender-devel \
|
|
libXfixes-devel libXft-devel pango-devel cairo-devel libstdc++-static
|
|
python3 -m pip install aqtinstall
|
|
git config --global --add safe.directory '*'
|
|
|
|
- name: Install Rust
|
|
# The bonsaiviewer-autodesk connector is a Rust crate; the "Package
|
|
# .zip archives" step below runs `cargo build --release` via
|
|
# packaging/build.py. Match the dedicated connector workflow's stable
|
|
# toolchain (dtolnay/rust-toolchain@stable).
|
|
run: |
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
|
|
- 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@v7
|
|
with:
|
|
submodules: recursive
|
|
|
|
- name: Checkout Build Repository
|
|
uses: actions/checkout@v7
|
|
with:
|
|
repository: IfcOpenShell/build-outputs
|
|
path: ./build
|
|
ref: rockylinux9-arm64
|
|
lfs: true
|
|
token: ${{ secrets.BUILD_REPO_TOKEN }}
|
|
|
|
- name: Unpack Dependencies
|
|
run: |
|
|
cd build
|
|
uv run ../nix/cache_dependencies.py unpack
|
|
|
|
- name: ccache
|
|
uses: hendrikmuhs/ccache-action@v1.2.23
|
|
with:
|
|
key: ubuntu-22.04-${{ runner.arch }}-rockylinux10
|
|
|
|
- name: Run Build Script
|
|
shell: bash
|
|
run: |
|
|
set -o pipefail
|
|
CXXFLAGS="-O3" CFLAGS="-O3" ADD_COMMIT_SHA=1 BUILD_CFG=Release BUILD_BONSAIVIEWER=ON \
|
|
uv run --with aqtinstall ./nix/build-all.py \
|
|
-v --diskcleanup --shared 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
|
|
uv run ../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`
|
|
# bonsaiviewer-autodesk is now a Rust connector. packaging/build.py
|
|
# invokes `cargo build --release` and stages the binary +
|
|
# connector.json into dist/autodesk/. Same on-disk shape as the
|
|
# old PyInstaller flow so the symlink + zip steps below
|
|
# continue to work unchanged.
|
|
python3 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"
|
|
include_geometry_writers="${2:-1}"
|
|
while IFS= read -r runtime_file; do
|
|
if [ "$include_geometry_writers" != "1" ] && [[ "$(basename "$runtime_file")" == ifcopenshell.geometry.writer.* ]]; then
|
|
continue
|
|
fi
|
|
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" 0
|
|
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
|