Files
IfcOpenShell/.github/workflows/build_rocky.yml
T
Dion Moult a91b1da28b Reduce Rocky package size
Build Rocky artifacts with shared IfcOpenShell libraries and keep geometry writer plugins out of executable packages while preserving them for Python packages.

Generated with the assistance of an AI coding tool.
2026-05-25 16:34:19 +10:00

241 lines
9.6 KiB
YAML

name: Build IfcOpenShell Linux
on:
workflow_dispatch:
jobs:
build_ifcopenshell:
runs-on: ubuntu-22.04
container: 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-x86_64.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-x64
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 --shared 2>&1 | tee build.log
- name: Upload Build Logs
if: always()
uses: actions/upload-artifact@v7
with:
name: build-logs-rocky
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"
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}-linux64.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}-linux64.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