mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-23 21:38:35 +00:00
Compare commits
344 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dd902bf0f8 | |||
| 371aabfef6 | |||
| 1c22fa0669 | |||
| a91b1da28b | |||
| 89cb551dbb | |||
| 102ac551b3 | |||
| 137a890256 | |||
| de7520418b | |||
| e8a93846dd | |||
| 96941463c0 | |||
| 19bff92a47 | |||
| 66f3593de1 | |||
| bb17cfbc40 | |||
| 4913b84af7 | |||
| 8734b419e5 | |||
| 49f6f64e5c | |||
| dc82171013 | |||
| 084c87ea06 | |||
| 59e5b2b1b8 | |||
| fcae3d90af | |||
| 486b858d56 | |||
| 95c62cc70e | |||
| 6ca38f8bf6 | |||
| e0a504417c | |||
| 8b8fafa698 | |||
| 5f467cd8fa | |||
| 8242efac97 | |||
| 22f25f0098 | |||
| fed739847e | |||
| 56273de443 | |||
| 6901533368 | |||
| 4a91e6a87d | |||
| 03b8b9c1bd | |||
| 8f937052b8 | |||
| b1bad23a64 | |||
| d18c05d4bd | |||
| cee2dbcc85 | |||
| a755e96c13 | |||
| 9c1a10190d | |||
| a4f7db45cd | |||
| 6df9aeda2c | |||
| 1c598a981e | |||
| 742561c56d | |||
| 05a15e84a6 | |||
| a900f2c437 | |||
| 0a297babea | |||
| bba2f30816 | |||
| d0c8c84e7b | |||
| 7f153375b2 | |||
| d25c2583da | |||
| 027e2406be | |||
| e864a961ee | |||
| d8f37b2376 | |||
| acfcf6e14e | |||
| 5bc7e4b98b | |||
| c8d39cc481 | |||
| 1cf9373000 | |||
| d8c9d1a47b | |||
| 0993c1b0f1 | |||
| 22384e136f | |||
| 6dea7a5110 | |||
| 424e70ac86 | |||
| fceb8911f6 | |||
| 94f4dbcf31 | |||
| 391f8363bb | |||
| 210861eda1 | |||
| a2012ace2e | |||
| 05e328339f | |||
| cd612dc988 | |||
| 44ba6e8963 | |||
| c3a10694ba | |||
| da5ebf172e | |||
| c1173dfc78 | |||
| fde502daa1 | |||
| 2eb2d65710 | |||
| 0d8e9f0edc | |||
| 3c773d71d3 | |||
| 43f5a79f99 | |||
| 12935c83de | |||
| e7249fe934 | |||
| cf257aa20a | |||
| 7d0b6f6fd8 | |||
| 554c7174e3 | |||
| bd436765bf | |||
| 5270318570 | |||
| 8fcaa18171 | |||
| 8d0a6ecc16 | |||
| bfea57c617 | |||
| 18b79a4360 | |||
| 05cd19592d | |||
| a1efdccb4b | |||
| 6ad5fbb27e | |||
| 884e7ba326 | |||
| 82f188fbe6 | |||
| 31ddc0ecdb | |||
| 02198e3f56 | |||
| b1899b1a8d | |||
| 39d583a26a | |||
| 609b6959bc | |||
| 2c7d25cffc | |||
| e893552f24 | |||
| bae1eddda9 | |||
| ad62dd6d91 | |||
| d565dc3ff3 | |||
| a340e6cf9a | |||
| 359693c562 | |||
| 016c278748 | |||
| f2b655fcf6 | |||
| 0bb6df6a6b | |||
| 2257d7930a | |||
| 98ff457fd6 | |||
| f07afda09c | |||
| 4670715ef3 | |||
| 5b2721c1c4 | |||
| 0d5fa0c20c | |||
| 802ddf8ff9 | |||
| ea4747ccb1 | |||
| e20cea221b | |||
| ae66550cae | |||
| 5ccb655e10 | |||
| 278c1e5068 | |||
| 095e4a1677 | |||
| de5eb9641f | |||
| 4597be7fda | |||
| ca2e866c45 | |||
| e84767c22b | |||
| f7add7f412 | |||
| 8ffdb8f0b9 | |||
| e0e143bab5 | |||
| 8f3eaa35d7 | |||
| 81b1efdfd6 | |||
| 4a9af13626 | |||
| e9d577890e | |||
| 7f29850022 | |||
| 92c3b4c308 | |||
| 600d3a3460 | |||
| bea4e38e65 | |||
| 5386c9ec69 | |||
| ecf0a5a4e1 | |||
| 540f3acf52 | |||
| b3d29c4081 | |||
| 0d3849737c | |||
| a2db0a68a4 | |||
| 3e2869b6aa | |||
| db1a2705a3 | |||
| e7787b6aad | |||
| 6f0327d4b5 | |||
| 6341d7dd31 | |||
| 51971dd493 | |||
| 309e20009c | |||
| a06e5ecdf5 | |||
| 1ca2e12f92 | |||
| b9e5739088 | |||
| 30cdffc27a | |||
| 3607fbb762 | |||
| b73cdd1a0e | |||
| e21bd1ac96 | |||
| 633c613da2 | |||
| 8282f691e8 | |||
| 7bc64bef1a | |||
| 81a7c5b50e | |||
| 3b3ed47e89 | |||
| f54c917ded | |||
| 5c6444d5ea | |||
| 6282634a70 | |||
| 40267aa068 | |||
| 1efedfd3cc | |||
| ddfe3bce20 | |||
| 8f7c8dc1d2 | |||
| eea2398e07 | |||
| 35be7f4190 | |||
| 4f929e90a7 | |||
| f898089b27 | |||
| 4e4553201b | |||
| 29f5132510 | |||
| ae938d425b | |||
| 5161b0a3f8 | |||
| 3015f758ba | |||
| dbe68b48f2 | |||
| 094d96c735 | |||
| ed6e8d831e | |||
| 930678e3d2 | |||
| 4e3cc63de1 | |||
| 7b64dd338b | |||
| 71612e0780 | |||
| 9aae8f0329 | |||
| 175efcfffe | |||
| 643a2e1c1f | |||
| 3c5c8e44cb | |||
| fc89ffeb19 | |||
| 4bedb40d8a | |||
| a34c36d22e | |||
| e5ed7b53d4 | |||
| 069ef20c46 | |||
| 0b122ae1f5 | |||
| a0cc4b874b | |||
| 2f88778c9f | |||
| 0a752e09eb | |||
| 03662d2016 | |||
| 99f409280a | |||
| 0c9d3ea6d7 | |||
| 37fa4e9076 | |||
| 1ec273f508 | |||
| 574bcfa6c5 | |||
| 09ffdd2028 | |||
| d0c5bd5e85 | |||
| c03a7fe117 | |||
| 8596d53a4a | |||
| c78e16eafb | |||
| 68fea7bd45 | |||
| 90366f8236 | |||
| d3c21d7a81 | |||
| cd77c557e9 | |||
| 3110c98429 | |||
| 0e2a62d3b7 | |||
| f532624dc1 | |||
| f0e3056d0a | |||
| 298eca0ab6 | |||
| 1f17d73f3e | |||
| ababb49ae7 | |||
| 07a5c59359 | |||
| 8c8ef5c32b | |||
| 36fa53122a | |||
| 1dace18d26 | |||
| 5b4c1089cf | |||
| 83a3131276 | |||
| 6f6bebf387 | |||
| bfac12dbe7 | |||
| d33055bb72 | |||
| d08a4e0706 | |||
| 06eca938d7 | |||
| 543d9f8588 | |||
| b40e4378b3 | |||
| 1089de14f0 | |||
| 1b35533917 | |||
| c42a7f32d0 | |||
| 14e9846e35 | |||
| 37c6aea092 | |||
| 9b13dc8dd6 | |||
| 89c66f62bf | |||
| 18363c0d19 | |||
| 782aa4f88f | |||
| 13c71d7a8a | |||
| cb7e7331e6 | |||
| 4850e2a07c | |||
| fd980abcc2 | |||
| b022ca7e70 | |||
| 325db2e57f | |||
| 046ceb452a | |||
| 9e19735275 | |||
| 6ee05b646b | |||
| e62921171c | |||
| 6c47123781 | |||
| d448fa95e3 | |||
| 57de09d236 | |||
| a25f522cc3 | |||
| e067c2b834 | |||
| e2905d6f0e | |||
| ead061a98a | |||
| fae85e63cc | |||
| bccea6d932 | |||
| 1cc93784cd | |||
| f1e93581ec | |||
| 91ae631c7d | |||
| b599ee1040 | |||
| d2cc66fdf0 | |||
| 3824e7b449 | |||
| aa10784154 | |||
| 2018bcb3c1 | |||
| 11006f0ef5 | |||
| a44f72287b | |||
| c6849073d9 | |||
| b2fc0c00cc | |||
| 2d5883f966 | |||
| 4621fc9269 | |||
| 1840e3d1a8 | |||
| becd38c77d | |||
| 7d6c6bd523 | |||
| a425bb6da0 | |||
| a19d398c78 | |||
| f616c4049c | |||
| 20ccf2b455 | |||
| a07f56db6f | |||
| 724cdb446e | |||
| 95b3f7dac4 | |||
| 603cedc487 | |||
| fe6e9d86ae | |||
| 8e42f35db3 | |||
| 9d69a712ac | |||
| dc127471c5 | |||
| 95a094d596 | |||
| 4ec643d4e1 | |||
| c089c11cd6 | |||
| 8afba9a665 | |||
| 5c4046e054 | |||
| d82e1da907 | |||
| 8c2e1226c9 | |||
| ed8821486d | |||
| 742bfac144 | |||
| 1f4c4204d0 | |||
| 43f78605f2 | |||
| 6cd1375cf9 | |||
| 2d1250c18f | |||
| bee61cba11 | |||
| 33f072e0a7 | |||
| 490fa92dc0 | |||
| cf3393b6a0 | |||
| fbbc92c5d7 | |||
| 574827016a | |||
| 18c9140700 | |||
| 9e165319e6 | |||
| 64bf807baa | |||
| 136befde86 | |||
| 1a4d750ecd | |||
| 0a5dd78774 | |||
| 94427ebcb3 | |||
| 9147938c36 | |||
| ffcc02fb99 | |||
| e4e4f31d20 | |||
| 2dd002bcd8 | |||
| 7e5248da29 | |||
| 07a01bcf54 | |||
| 0a9e29ce45 | |||
| 0604db06e9 | |||
| 991556fbe3 | |||
| b66b04b001 | |||
| 5c9213426f | |||
| 69a4ad35a1 | |||
| 7f4d9e31c3 | |||
| ae79996eb6 | |||
| f5b2358c2e | |||
| f9c791de1b | |||
| 5b85a2c38b | |||
| bc46a8f85b | |||
| c57209fbce | |||
| 088a6b7204 | |||
| f2f4d626a5 | |||
| 572a5655cf | |||
| ccd91c0ff0 | |||
| a1d2c902f3 | |||
| 3ae361bb3b | |||
| 2d7521ed88 | |||
| 7098beb819 | |||
| f09ca658f1 |
@@ -1,95 +0,0 @@
|
||||
#!/usr/bin/env -S uv run
|
||||
# /// script
|
||||
# dependencies = [
|
||||
# "PyGithub",
|
||||
# "requests",
|
||||
# ]
|
||||
# ///
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
from github import Github
|
||||
from github.GitReleaseAsset import GitReleaseAsset
|
||||
|
||||
EXTENSION_ID = "bonsai"
|
||||
CURRENT_PYTHON_VERSION = "py313"
|
||||
CURRENT_PLATFORMS = ["linux-x64", "macos-arm64", "windows-x64"]
|
||||
|
||||
|
||||
def publish_asset(asset: GitReleaseAsset, token: str, repo_root: Path) -> None:
|
||||
"""
|
||||
Publish an asset to Blender Extensions.
|
||||
Reference: https://extensions.blender.org/api/v1/swagger
|
||||
"""
|
||||
temp_path = repo_root / asset.name
|
||||
|
||||
response = requests.get(asset.browser_download_url)
|
||||
response.raise_for_status()
|
||||
temp_path.write_bytes(response.content)
|
||||
|
||||
url = f"https://extensions.blender.org/api/v1/extensions/{EXTENSION_ID}/versions/upload/"
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
|
||||
files = {"version_file": temp_path.read_bytes()}
|
||||
response = requests.post(url, headers=headers, files=files)
|
||||
response.raise_for_status()
|
||||
|
||||
temp_path.unlink()
|
||||
|
||||
print(f"✓ Published {asset.name}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
token = os.getenv("BLENDER_EXTENSIONS_TOKEN")
|
||||
if not token:
|
||||
raise Exception("BLENDER_EXTENSIONS_TOKEN environment variable not set")
|
||||
|
||||
# Get the repository root
|
||||
repo_root = Path(__file__).parent.parent.parent
|
||||
|
||||
# Read VERSION file
|
||||
version_file = repo_root / "VERSION"
|
||||
version = version_file.read_text().strip()
|
||||
|
||||
print(f"Current VERSION: {version}")
|
||||
|
||||
tag_name = f"bonsai-{version}"
|
||||
|
||||
# Get release from GitHub
|
||||
gh = Github()
|
||||
gh_repo = gh.get_repo("IfcOpenShell/IfcOpenShell")
|
||||
release = gh_repo.get_release(tag_name)
|
||||
|
||||
assets = release.get_assets()
|
||||
|
||||
asset_platform_map: dict[str, tuple[GitReleaseAsset, str]] = {}
|
||||
for asset in assets:
|
||||
if CURRENT_PYTHON_VERSION not in asset.name:
|
||||
continue
|
||||
for platform in CURRENT_PLATFORMS:
|
||||
if platform in asset.name:
|
||||
asset_platform_map[asset.name] = (asset, platform)
|
||||
break
|
||||
|
||||
if len(asset_platform_map) != len(CURRENT_PLATFORMS):
|
||||
found_platforms = {platform for _, (_, platform) in asset_platform_map.items()}
|
||||
missing_platforms = set(CURRENT_PLATFORMS) - found_platforms
|
||||
raise Exception(
|
||||
f"Expected {len(CURRENT_PLATFORMS)} assets but found {len(asset_platform_map)}. "
|
||||
f"Missing: {', '.join(sorted(missing_platforms))}"
|
||||
)
|
||||
|
||||
print("\nRelease assets:")
|
||||
for asset_name in sorted(asset_platform_map.keys()):
|
||||
print(f"- {asset_name}")
|
||||
|
||||
# https://extensions.blender.org/api/v1/swagger
|
||||
print("\nPublishing assets to Blender Extensions:")
|
||||
for asset_name, (asset, platform) in asset_platform_map.items():
|
||||
publish_asset(asset, token, repo_root)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,101 @@
|
||||
name: Build Bonsai Viewer Autodesk Connector
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- 'src/bonsaiviewer-autodesk/**'
|
||||
- '.github/workflows/build-bonsaiviewer-autodesk.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'src/bonsaiviewer-autodesk/**'
|
||||
- '.github/workflows/build-bonsaiviewer-autodesk.yml'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: test-py${{ matrix.python-version }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Exercise the floor and a current version of the supported range
|
||||
# (pyproject requires-python = ">=3.11").
|
||||
python-version: ['3.11', '3.13']
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: src/bonsaiviewer-autodesk
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
# The connector imports tkinter/customtkinter (via the test suite's
|
||||
# connector coverage), so fail loudly here if Tk is missing.
|
||||
- name: Verify tkinter is available
|
||||
run: python -c "import tkinter; print('Tk', tkinter.TkVersion)"
|
||||
|
||||
- name: Install package and test deps
|
||||
run: python -m pip install ".[test]"
|
||||
|
||||
- name: Run pytest
|
||||
run: python -m pytest -q
|
||||
|
||||
build:
|
||||
name: ${{ matrix.os_label }}-${{ matrix.arch }}
|
||||
needs: test
|
||||
runs-on: ${{ matrix.runner }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Linux: build on the oldest reasonable glibc (Ubuntu 22.04 / glibc
|
||||
# 2.35) so the bundle runs on older distributions.
|
||||
- os_label: linux
|
||||
arch: x86_64
|
||||
runner: ubuntu-22.04
|
||||
# macOS Apple Silicon.
|
||||
- os_label: macos
|
||||
arch: arm64
|
||||
runner: macos-14
|
||||
# macOS Intel. macos-13 is the last Intel runner GitHub provides.
|
||||
- os_label: macos
|
||||
arch: x86_64
|
||||
runner: macos-13
|
||||
# Windows x86_64.
|
||||
- os_label: windows
|
||||
arch: x86_64
|
||||
runner: windows-latest
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: src/bonsaiviewer-autodesk
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
# actions/setup-python ships Python with tkinter on all three OSes via
|
||||
# python-build-standalone, but verify so a missing-tk regression fails
|
||||
# the build loudly instead of inside PyInstaller.
|
||||
- name: Verify tkinter is available
|
||||
run: python -c "import tkinter; print('Tk', tkinter.TkVersion)"
|
||||
|
||||
- name: Install package and build deps
|
||||
run: python -m pip install ".[build]"
|
||||
|
||||
- name: Build connector bundle
|
||||
run: python packaging/build.py
|
||||
|
||||
- name: Upload connector zip
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: autodesk-${{ matrix.os_label }}-${{ matrix.arch }}
|
||||
path: src/bonsaiviewer-autodesk/dist/autodesk-${{ matrix.os_label }}-${{ matrix.arch }}.zip
|
||||
if-no-files-found: error
|
||||
@@ -21,12 +21,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Checkout Build Repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: IfcOpenShell/build-outputs
|
||||
path: ./build
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
python ../nix/cache_dependencies.py unpack
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.23
|
||||
uses: hendrikmuhs/ccache-action@v1.2.22
|
||||
with:
|
||||
key: mac-${{ matrix.arch }}
|
||||
|
||||
@@ -110,7 +110,20 @@ jobs:
|
||||
run: |
|
||||
VERSION=v`cat VERSION`
|
||||
cd ./build/`uname`/*/10.15/install/ifcopenshell
|
||||
mkdir ~/output
|
||||
mkdir -p ~/output
|
||||
install_root="$PWD"
|
||||
|
||||
stage_runtime_payload() {
|
||||
dest="$1"
|
||||
while IFS= read -r runtime_file; do
|
||||
cp -L "$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 \( -name "*.so" -o -name "*.so.*" -o -name "*.dylib" -o -name "*.dll" \)
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
ls -d python-* | while read py_version; do
|
||||
postfix=`echo ${py_version: -1} | sed s/[0-9]//`
|
||||
@@ -125,18 +138,25 @@ jobs:
|
||||
fi
|
||||
[ -d ifcopenshell/__pycache__ ] && rm -rf ifcopenshell/__pycache__
|
||||
find ifcopenshell -name "*.pyc" -delete
|
||||
zip -r -qq ifcopenshell-${py_version_major}-${VERSION}-${GITHUB_SHA:0:7}-macos${{ matrix.oldarch }}64.zip ifcopenshell/*
|
||||
stage_runtime_payload ifcopenshell
|
||||
zip -r -qq ifcopenshell-${py_version_major}-${VERSION}-${GITHUB_SHA:0:7}-macos${{ matrix.oldarch }}64.zip ifcopenshell
|
||||
mv *.zip ~/output
|
||||
popd > /dev/null
|
||||
done
|
||||
|
||||
cd bin
|
||||
rm *.zip || true
|
||||
ls | while read exe; do
|
||||
zip -qq -r ${exe}-${VERSION}-${GITHUB_SHA:0:7}-macos${{ matrix.oldarch }}64.zip $exe
|
||||
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/"
|
||||
stage_runtime_payload "$package_dir"
|
||||
pushd "$package_dir" > /dev/null
|
||||
zip -qq -r "$HOME/output/${exe}-${VERSION}-${GITHUB_SHA:0:7}-macos${{ matrix.oldarch }}64.zip" .
|
||||
popd > /dev/null
|
||||
rm -rf "$package_dir"
|
||||
done
|
||||
mv *.zip ~/output
|
||||
cd ..
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v6
|
||||
|
||||
@@ -9,13 +9,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
path: IfcOpenShell
|
||||
|
||||
- name: Checkout Build Repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: IfcOpenShell/build-outputs
|
||||
path: ifcopenshell_build
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
python ../IfcOpenShell/nix/cache_dependencies.py unpack
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.23
|
||||
uses: hendrikmuhs/ccache-action@v1.2.22
|
||||
with:
|
||||
key: ubuntu-22.04-${{ runner.arch }}
|
||||
|
||||
@@ -40,6 +40,18 @@ jobs:
|
||||
NEW_FILE=`echo $FILE | sed "s/-/+${GITHUB_SHA:0:7}-/2"`
|
||||
mv $FILE $NEW_FILE
|
||||
|
||||
- name: Order wheel shared objects
|
||||
run: |
|
||||
python ./IfcOpenShell/pyodide/order_pyodide_wheel_shared_objects.py dist/ifcopenshell-*.whl
|
||||
|
||||
- name: Split packages
|
||||
run: |
|
||||
VERSION=v`cat ./IfcOpenShell/VERSION`
|
||||
mkdir -p dist-modular
|
||||
python ./IfcOpenShell/pyodide/split_pyodide_ifcopenshell_wheel.py dist/ifcopenshell-*.whl ./dist-modular
|
||||
cd dist-modular
|
||||
zip -r -qq ifcopenshell-modular-${VERSION}-${GITHUB_SHA:0:7}-pyodide.zip *.whl
|
||||
|
||||
- name: Upload Build Logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
@@ -86,3 +98,4 @@ jobs:
|
||||
- name: Upload .zip archives to S3
|
||||
run: |
|
||||
aws s3 cp dist s3://ifcopenshell-builds/ --recursive --exclude "*" --include "*.whl"
|
||||
aws s3 cp dist-modular s3://ifcopenshell-builds/ --recursive --exclude "*" --include "*.zip"
|
||||
|
||||
@@ -9,22 +9,19 @@ jobs:
|
||||
container: rockylinux:9
|
||||
|
||||
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
|
||||
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
|
||||
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: |
|
||||
@@ -35,12 +32,12 @@ jobs:
|
||||
aws --version
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Checkout Build Repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: IfcOpenShell/build-outputs
|
||||
path: ./build
|
||||
@@ -51,10 +48,10 @@ jobs:
|
||||
- name: Unpack Dependencies
|
||||
run: |
|
||||
cd build
|
||||
uv run ../nix/cache_dependencies.py unpack
|
||||
python3 ../nix/cache_dependencies.py unpack
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.23
|
||||
uses: hendrikmuhs/ccache-action@v1.2.22
|
||||
with:
|
||||
key: ubuntu-22.04-${{ runner.arch }}-rockylinux9
|
||||
|
||||
@@ -62,7 +59,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
set -o pipefail
|
||||
CXXFLAGS="-O3" CFLAGS="-O3 ${DARWIN_C_SOURCE}" ADD_COMMIT_SHA=1 BUILD_CFG=Release uv run ./nix/build-all.py -v --diskcleanup 2>&1 | tee build.log
|
||||
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()
|
||||
@@ -77,7 +74,7 @@ jobs:
|
||||
- name: Pack Dependencies
|
||||
run: |
|
||||
cd build
|
||||
uv run ../nix/cache_dependencies.py pack
|
||||
python3 ../nix/cache_dependencies.py pack
|
||||
|
||||
- name: Commit and Push Changes to Build Repository
|
||||
run: |
|
||||
@@ -89,10 +86,107 @@ jobs:
|
||||
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 ~/output
|
||||
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]//`
|
||||
@@ -107,18 +201,32 @@ jobs:
|
||||
fi
|
||||
[ -d ifcopenshell/__pycache__ ] && rm -rf ifcopenshell/__pycache__
|
||||
find ifcopenshell -name "*.pyc" -delete
|
||||
zip -r -qq ifcopenshell-${py_version_major}-${VERSION}-${GITHUB_SHA:0:7}-linux64.zip ifcopenshell/*
|
||||
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
|
||||
|
||||
cd bin
|
||||
rm *.zip || true
|
||||
ls | while read exe; do
|
||||
zip -qq -r ${exe}-${VERSION}-${GITHUB_SHA:0:7}-linux64.zip $exe
|
||||
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
|
||||
mv *.zip ~/output
|
||||
cd ..
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v6
|
||||
|
||||
@@ -9,22 +9,19 @@ jobs:
|
||||
container: arm64v8/rockylinux:9
|
||||
|
||||
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
|
||||
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
|
||||
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: |
|
||||
@@ -35,12 +32,12 @@ jobs:
|
||||
aws --version
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Checkout Build Repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: IfcOpenShell/build-outputs
|
||||
path: ./build
|
||||
@@ -51,10 +48,10 @@ jobs:
|
||||
- name: Unpack Dependencies
|
||||
run: |
|
||||
cd build
|
||||
uv run ../nix/cache_dependencies.py unpack
|
||||
python3 ../nix/cache_dependencies.py unpack
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.23
|
||||
uses: hendrikmuhs/ccache-action@v1.2.22
|
||||
with:
|
||||
key: ubuntu-22.04-${{ runner.arch }}-rockylinux9
|
||||
|
||||
@@ -62,7 +59,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
set -o pipefail
|
||||
CXXFLAGS="-O3" CFLAGS="-O3 ${DARWIN_C_SOURCE}" ADD_COMMIT_SHA=1 BUILD_CFG=Release uv run ./nix/build-all.py -v --diskcleanup 2>&1 | tee build.log
|
||||
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()
|
||||
@@ -77,7 +74,7 @@ jobs:
|
||||
- name: Pack Dependencies
|
||||
run: |
|
||||
cd build
|
||||
uv run ../nix/cache_dependencies.py pack
|
||||
python3 ../nix/cache_dependencies.py pack
|
||||
|
||||
- name: Commit and Push Changes to Build Repository
|
||||
run: |
|
||||
@@ -89,10 +86,107 @@ jobs:
|
||||
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 ~/output
|
||||
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]//`
|
||||
@@ -107,18 +201,32 @@ jobs:
|
||||
fi
|
||||
[ -d ifcopenshell/__pycache__ ] && rm -rf ifcopenshell/__pycache__
|
||||
find ifcopenshell -name "*.pyc" -delete
|
||||
zip -r -qq ifcopenshell-${py_version_major}-${VERSION}-${GITHUB_SHA:0:7}-linuxarm64.zip ifcopenshell/*
|
||||
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
|
||||
|
||||
cd bin
|
||||
rm *.zip || true
|
||||
ls | while read exe; do
|
||||
zip -qq -r ${exe}-${VERSION}-${GITHUB_SHA:0:7}-linuxarm64.zip $exe
|
||||
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
|
||||
mv *.zip ~/output
|
||||
cd ..
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v6
|
||||
|
||||
@@ -27,12 +27,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Checkout Build Repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: IfcOpenShell/build-outputs
|
||||
path: ${{ matrix.deps_dir }}
|
||||
@@ -48,17 +48,39 @@ jobs:
|
||||
run: |
|
||||
cd ${{ matrix.deps_dir }}
|
||||
Get-ChildItem -Path . -Filter 'cache-*.zip' | ForEach-Object {
|
||||
7z x $_.FullName
|
||||
Write-Host "Extracting $($_.Name)"
|
||||
7z x -bso0 -bsp0 $_.FullName
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to extract $($_.Name) with 7z exit code $LASTEXITCODE."
|
||||
}
|
||||
}
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.23
|
||||
uses: hendrikmuhs/ccache-action@v1.2.22
|
||||
with:
|
||||
key: win-${{ matrix.arch }}
|
||||
# Windows ccache needs ~1GB
|
||||
# and with default 500MB some cache gets deleted, leading to misses.
|
||||
max-size: 5000MB
|
||||
|
||||
- name: Set up Python for connector build
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
# The connector's PyInstaller bundle embeds a tkinter GUI; verify Tk is
|
||||
# present so a missing-tk regression fails here, not inside the build.
|
||||
- name: Verify tkinter is available
|
||||
run: python -c "import tkinter; print('Tk', tkinter.TkVersion)"
|
||||
|
||||
# Build the Autodesk connector before the C++ build: build-all-win.py
|
||||
# bundles it next to BonsaiViewer.exe while archiving the executables.
|
||||
- name: Build Autodesk connector
|
||||
working-directory: src/bonsaiviewer-autodesk
|
||||
run: |
|
||||
python -m pip install ".[build]"
|
||||
python packaging/build.py
|
||||
|
||||
- name: Run Build Script And Pack .zip Archives
|
||||
shell: cmd
|
||||
env:
|
||||
|
||||
@@ -19,8 +19,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7 # https://github.com/actions/checkout
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6 # https://github.com/actions/checkout
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-tags: true
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -65,8 +65,8 @@ jobs:
|
||||
config:
|
||||
short_name: macos
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
python-version: '3.11'
|
||||
@@ -98,7 +98,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout bonsai_unstable_repo repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: IfcOpenShell/bonsai_unstable_repo
|
||||
token: ${{ secrets.IFCOPENBOT_TOKEN }}
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
# Ensure Bonsai and ifcsverchok enable/disable works before uploading to extensions repo.
|
||||
|
||||
# Download Blender.
|
||||
wget -q -O blender.tar.xz https://download.blender.org/release/Blender5.2/blender-5.2.0-linux-x64.tar.xz
|
||||
wget -q -O blender.tar.xz https://download.blender.org/release/Blender5.1/blender-5.1.0-linux-x64.tar.xz
|
||||
tar -xf blender.tar.xz
|
||||
|
||||
# Setup Blender.
|
||||
@@ -179,7 +179,8 @@ jobs:
|
||||
blender --online-mode --command extension install --enable --sync sun_position
|
||||
|
||||
cd IfcOpenShell/src/bonsai
|
||||
pip install -r requirements-dev.txt
|
||||
pip install pytest-blender
|
||||
pip install pytest-bdd
|
||||
blender --background --python scripts/setup_pytest.py
|
||||
blender --python-expr "import bonsai; print(bonsai.bbim_semver); import ifcopenshell; print(ifcopenshell.version)" --background
|
||||
make test
|
||||
|
||||
@@ -48,8 +48,8 @@ jobs:
|
||||
config:
|
||||
short_name: macos
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
python-version: '3.11'
|
||||
|
||||
@@ -18,8 +18,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
- name: Compile
|
||||
|
||||
@@ -18,8 +18,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
- name: Compile
|
||||
|
||||
@@ -18,8 +18,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
- name: Compile
|
||||
|
||||
@@ -18,8 +18,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
- name: Compile
|
||||
|
||||
@@ -18,8 +18,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
- name: Compile
|
||||
|
||||
@@ -37,8 +37,8 @@ jobs:
|
||||
short_name: macosm164
|
||||
}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
|
||||
@@ -18,8 +18,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
- name: Compile
|
||||
|
||||
@@ -18,8 +18,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
- name: Compile
|
||||
|
||||
@@ -18,8 +18,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Compile
|
||||
|
||||
@@ -18,8 +18,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
- name: Compile
|
||||
|
||||
@@ -18,8 +18,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Compile
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
date: ${{ steps.date.outputs.date }}
|
||||
verdate: ${{ steps.verdate.outputs.verdate }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set env
|
||||
run: echo ok go
|
||||
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
echo "ARTIFACTS_DIR=/home/runner/work/artifacts" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: activate
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -31,11 +31,11 @@ jobs:
|
||||
sudo apt-get install --no-install-recommends \
|
||||
git cmake gcc g++ libboost-all-dev python3-all-dev swig libpcre3-dev libxml2-dev \
|
||||
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
|
||||
libhdf5-dev libcgal-dev nlohmann-json3-dev libeigen3-dev
|
||||
libcgal-dev nlohmann-json3-dev libeigen3-dev
|
||||
|
||||
-
|
||||
name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.23
|
||||
uses: hendrikmuhs/ccache-action@v1.2.22
|
||||
|
||||
-
|
||||
name: Build ifcopenshell
|
||||
@@ -60,7 +60,6 @@ jobs:
|
||||
-DMPFR_INCLUDE_DIR=/usr/include \
|
||||
-DGMP_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DMPFR_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DHDF5_INCLUDE_DIR=/usr/include/hdf5/serial \
|
||||
-DGLTF_SUPPORT=On \
|
||||
-DJSON_INCLUDE_DIR=/usr/include \
|
||||
-DEIGEN_DIR=/usr/include/eigen3 \
|
||||
@@ -86,7 +85,7 @@ jobs:
|
||||
name: Docker Build, Tag, Push
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
lfs: true
|
||||
|
||||
|
||||
@@ -47,10 +47,10 @@ jobs:
|
||||
short_name: macosm164
|
||||
}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
|
||||
@@ -38,10 +38,10 @@ jobs:
|
||||
short_name: macosm164
|
||||
}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
|
||||
@@ -18,8 +18,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
- name: Compile
|
||||
|
||||
@@ -18,8 +18,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Compile
|
||||
|
||||
@@ -25,8 +25,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
python-version: '3.11'
|
||||
|
||||
@@ -19,8 +19,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
python-version: '3.11'
|
||||
|
||||
@@ -10,9 +10,9 @@ jobs:
|
||||
publish_website:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
- name: Checkout ifctester_org_static_html
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: IfcOpenShell/ifctester_org_static_html
|
||||
token: ${{ secrets.IFCOPENBOT_TOKEN }}
|
||||
|
||||
@@ -18,8 +18,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-python@v7 # https://github.com/actions/setup-python
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
- name: Compile
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
# This file was generated with the assistance of an AI coding tool.
|
||||
name: ci-ifcwrap-standalone
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/ci-ifcwrap-standalone.yml"
|
||||
- "cmake/**"
|
||||
- "src/ifcwrap/**"
|
||||
- "src/ifcparse/**"
|
||||
- "src/ifcgeom/**"
|
||||
- "src/serializers/**"
|
||||
- "src/ifcconvert/**"
|
||||
- "src/ifcopenshell-python/**"
|
||||
- "src/svgfill/**"
|
||||
push:
|
||||
paths:
|
||||
- ".github/workflows/ci-ifcwrap-standalone.yml"
|
||||
- "cmake/**"
|
||||
- "src/ifcwrap/**"
|
||||
- "src/ifcparse/**"
|
||||
- "src/ifcgeom/**"
|
||||
- "src/serializers/**"
|
||||
- "src/ifcconvert/**"
|
||||
- "src/ifcopenshell-python/**"
|
||||
- "src/svgfill/**"
|
||||
|
||||
env:
|
||||
IFCOPENSHELL_PREFIX: ${{ github.workspace }}/ifcopenshell-install
|
||||
|
||||
jobs:
|
||||
build-ifcopenshell:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install C++ dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install --no-install-recommends -y \
|
||||
cmake \
|
||||
gcc \
|
||||
g++ \
|
||||
libboost-date-time-dev \
|
||||
libboost-filesystem-dev \
|
||||
libboost-iostreams-dev \
|
||||
libboost-program-options-dev \
|
||||
libboost-regex-dev \
|
||||
libboost-system-dev \
|
||||
libboost-thread-dev \
|
||||
libeigen3-dev \
|
||||
libocct-data-exchange-dev \
|
||||
libocct-draw-dev \
|
||||
libocct-foundation-dev \
|
||||
libocct-modeling-algorithms-dev \
|
||||
libocct-modeling-data-dev \
|
||||
libocct-ocaf-dev \
|
||||
libocct-visualization-dev \
|
||||
libpcre3-dev \
|
||||
libtbb-dev \
|
||||
libxml2-dev \
|
||||
libxi-dev \
|
||||
occt-misc \
|
||||
tcl-dev \
|
||||
tk-dev \
|
||||
swig
|
||||
|
||||
- name: Configure minimal IfcOpenShell
|
||||
run: |
|
||||
cmake -S cmake -B build-ifcopenshell \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX="${IFCOPENSHELL_PREFIX}" \
|
||||
-DCMAKE_PREFIX_PATH=/usr \
|
||||
-DCMAKE_SYSTEM_PREFIX_PATH=/usr \
|
||||
-DMINIMAL_BUILD=ON \
|
||||
-DBUILD_IFCPYTHON=OFF \
|
||||
"-DSCHEMA_VERSIONS=4x3_add2"
|
||||
|
||||
- name: Build and install minimal IfcOpenShell
|
||||
run: |
|
||||
cmake --build build-ifcopenshell --target install -j "$(nproc)"
|
||||
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: 3.11
|
||||
|
||||
- name: Install Python import dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install numpy typing_extensions
|
||||
|
||||
- name: Configure standalone IfcPython
|
||||
run: |
|
||||
PYTHON_EXECUTABLE="$(python -c 'import sys; print(sys.executable)')"
|
||||
PYTHON_INCLUDE_DIR="$(python -c 'import sysconfig; print(sysconfig.get_path("include"))')"
|
||||
|
||||
cmake -S src/ifcwrap -B "build-ifcwrap-311" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH="${IFCOPENSHELL_PREFIX};/usr" \
|
||||
-DPython_EXECUTABLE:FILEPATH="${PYTHON_EXECUTABLE}" \
|
||||
-DPython_INCLUDE_DIR:PATH="${PYTHON_INCLUDE_DIR}" \
|
||||
-DPYTHON_EXECUTABLE:FILEPATH="${PYTHON_EXECUTABLE}" \
|
||||
-DPYTHON_INCLUDE_DIR:PATH="${PYTHON_INCLUDE_DIR}"
|
||||
|
||||
- name: Build and install standalone IfcPython
|
||||
run: |
|
||||
cmake --build "build-ifcwrap-311" --target install -j "$(nproc)"
|
||||
|
||||
- name: Import installed IfcPython
|
||||
run: |
|
||||
PYTHONPATH="${RUNNER_TEMP}/ifcopenshell-python" python - <<'PY'
|
||||
import ifcopenshell
|
||||
|
||||
print("IfcOpenShell import ok:", ifcopenshell.version)
|
||||
PY
|
||||
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: 3.12
|
||||
|
||||
- name: Install Python import dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install numpy typing_extensions
|
||||
|
||||
- name: Configure standalone IfcPython
|
||||
run: |
|
||||
PYTHON_EXECUTABLE="$(python -c 'import sys; print(sys.executable)')"
|
||||
PYTHON_INCLUDE_DIR="$(python -c 'import sysconfig; print(sysconfig.get_path("include"))')"
|
||||
|
||||
cmake -S src/ifcwrap -B "build-ifcwrap-312" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH="${IFCOPENSHELL_PREFIX};/usr" \
|
||||
-DPython_EXECUTABLE:FILEPATH="${PYTHON_EXECUTABLE}" \
|
||||
-DPython_INCLUDE_DIR:PATH="${PYTHON_INCLUDE_DIR}" \
|
||||
-DPYTHON_EXECUTABLE:FILEPATH="${PYTHON_EXECUTABLE}" \
|
||||
-DPYTHON_INCLUDE_DIR:PATH="${PYTHON_INCLUDE_DIR}"
|
||||
|
||||
- name: Build and install standalone IfcPython
|
||||
run: |
|
||||
cmake --build "build-ifcwrap-312" --target install -j "$(nproc)"
|
||||
|
||||
- name: Import installed IfcPython
|
||||
run: |
|
||||
PYTHONPATH="${RUNNER_TEMP}/ifcopenshell-python" python - <<'PY'
|
||||
import ifcopenshell
|
||||
|
||||
print("IfcOpenShell import ok:", ifcopenshell.version)
|
||||
PY
|
||||
@@ -12,22 +12,25 @@ jobs:
|
||||
MIN_BLENDER_PY_VERSION: "3.11"
|
||||
steps:
|
||||
- name: Action - checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Action - install python
|
||||
uses: actions/setup-python@v7
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ env.MIN_IOS_PY_VERSION }}
|
||||
|
||||
- name: Action - install python
|
||||
uses: actions/setup-python@v7
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ env.MIN_BLENDER_PY_VERSION }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
cat requirements-tools.txt | xargs -L1 uv tool install
|
||||
uv tool install ruff
|
||||
uv tool install black
|
||||
uv tool install poethepoet
|
||||
uv tool install ty
|
||||
|
||||
# black doesn't catch all syntax errors, so we check them explicitly.
|
||||
- name: Check syntax errors
|
||||
@@ -55,17 +58,11 @@ jobs:
|
||||
black --diff --check . | black-codeclimate | python .github/workflows/black_to_github_annotations.py
|
||||
continue-on-error: true
|
||||
|
||||
- name: ty check (venv setup)
|
||||
run: poe ty-venv
|
||||
|
||||
- name: ty check (bonsai)
|
||||
id: ty-bonsai
|
||||
run: poe ty-bonsai
|
||||
continue-on-error: true
|
||||
|
||||
- name: ty check (ios)
|
||||
id: ty-ios
|
||||
run: poe ty-ios
|
||||
- name: ty check
|
||||
id: ty
|
||||
run: |
|
||||
poe ty-venv
|
||||
poe ty
|
||||
continue-on-error: true
|
||||
|
||||
- name: Ruff check
|
||||
@@ -98,7 +95,8 @@ jobs:
|
||||
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
||||
}
|
||||
|
||||
run_check poe ruff
|
||||
run_check poe ruff-main
|
||||
run_check poe ruff-old
|
||||
|
||||
exit $ERROR
|
||||
continue-on-error: true
|
||||
@@ -115,10 +113,7 @@ jobs:
|
||||
if [ "${{ steps.ruff.outcome }}" != "success" ]; then
|
||||
echo "::error::Ruff check failed, see Summary or 'ruff' step for the details." && ERROR=1
|
||||
fi
|
||||
if [ "${{ steps.ty-bonsai.outcome }}" != "success" ]; then
|
||||
echo "::error::ty check (bonsai) failed, see 'ty check (bonsai)' step for the details." && ERROR=1
|
||||
fi
|
||||
if [ "${{ steps.ty-ios.outcome }}" != "success" ]; then
|
||||
echo "::error::ty check (ios) failed, see 'ty check (ios)' step for the details." && ERROR=1
|
||||
if [ "${{ steps.ty.outcome }}" != "success" ]; then
|
||||
echo "::error::ty check failed, see 'ty check' step for the details." && ERROR=1
|
||||
fi
|
||||
exit $ERROR
|
||||
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout IfcOpenShell
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v7
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
echo "name=$(basename $WHEEL)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Checkout wasm-wheels
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: IfcOpenShell/wasm-wheels
|
||||
path: wasm-wheels
|
||||
|
||||
@@ -10,13 +10,9 @@ on:
|
||||
- 'src/ifcgeomserver/**'
|
||||
- 'src/ifcjni/**'
|
||||
- 'src/ifcmax/**'
|
||||
- 'src/ifc5d/**'
|
||||
- 'src/ifcedit/**'
|
||||
- 'src/ifcmcp/**'
|
||||
- 'src/ifcopenshell-python/**'
|
||||
- '!src/ifcopenshell-python/docs/**'
|
||||
- 'src/ifcparse/**'
|
||||
- 'src/ifcquery/**'
|
||||
- 'src/ifcwrap/**'
|
||||
- 'src/qtviewer/**'
|
||||
- 'src/svgfill/**'
|
||||
@@ -43,19 +39,19 @@ jobs:
|
||||
CLICOLOR_FORCE: "1"
|
||||
CMAKE_COLOR_DIAGNOSTICS: "ON"
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v7
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.11
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install xmlschema xsdata numpy lxml pytest isodate lark networkx tabulate python-dateutil shapely pyparsing psutil
|
||||
pip install xmlschema xsdata numpy lxml pytest isodate lark networkx tabulate python-dateutil shapely
|
||||
pip install src/bcf --no-deps
|
||||
pip install pytest-xdist==3.8.0
|
||||
|
||||
@@ -80,10 +76,10 @@ jobs:
|
||||
libtbb-dev nlohmann-json3-dev \
|
||||
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
|
||||
${OCCT_CMAKE_DEPS} \
|
||||
libhdf5-dev libcgal-dev libeigen3-dev
|
||||
libcgal-dev libeigen3-dev
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.23
|
||||
uses: hendrikmuhs/ccache-action@v1.2.22
|
||||
with:
|
||||
key: ubuntu-22.04-${{ runner.arch }}
|
||||
|
||||
@@ -256,28 +252,13 @@ jobs:
|
||||
pip install deepdiff
|
||||
cd ../ifcdiff && make test || ERROR=1
|
||||
cd ../ifcpatch && make test || ERROR=1
|
||||
pip install -e ../ifc5d --no-deps
|
||||
pip install odfpy openpyxl
|
||||
cd ../ifc5d && make test || ERROR=1
|
||||
pip install -e ../ifcquery --no-deps
|
||||
cd ../ifcquery && make test || ERROR=1
|
||||
pip install -e ../ifcedit --no-deps
|
||||
cd ../ifcedit && make test || ERROR=1
|
||||
# Pinned <2: mcp 2.0.0 renamed mcp.server.fastmcp.FastMCP to
|
||||
# mcp.server.mcpserver.MCPServer, which ifcmcp doesn't support yet.
|
||||
pip install "mcp>=1.0,<2"
|
||||
pip install -e ../ifcmcp --no-deps
|
||||
cd ../ifcmcp && make test || ERROR=1
|
||||
pip install -e ../ifctester --no-deps
|
||||
cd ../ifctester && make test || ERROR=1
|
||||
make build-ids-docs || ERROR=1
|
||||
# Run mathutils related tests at the end to ensure no other code is relying on mathutils.
|
||||
# mathutils only has pre-built wheels for Python 3.13+; skip on older versions.
|
||||
cd ../ifcopenshell-python
|
||||
if python -c "import sys; sys.exit(0 if sys.version_info >= (3, 13) else 1)"; then
|
||||
pip install mathutils
|
||||
make test-mathutils || ERROR=1
|
||||
fi
|
||||
pip install mathutils
|
||||
make test-mathutils || ERROR=1
|
||||
if [ $ERROR -ne 0 ]; then
|
||||
echo "One or more tests failed";
|
||||
exit 1;
|
||||
|
||||
@@ -11,10 +11,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v7
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
|
||||
@@ -27,12 +27,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout (recursive)
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
- name: Checkout intermediate Pages repo
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: IfcOpenShell/aichat_ifcopenshell_org_static_html
|
||||
ref: gh-pages
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
run: |
|
||||
rsync -av --delete --exclude='.git/' src/ifcchat/ output/
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v7
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Download wheels
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
name: Publish Bonsai Releases
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- uses: astral-sh/setup-uv@v7
|
||||
|
||||
- run: uv run .github/scripts/publish-bonsai-releases.py
|
||||
env:
|
||||
BLENDER_EXTENSIONS_TOKEN: ${{ secrets.BLENDER_EXTENSIONS_TOKEN }}
|
||||
@@ -27,12 +27,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout (recursive)
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
- name: Checkout intermediate Pages repo
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: IfcOpenShell/wasm_ifcopenshell_org_static_html
|
||||
ref: gh-pages
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install C++ dependencies
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
swig libpcre3-dev libxml2-dev \
|
||||
libtbb-dev nlohmann-json3-dev \
|
||||
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
|
||||
libhdf5-dev libcgal-dev opencollada-dev
|
||||
libcgal-dev opencollada-dev
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
@@ -64,7 +64,6 @@ jobs:
|
||||
-DMPFR_INCLUDE_DIR=/usr/include \
|
||||
-DGMP_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DMPFR_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DHDF5_INCLUDE_DIR=/usr/include/hdf5/serial \
|
||||
-DOPENCOLLADA_INCLUDE_DIR=/usr/include/opencollada \
|
||||
-DOPENCOLLADA_LIBRARY_DIR=/usr/lib/opencollada/ \
|
||||
../cmake
|
||||
|
||||
+3
-5
@@ -4,8 +4,6 @@
|
||||
/_deps-vs*-x*-installed/
|
||||
/_installed-vs*-x*/
|
||||
/build/
|
||||
/build.log
|
||||
/output/
|
||||
/src/examples/build/
|
||||
# ifctester docs output
|
||||
/src/ifctester/test/build/
|
||||
@@ -24,14 +22,12 @@
|
||||
__pycache__
|
||||
*.py.bak
|
||||
venv
|
||||
uv.lock
|
||||
|
||||
# Visual Studio Code files
|
||||
.vscode
|
||||
!.vscode/launch.json
|
||||
!.vscode/tasks.json
|
||||
.vs
|
||||
/*.code-workspace
|
||||
|
||||
# PyCharm files
|
||||
.idea
|
||||
@@ -130,7 +126,9 @@ src/ifcopenshell-python/ifcopenshell/express/*.exp.cache.dat
|
||||
|
||||
# temp files from AI coding tools
|
||||
*.claude
|
||||
CLAUDE.local.md
|
||||
*.py.tmp*
|
||||
*.json.tmp*
|
||||
|
||||
# bonsaiviewer-autodesk connector build artifacts
|
||||
/src/bonsaiviewer-autodesk/build/
|
||||
/src/bonsaiviewer-autodesk/dist/
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ RUN echo "deb http://archive.ubuntu.com/ubuntu focal-proposed main restricted" |
|
||||
libboost-all-dev \
|
||||
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev \
|
||||
libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
|
||||
libhdf5-serial-dev python3-pytest ; \
|
||||
python3-pytest ; \
|
||||
rm -rf /var/lib/apt/lists/* ;
|
||||
|
||||
COPY . /home/IfcOpenShell/
|
||||
|
||||
@@ -18,7 +18,7 @@ and many other libraries, CLI apps, and more. Support is also provided for auxil
|
||||
|
||||
For more information, see:
|
||||
|
||||
* [IfcOpenShell Website](https://ifcopenshell.org)
|
||||
* [IfcOpenShell Website](http://ifcopenshell.org)
|
||||
* [IfcOpenShell Documentation](https://docs.ifcopenshell.org)
|
||||
* [IfcOpenShell C++ Installation](https://docs.ifcopenshell.org/ifcopenshell/installation.html)
|
||||
* [IfcOpenShell Python Installation](https://docs.ifcopenshell.org/ifcopenshell-python/installation.html)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
mkdir -p build && cd build
|
||||
|
||||
cmake ../cmake \
|
||||
-G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DPython_EXECUTABLE=/home/dion/Projects/env/bin/python3.11 \
|
||||
-DPython_INCLUDE_DIR=/usr/include/python3.11 \
|
||||
-DBUILD_IFCPYTHON=ON \
|
||||
-DBUILD_IFCGEOM=ON \
|
||||
-DBUILD_CONVERT=ON \
|
||||
-DBUILD_GEOMSERVER=OFF \
|
||||
-DBUILD_EXAMPLES=OFF \
|
||||
-DWITH_OPENCASCADE=ON \
|
||||
-DWITH_CGAL=ON \
|
||||
-DWITH_MANIFOLD=ON \
|
||||
-DGLTF_SUPPORT=ON \
|
||||
-DIFCXML_SUPPORT=OFF \
|
||||
-DCOLLADA_SUPPORT=OFF \
|
||||
-DSCHEMA_VERSIONS="2x3;4;4x3_add2" \
|
||||
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
|
||||
-DOCC_LIBRARY_DIR=/usr/lib64/opencascade
|
||||
|
||||
ninja
|
||||
|
||||
cp ifcwrap/_ifcopenshell_wrapper*.so ifcwrap/ifcopenshell_wrapper.py \
|
||||
../src/ifcopenshell-python/ifcopenshell/
|
||||
@@ -3,7 +3,7 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>blenderbim-nightly</id>
|
||||
<version>blenderbim_build_version</version>
|
||||
<version>blenderbim_build_version-alpha</version>
|
||||
<packageSourceUrl>https://github.com/IfcOpenShell/IfcOpenShell</packageSourceUrl>
|
||||
<owners>fbpyr</owners>
|
||||
<!-- == SOFTWARE SPECIFIC SECTION == -->
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
apt update && apt install git wget curl ptpython mono-devel micro
|
||||
mkdir -p /home/runner/work/IfcOpenShell && cd /home/runner/work/IfcOpenShell
|
||||
git clone https://github.com/IfcOpenShell/IfcOpenShell
|
||||
cd /home/runner/work/IfcOpenShell/IfcOpenShell/choco/bonsai/
|
||||
cd /home/runner/work/IfcOpenShell/IfcOpenShell/choco/blenderbim/
|
||||
micro choco_release.py # paste this script, comment out push command
|
||||
export CHOCO_TOKEN="secret_choco_release_token"
|
||||
python3 choco_release.py
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import hashlib
|
||||
import os
|
||||
@@ -29,7 +28,7 @@ def get_repo_tag_names() -> list[str]:
|
||||
|
||||
|
||||
def request_repo_info(url: str):
|
||||
req = request.Request(url)
|
||||
req = request.Request(url)
|
||||
resp = request.urlopen(req)
|
||||
if not resp.status == 200:
|
||||
print(f"[ERROR] could not contact server: {url}")
|
||||
@@ -86,15 +85,13 @@ def run(command: str) -> None:
|
||||
|
||||
start = datetime.datetime.now()
|
||||
|
||||
URL_CHOCO_PACKAGE = "https://community.chocolatey.org/packages/blender"
|
||||
URL_BLENDER_CMAKE = (
|
||||
"https://raw.githubusercontent.com/blender/blender/{}/build_files/cmake/Modules/FindPythonLibsUnix.cmake"
|
||||
)
|
||||
RE_BLENDER_VERSION_MIN_MAJ = r"Latest Version.+<span>Blender (\d+\.\d+)\..+</span>"
|
||||
RE_BLENDER_VERSION_MIN_MAJ_PAT = r"Latest Version.+<span>Blender (\d+\.\d+\.\d+)</span>"
|
||||
URL_CHOCO_PACKAGE = "https://community.chocolatey.org/packages/blender"
|
||||
URL_BLENDER_CMAKE = "https://raw.githubusercontent.com/blender/blender/{}/build_files/cmake/Modules/FindPythonLibsUnix.cmake"
|
||||
RE_BLENDER_VERSION_MIN_MAJ = r"Latest Version.+<span>Blender (\d+\.\d+)\..+</span>"
|
||||
RE_BLENDER_VERSION_MIN_MAJ_PAT = r"Latest Version.+<span>Blender (\d+\.\d+\.\d+)</span>"
|
||||
RE_BLENDER_PYTHON_VERSION_MAJ_MIN = r"\(_PYTHON_VERSION_SUPPORTED (\d+\.\d+)\)"
|
||||
|
||||
BLENDERBIM_DIR = pathlib.Path("/home/runner/work/IfcOpenShell/IfcOpenShell/choco/bonsai/")
|
||||
BLENDERBIM_DIR = pathlib.Path("/home/runner/work/IfcOpenShell/IfcOpenShell/choco/blenderbim/")
|
||||
|
||||
print("_____ check choco release needed?")
|
||||
|
||||
@@ -151,7 +148,7 @@ print(f"{blender_python_version_maj_min=}")
|
||||
python_version = f"py{found[0].replace('.', '')}"
|
||||
print(f"{python_version=}")
|
||||
|
||||
blenderbim_build_version = target_release_tag.replace("bonsai-", "")
|
||||
blenderbim_build_version = target_release_tag.replace("blenderbim-", "")
|
||||
|
||||
# url_blenderbim_py3x_win_zip
|
||||
release_zip_file_name, url_blenderbim_py3x_win_zip = get_release_zip(target_release_tag)
|
||||
@@ -169,15 +166,15 @@ topics = {
|
||||
"path": HERE_DIR / "blenderbim.nuspec",
|
||||
"key_values": {
|
||||
"latest_blender_version_maj_min_pat": latest_blender_release_maj_min_pat,
|
||||
"blenderbim_build_version": blenderbim_build_version,
|
||||
"blenderbim_build_version" : blenderbim_build_version,
|
||||
},
|
||||
},
|
||||
"install": {
|
||||
"path": HERE_DIR / "tools" / "chocolateyinstall.ps1",
|
||||
"key_values": {
|
||||
"url_blenderbim_py3x_win_zip": url_blenderbim_py3x_win_zip,
|
||||
"url_blenderbim_py3x_win_zip" : url_blenderbim_py3x_win_zip,
|
||||
"sha256sum_blenderbim_py3x_win_zip": sha256sum_blenderbim_py3x_win_zip,
|
||||
"latest_blender_version_maj_min": blender_version_min_maj,
|
||||
"latest_blender_version_maj_min" : blender_version_min_maj,
|
||||
},
|
||||
},
|
||||
"uninstall": {
|
||||
|
||||
+209
-229
@@ -18,29 +18,19 @@
|
||||
################################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
if(NOT DEFINED CMAKE_CXX_STANDARD)
|
||||
if (NOT DEFINED CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
endif()
|
||||
if(CMAKE_CXX_STANDARD LESS 17)
|
||||
if (CMAKE_CXX_STANDARD LESS 17)
|
||||
message(FATAL_ERROR "C++17 or newer is required.")
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON) # not necessary, but encouraged
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# The VERSION file in the repository root is the single source of truth for the
|
||||
# release version. Read it unconditionally so a plain source build reports the
|
||||
# real version through buildinfo.cpp instead of the stale hardcoded 0.8.0
|
||||
# fallback (see #8164). VERSION_OVERRIDE still controls the branch name used
|
||||
# when ADD_COMMIT_SHA embeds a commit sha.
|
||||
file(READ "../VERSION" "RELEASE_VERSION_")
|
||||
string(STRIP "${RELEASE_VERSION_}" RELEASE_VERSION)
|
||||
message(STATUS "Detected version '${RELEASE_VERSION}'")
|
||||
|
||||
add_definitions(-D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
|
||||
|
||||
if(POLICY CMP0141) # 3.25+
|
||||
# Has to be set before `project` to take effect.
|
||||
cmake_policy(SET CMP0141 NEW) # Support for `CMAKE_MSVC_DEBUG_INFORMATION_FORMAT`.
|
||||
cmake_policy(SET CMP0141 NEW) # Support for `CMAKE_MSVC_DEBUG_INFORMATION_FORMAT`.
|
||||
endif()
|
||||
if(POLICY CMP0144) # 3.27
|
||||
cmake_policy(SET CMP0144 NEW) # find_package() uses upper-case <PACKAGENAME>_ROOT variables.
|
||||
@@ -49,8 +39,6 @@ if(POLICY CMP0167) # 3.30
|
||||
cmake_policy(SET CMP0167 OLD)
|
||||
endif()
|
||||
|
||||
project(IfcOpenShell VERSION ${RELEASE_VERSION})
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
endif()
|
||||
@@ -66,64 +54,69 @@ endif()
|
||||
option(MINIMAL_BUILD "The build is to make a minimal version of IFC converter from OCCT into IFC." OFF)
|
||||
option(WASM_BUILD "Build a WebAssembly binary." OFF)
|
||||
|
||||
option(
|
||||
ENABLE_BUILD_OPTIMIZATIONS
|
||||
"Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds."
|
||||
OFF
|
||||
)
|
||||
option(BUILD_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." OFF)
|
||||
option(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
|
||||
option(BUILD_SHARED_LIBS "Build IfcOpenShell as shared libraries (required)." ON)
|
||||
option(MSVC_PARALLEL_BUILD "Multi-threaded compilation in Microsoft Visual Studio (/MP)" OFF)
|
||||
option(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." OFF)
|
||||
option(USE_MMAP "Adds a command line options to parse IFC files from memory mapped files using Boost.Iostreams" OFF)
|
||||
option(NO_WARN "Disable all warnings" OFF)
|
||||
option(CREATE_BUNDLE "Copy .so files and don't create RPATHS or SOVERSION symlinks" )
|
||||
|
||||
option(BUILD_IFCGEOM "Build IfcGeom." ON)
|
||||
option(BUILD_IFCPYTHON "Build IfcPython." ON)
|
||||
option(BUILD_IFCPARSE_EXPERIMENTAL_WRAPPER "Build the experimental Clang-generated ifcparse Python wrapper." OFF)
|
||||
option(BUILD_CONVERT "Build IfcConvert executable." ON)
|
||||
option(BUILD_DOCUMENTATION "Build IfcOpenShell Documentation." OFF)
|
||||
option(BUILD_EXAMPLES "Build example applications." OFF)
|
||||
option(BUILD_EXAMPLES "Build example applications." ON)
|
||||
option(BUILD_GEOMSERVER "Build IfcGeomServer executable (Open CASCADE is required)." ON)
|
||||
option(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." OFF)
|
||||
option(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer" OFF) # QtViewer requires Qt6
|
||||
option(BUILD_BONSAIVIEWER "Build Bonsai Viewer" OFF) # Requires Qt6 + OpenGL 4.5
|
||||
option(BUILD_BONSAIVIEWER_TESTS "Build unit tests for Bonsai Viewer core (fetches Catch2 v3)" OFF)
|
||||
option(BUILD_PACKAGE "" OFF)
|
||||
# Most users probably need just common schemas,
|
||||
# but we're keeping it `OFF` by default to avoid disruption
|
||||
# (e.g. all Python distribution would need to adapt this option to be set).
|
||||
|
||||
option(
|
||||
BUILD_ONLY_COMMON_SCHEMAS
|
||||
"Build only common IFC schemas (2x3, 4, 4x3_add2). By default all schemas will be built."
|
||||
IFCOPENSHELL_DEPLOY_QT_RUNTIME
|
||||
"Deploy Qt runtime dependencies for installed Qt applications."
|
||||
ON
|
||||
)
|
||||
option(
|
||||
IFCOPENSHELL_DEPLOY_QT_TRANSLATIONS
|
||||
"Deploy Qt translation catalogs with installed Qt applications."
|
||||
OFF
|
||||
)
|
||||
option(SCHEMA_VERSIONS "Explicitly specify schemas to build." "")
|
||||
|
||||
option(WITH_OPENCASCADE "Enable geometry interpretation using Open CASCADE" ON)
|
||||
option(WITH_CGAL "Enable geometry interpretation using CGAL" ON)
|
||||
option(WITH_MANIFOLD "Enable geometry interpretation using Manifold" OFF)
|
||||
option(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON)
|
||||
option(GLTF_SUPPORT "Build IfcConvert with glTF support (requires json.hpp)." OFF)
|
||||
option(HDF5_SUPPORT "Enable HDF5 support (requires HDF5, zlib)" ON)
|
||||
option(WITH_PROJ "Enable output of Earth-Centered Earth-Fixed glTF output using the PROJ library" OFF)
|
||||
option(IFCXML_SUPPORT "Build IfcParse with ifcXML support (requires libxml2)." ON)
|
||||
option(USD_SUPPORT "Build IfcConvert with USD support (requires pixar's USD library)." OFF)
|
||||
option(WITH_RELATIONSHIP_VALIDATION "Build IfcConvert with option to validate geometrical relationships." OFF)
|
||||
option(WITH_ROCKSDB "Support a RocksDB key-value store as a file backend in IfcOpenShell" OFF)
|
||||
option(WITH_ZSTD "Use Zstd compression in RocksDB writes" OFF)
|
||||
|
||||
option(USERSPACE_PYTHON_PREFIX "Installs IfcPython for the current user only instead of system-wide." OFF)
|
||||
option(USE_DEBUG_PYTHON "Use debug binaries when building Debug IfcPython on Windows." OFF)
|
||||
option(ADD_COMMIT_SHA "Add commit sha and branch in version number, requires git" OFF)
|
||||
option(
|
||||
VERSION_OVERRIDE
|
||||
"Override the version defined in buildinfo.cpp with the file VERSION in the repository root"
|
||||
OFF
|
||||
)
|
||||
option(USE_CCACHE "Enable use of ccache if it's available from PATH." ON)
|
||||
option(VERSION_OVERRIDE "Override the version defined in buildinfo.cpp with the file VERSION in the repository root" OFF)
|
||||
|
||||
set(PYTHON_MODULE_INSTALL_DIR
|
||||
""
|
||||
CACHE PATH
|
||||
set(
|
||||
PYTHON_MODULE_INSTALL_DIR
|
||||
"" CACHE PATH
|
||||
"Directory to install IfcPython package to. By default package is installed in found Python's site-packages."
|
||||
)
|
||||
|
||||
if (VERSION_OVERRIDE)
|
||||
file(READ "../VERSION" "RELEASE_VERSION_")
|
||||
string(STRIP "${RELEASE_VERSION_}" RELEASE_VERSION)
|
||||
message(STATUS "Detected version '${RELEASE_VERSION}'")
|
||||
else()
|
||||
set(RELEASE_VERSION "0.8.0")
|
||||
endif()
|
||||
|
||||
project(IfcOpenShell VERSION ${RELEASE_VERSION})
|
||||
|
||||
# Make sure CMake modules in this project are found first
|
||||
list(PREPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
|
||||
|
||||
@@ -134,18 +127,16 @@ if(MINIMAL_BUILD)
|
||||
set(WITH_CGAL OFF)
|
||||
set(COLLADA_SUPPORT OFF)
|
||||
set(GLTF_SUPPORT OFF)
|
||||
set(HDF5_SUPPORT OFF)
|
||||
set(IFCXML_SUPPORT OFF)
|
||||
set(USD_SUPPORT OFF)
|
||||
endif()
|
||||
|
||||
if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND (NOT BUILD_IFCGEOM))
|
||||
if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND(NOT BUILD_IFCGEOM))
|
||||
message(STATUS "'IfcGeom' is required with current outputs")
|
||||
set(BUILD_IFCGEOM ON)
|
||||
endif()
|
||||
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(USE_CCACHE AND CCACHE_FOUND)
|
||||
if(CCACHE_FOUND)
|
||||
message(STATUS "`ccache` is found, using it as a compiler launcher.")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_FOUND}")
|
||||
if(MSVC)
|
||||
@@ -154,15 +145,17 @@ if(USE_CCACHE AND CCACHE_FOUND)
|
||||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>")
|
||||
# Not needed for Ninja.
|
||||
if(CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
file(COPY_FILE ${CCACHE_FOUND} ${CMAKE_BINARY_DIR}/cl.exe ONLY_IF_DIFFERENT)
|
||||
set(CMAKE_VS_GLOBALS "CLToolExe=cl.exe" "CLToolPath=${CMAKE_BINARY_DIR}" "UseMultiToolTask=true")
|
||||
file(COPY_FILE
|
||||
${CCACHE_FOUND} ${CMAKE_BINARY_DIR}/cl.exe
|
||||
ONLY_IF_DIFFERENT)
|
||||
set(CMAKE_VS_GLOBALS
|
||||
"CLToolExe=cl.exe"
|
||||
"CLToolPath=${CMAKE_BINARY_DIR}"
|
||||
"UseMultiToolTask=true"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
mark_as_advanced(CCACHE_FOUND)
|
||||
|
||||
# Variable to accumulate swig definitions from various submodules.
|
||||
set(SWIG_DEFINES "")
|
||||
|
||||
if(MSVC AND MSVC_PARALLEL_BUILD)
|
||||
add_definitions("/MP")
|
||||
@@ -178,28 +171,23 @@ endif()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(IFCOPENSHELL_EXPORT_TARGETS "${PROJECT_NAME}Targets")
|
||||
|
||||
# On Windows Release and Debug binaries are not compatible.
|
||||
# So we add a postfix to avoid issues and allow release and debug installations to coexist.
|
||||
if(WIN32)
|
||||
set(CMAKE_DEBUG_POSTFIX "_d")
|
||||
if(NOT INCLUDEDIR)
|
||||
set(INCLUDEDIR include)
|
||||
endif()
|
||||
if(NOT IS_ABSOLUTE ${INCLUDEDIR})
|
||||
set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
endif()
|
||||
message(STATUS "INCLUDEDIR: ${INCLUDEDIR}")
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
add_definitions(-DIFC_SHARED_BUILD)
|
||||
if(MSVC)
|
||||
message(
|
||||
WARNING
|
||||
"Building DLLs against the static VC run-time. This is not recommended if the DLLs are to be redistributed."
|
||||
)
|
||||
# C4521: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
|
||||
# There will be couple hundreds of these so suppress them away, https://msdn.microsoft.com/en-us/library/esew7y1w.aspx
|
||||
add_definitions(-wd4251)
|
||||
endif()
|
||||
if(MSVC)
|
||||
message(WARNING "Building DLLs against the static VC run-time. This is not recommended if the DLLs are to be redistributed.")
|
||||
# C4521: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
|
||||
# There will be couple hundreds of these so suppress them away, https://msdn.microsoft.com/en-us/library/esew7y1w.aspx
|
||||
add_definitions(-wd4251)
|
||||
endif()
|
||||
|
||||
UNIFY_ENVVARS_AND_CACHE(BOOST_ROOT)
|
||||
UNIFY_ENVVARS_AND_CACHE(BOOST_LIBRARYDIR)
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
UNIFY_ENVVARS_AND_CACHE(PYTHON_INCLUDE_DIR)
|
||||
@@ -215,75 +203,75 @@ foreach(option_flag IN LISTS option_flags)
|
||||
convert_env_var_to_bool("${option_flag}")
|
||||
endforeach()
|
||||
|
||||
if(WITH_CGAL)
|
||||
find_package(CGAL REQUIRED)
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DIFOPSH_WITH_CGAL)
|
||||
list(APPEND GEOMETRY_KERNELS cgal)
|
||||
endif()
|
||||
|
||||
if(BUILD_IFCGEOM AND WITH_OPENCASCADE)
|
||||
find_package(OpenCASCADE REQUIRED)
|
||||
add_definitions(-DIFOPSH_WITH_OPENCASCADE)
|
||||
# Map OpenCASCADE_LIBRARIES variable from OpenCASCADEConfig.cmake to OpenCASCADE_LIBRARIES used by kernel generic cmake file
|
||||
set(OpenCASCADE_LIBRARIES ${OpenCASCADE_LIBRARIES})
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DIFOPSH_WITH_OPENCASCADE)
|
||||
list(APPEND GEOMETRY_KERNELS opencascade)
|
||||
endif()
|
||||
|
||||
set(GLTF_LIBRARIES "")
|
||||
message(STATUS "BUILD_IFCGEOM WITH_MANIFOLD: ${BUILD_IFCGEOM} ${WITH_MANIFOLD}")
|
||||
|
||||
if(BUILD_IFCGEOM AND WITH_MANIFOLD)
|
||||
find_package(manifold CONFIG REQUIRED)
|
||||
if(TARGET manifold::manifold)
|
||||
set(MANIFOLD_LIBRARIES manifold::manifold)
|
||||
elseif(TARGET manifold)
|
||||
set(MANIFOLD_LIBRARIES manifold)
|
||||
else()
|
||||
message(FATAL_ERROR "Unable to determine manifold target")
|
||||
endif()
|
||||
list(APPEND GEOMETRY_KERNELS manifold)
|
||||
endif()
|
||||
|
||||
if(BUILD_IFCGEOM)
|
||||
list(APPEND GEOMETRY_KERNELS passthrough)
|
||||
endif()
|
||||
|
||||
if(GLTF_SUPPORT)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
set(GLTF_LIBRARIES nlohmann_json::nlohmann_json)
|
||||
add_definitions(-DWITH_GLTF)
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_GLTF)
|
||||
endif()
|
||||
|
||||
# Add USD support to serializers
|
||||
set(USD_LIBRARIES "")
|
||||
if(USD_SUPPORT)
|
||||
find_package(USD REQUIRED)
|
||||
set(USD_LIBRARIES pxr::USD)
|
||||
endif(USD_SUPPORT)
|
||||
|
||||
set(ROCKSDB_LIBRARIES "")
|
||||
if(WITH_ROCKSDB)
|
||||
if (WITH_ROCKSDB)
|
||||
# Temporaily mess with CMAKE_FIND_PACKAGE_PREFER_CONFIG to help RocksDB
|
||||
# find it's zstd dependency on Windows.
|
||||
# Only do it on Windows, otherwise it might create problems as
|
||||
# findzstd and zstd-config target names do not match.
|
||||
# https://github.com/facebook/rocksdb/pull/13975
|
||||
if(WIN32)
|
||||
set(TEMP CMAKE_FIND_PACKAGE_PREFER_CONFIG)
|
||||
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)
|
||||
endif()
|
||||
find_package(RocksDB CONFIG REQUIRED)
|
||||
mark_as_advanced(RocksDB_DIR)
|
||||
if(WIN32)
|
||||
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ${TEMP})
|
||||
endif()
|
||||
|
||||
message(STATUS "RocksDB: found at '${RocksDB_DIR}'.")
|
||||
add_library(IFCOPENSHELL_RocksDB INTERFACE)
|
||||
set(ROCKSDB_LIBRARIES "IFCOPENSHELL_RocksDB")
|
||||
target_compile_definitions(IFCOPENSHELL_RocksDB INTERFACE IFOPSH_WITH_ROCKSDB)
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DIFOPSH_WITH_ROCKSDB)
|
||||
# See https://github.com/facebook/rocksdb/issues/981.
|
||||
if(TARGET RocksDB::rocksdb)
|
||||
target_link_libraries(IFCOPENSHELL_RocksDB INTERFACE RocksDB::rocksdb)
|
||||
elseif(TARGET RocksDB::rocksdb-shared)
|
||||
target_link_libraries(IFCOPENSHELL_RocksDB INTERFACE RocksDB::rocksdb-shared)
|
||||
else()
|
||||
message(FATAL_ERROR "RocksDB found but neither RocksDB::rocksdb nor RocksDB::rocksdb-shared target exists")
|
||||
endif()
|
||||
|
||||
if(WITH_ZSTD)
|
||||
if (WITH_ZSTD)
|
||||
# @todo do we actually need the zstd include dir or rather just pass
|
||||
# the libzstd.a along with the rocksdb library when needed and feature
|
||||
# detect based on rocksdb API?
|
||||
find_package(zstd CONFIG REQUIRED)
|
||||
mark_as_advanced(zstd_DIR)
|
||||
message(STATUS "zstd: found at '${zstd_DIR}'.")
|
||||
target_link_libraries(IFCOPENSHELL_RocksDB INTERFACE zstd::libzstd_static)
|
||||
endif()
|
||||
|
||||
install(TARGETS IFCOPENSHELL_RocksDB EXPORT ${IFCOPENSHELL_EXPORT_TARGETS})
|
||||
endif()
|
||||
|
||||
# Find Boost: On win32 the (hardcoded) default is to use static libraries and
|
||||
# runtime, when doing running conda-build we pick what conda prepared for us.
|
||||
if(WIN32 AND NOT DEFINED ENV{CONDA_BUILD})
|
||||
if(WIN32 AND("$ENV{CONDA_BUILD}" STREQUAL ""))
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_STATIC_RUNTIME OFF)
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
@@ -314,18 +302,8 @@ if(WASM_BUILD)
|
||||
else()
|
||||
# @todo review this, shouldn't this be all possible header-only now?
|
||||
# ... or rewritten using C++17 features?
|
||||
# Boost.System has been header-only since 1.69 and its compiled stub library
|
||||
# was dropped in newer Boost, so requesting it as a component makes
|
||||
# find_package fail on Boost 1.70 and up (for example Boost 1.90). It is
|
||||
# still pulled in transitively by thread / iostreams where needed, so do not
|
||||
# request it explicitly.
|
||||
set(BOOST_COMPONENTS
|
||||
program_options
|
||||
regex
|
||||
thread
|
||||
date_time
|
||||
iostreams
|
||||
)
|
||||
# set(BOOST_COMPONENTS system program_options regex thread date_time iostreams)
|
||||
set(BOOST_COMPONENTS program_options regex thread date_time iostreams)
|
||||
endif()
|
||||
|
||||
if(USE_MMAP)
|
||||
@@ -335,17 +313,6 @@ if(USE_MMAP)
|
||||
else()
|
||||
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} iostreams)
|
||||
endif()
|
||||
|
||||
add_definitions(-DUSE_MMAP)
|
||||
endif()
|
||||
|
||||
# Handle CGAL after Boost settings are set, since CGAL will use them too.
|
||||
# Do `find_package(Boost)` only after this, to make sure `FindBoost` finds correct components.
|
||||
# Otherwise it will find components needed for CGAL and we might some libraries.
|
||||
if(WITH_CGAL)
|
||||
find_package(CGAL REQUIRED)
|
||||
set(CGAL_LIBRARIES IFCOPENSHELL_CGAL)
|
||||
list(APPEND GEOMETRY_KERNELS cgal)
|
||||
endif()
|
||||
|
||||
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
||||
@@ -354,17 +321,8 @@ message(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}")
|
||||
|
||||
if(COLLADA_SUPPORT)
|
||||
find_package(OpenCOLLADA REQUIRED)
|
||||
add_definitions(-DWITH_OPENCOLLADA)
|
||||
endif()
|
||||
|
||||
if(HDF5_SUPPORT)
|
||||
find_package(HDF5 REQUIRED COMPONENTS C CXX)
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} hdf5::hdf5_cpp)
|
||||
|
||||
add_definitions(-DWITH_HDF5)
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_HDF5)
|
||||
endif(HDF5_SUPPORT)
|
||||
|
||||
if(ENABLE_BUILD_OPTIMIZATIONS)
|
||||
if(MSVC)
|
||||
# NOTE: RelWithDebInfo and Release use O2 (= /Ox /Gl /Gy/ = Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy) by default,
|
||||
@@ -377,20 +335,12 @@ if(ENABLE_BUILD_OPTIMIZATIONS)
|
||||
|
||||
# Linker
|
||||
# /OPT:REF enables also /OPT:ICF and disables INCREMENTAL
|
||||
set(LINKER_FLAGS_RELEASE "/LTCG /OPT:REF")
|
||||
# /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx)
|
||||
set(LINKER_FLAGS_RELWITHDEBINFO "/DEBUG /OPT:NOICF")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELEASE}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELWITHDEBINFO}"
|
||||
)
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELEASE}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELWITHDEBINFO}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELEASE}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO
|
||||
"${CMAKE_MODULE_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELWITHDEBINFO}"
|
||||
)
|
||||
# /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
|
||||
else()
|
||||
# GCC-like: Release should use O3 but RelWithDebInfo 02 so enforce 03. Anything other useful that could be added here?
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
@@ -439,7 +389,7 @@ if(MSVC)
|
||||
endif()
|
||||
|
||||
# Enforce standards-conformance on VS > 2015, older Boost versions fail to compile with this
|
||||
if(MSVC_VERSION GREATER 1900 AND (Boost_MAJOR_VERSION GREATER 1 OR Boost_MINOR_VERSION GREATER 66))
|
||||
if(MSVC_VERSION GREATER 1900 AND(Boost_MAJOR_VERSION GREATER 1 OR Boost_MINOR_VERSION GREATER 66))
|
||||
add_definitions(-permissive-)
|
||||
endif()
|
||||
|
||||
@@ -458,11 +408,11 @@ if(MSVC)
|
||||
# endforeach()
|
||||
# endif()
|
||||
|
||||
add_definitions(-D_ENABLE_EXTENDED_ALIGNED_STORAGE)
|
||||
# See #5158.
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.40)
|
||||
add_definitions(-D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
|
||||
endif()
|
||||
add_definitions(-D_ENABLE_EXTENDED_ALIGNED_STORAGE)
|
||||
# See #5158.
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.40)
|
||||
add_definitions(-D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
|
||||
endif()
|
||||
else()
|
||||
add_definitions(-Wall -Wextra)
|
||||
|
||||
@@ -472,10 +422,7 @@ else()
|
||||
add_definitions(-Wno-maybe-uninitialized)
|
||||
endif()
|
||||
|
||||
if(
|
||||
CMAKE_CXX_COMPILER_ID MATCHES "GNU"
|
||||
AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 9.0)
|
||||
)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 9.0))
|
||||
# OpenCascade spews a lot of deprecated-copy warnings
|
||||
add_definitions(-Wno-deprecated-copy)
|
||||
endif()
|
||||
@@ -486,45 +433,28 @@ else()
|
||||
endif()
|
||||
endif(MSVC)
|
||||
|
||||
include_directories(${OPENCOLLADA_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${HDF5_INCLUDE_DIR})
|
||||
include_directories(${INCLUDE_DIRECTORIES}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${CGAL_INCLUDE_DIR} ${GMP_INCLUDE_DIR} ${MPFR_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
if(NOT SCHEMA_VERSIONS)
|
||||
# `WASM_BUILD` - super arbitrarily try to keep size down at least a little bit
|
||||
if(BUILD_ONLY_COMMON_SCHEMAS OR WASM_BUILD)
|
||||
if(WASM_BUILD)
|
||||
# super arbitrarily try to keep size down at least a little bit
|
||||
set(SCHEMA_VERSIONS "2x3" "4" "4x3_add2")
|
||||
else()
|
||||
set(SCHEMA_VERSIONS
|
||||
"2x3"
|
||||
"4"
|
||||
"4x1"
|
||||
"4x2"
|
||||
"4x3"
|
||||
"4x3_tc1"
|
||||
"4x3_add1"
|
||||
"4x3_add2"
|
||||
)
|
||||
set(SCHEMA_VERSIONS "2x3" "4" "4x1" "4x2" "4x3" "4x3_tc1" "4x3_add1" "4x3_add2")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "IFC SCHEMA_VERSIONS that will be used for the build: ${SCHEMA_VERSIONS}.")
|
||||
|
||||
set(SCHEMA_DEFINITIONS "")
|
||||
foreach(schema ${SCHEMA_VERSIONS})
|
||||
list(APPEND SCHEMA_DEFINITIONS "-DHAS_SCHEMA_${schema}")
|
||||
endforeach()
|
||||
|
||||
string(REPLACE ";" ")(" schema_version_seq "(${SCHEMA_VERSIONS})")
|
||||
list(APPEND SCHEMA_DEFINITIONS "-DSCHEMA_SEQ=${schema_version_seq}")
|
||||
|
||||
if(COMPILE_SCHEMA)
|
||||
# @todo, this appears to be untested at the moment
|
||||
find_package(PythonInterp)
|
||||
|
||||
if(NOT PYTHONINTERP_FOUND)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed."
|
||||
)
|
||||
message(FATAL_ERROR "A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed.")
|
||||
endif()
|
||||
|
||||
set(IFC_RELEASE_NOT_USED ${SCHEMA_VERSIONS})
|
||||
@@ -544,10 +474,7 @@ if(COMPILE_SCHEMA)
|
||||
|
||||
if("${PYPARSING_FOUND}" STREQUAL "-1")
|
||||
message(STATUS "Installing pyparsing")
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} -m pip "install" --user pyparsing
|
||||
RESULT_VARIABLE SUCCESS
|
||||
)
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
|
||||
|
||||
if(NOT "${SUCCESS}" STREQUAL "0")
|
||||
execute_process(COMMAND pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
|
||||
@@ -562,23 +489,19 @@ if(COMPILE_SCHEMA)
|
||||
|
||||
# Bootstrap the parser
|
||||
message(STATUS "Compiling schema, this will take a while...")
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} bootstrap.py
|
||||
WORKING_DIRECTORY ../src/ifcopenshell-python/ifcopenshell/express
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} bootstrap.py express.bnf
|
||||
WORKING_DIRECTORY ../src/ifcexpressparser
|
||||
OUTPUT_FILE express_parser.py
|
||||
RESULT_VARIABLE SUCCESS
|
||||
)
|
||||
RESULT_VARIABLE SUCCESS)
|
||||
|
||||
if(NOT "${SUCCESS}" STREQUAL "0")
|
||||
message(FATAL_ERROR "Failed to bootstrap parser. Make sure pyparsing is installed")
|
||||
endif()
|
||||
|
||||
# Generate code
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} ../ifcopenshell-python/ifcopenshell/express/express_parser.py ../../${COMPILE_SCHEMA}
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} ../ifcexpressparser/express_parser.py ../../${COMPILE_SCHEMA}
|
||||
WORKING_DIRECTORY ../src/ifcparse
|
||||
OUTPUT_VARIABLE COMPILED_SCHEMA_NAME
|
||||
)
|
||||
OUTPUT_VARIABLE COMPILED_SCHEMA_NAME)
|
||||
|
||||
# Prevent the schema that had just been compiled from being excluded
|
||||
foreach(schema ${SCHEMA_VERSIONS})
|
||||
@@ -593,17 +516,40 @@ if(NOT Boost_VERSION LESS 105800)
|
||||
add_definitions(-DBOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE)
|
||||
endif()
|
||||
|
||||
add_subdirectory(../src/plugin plugin)
|
||||
|
||||
add_subdirectory(../src/ifcparse ifcparse)
|
||||
set(IFCOPENSHELL_LIBRARIES IfcParse)
|
||||
|
||||
if(BUILD_IFCPARSE_EXPERIMENTAL_WRAPPER)
|
||||
add_subdirectory(../src/wrappergen wrappergen)
|
||||
endif()
|
||||
|
||||
if(BUILD_IFCGEOM)
|
||||
# CGAL::CGAL target already has dependencies resolved.
|
||||
if(WITH_CGAL AND CGAL_DIR)
|
||||
set(CGAL_LIBRARIES CGAL::CGAL)
|
||||
message(STATUS "Using found CGAL package at '${CGAL_DIR}'")
|
||||
elseif(WITH_CGAL AND NOT CGAL_DIR)
|
||||
find_library(libGMP NAMES gmp mpir PATHS ${GMP_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
find_library(libMPFR NAMES mpfr PATHS ${MPFR_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
if(NOT libGMP)
|
||||
message(FATAL_ERROR "Unable to find GMP library files, aborting")
|
||||
endif()
|
||||
if(NOT libMPFR)
|
||||
message(FATAL_ERROR "Unable to find MPFR library files, aborting")
|
||||
endif()
|
||||
|
||||
list(APPEND CGAL_LIBRARIES "${libMPFR}")
|
||||
list(APPEND CGAL_LIBRARIES "${libGMP}")
|
||||
endif()
|
||||
|
||||
add_subdirectory(../src/ifcgeom ifcgeom)
|
||||
endif(BUILD_IFCGEOM)
|
||||
|
||||
if(BUILD_CONVERT OR BUILD_IFCPYTHON)
|
||||
if(BUILD_CONVERT OR BUILD_IFCPYTHON OR BUILD_BONSAIVIEWER)
|
||||
add_subdirectory(../src/serializers serializers)
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} ${SERIALIZER_SCHEMA_LIBRARIES})
|
||||
endif(BUILD_CONVERT OR BUILD_IFCPYTHON)
|
||||
endif(BUILD_CONVERT OR BUILD_IFCPYTHON OR BUILD_BONSAIVIEWER)
|
||||
|
||||
if(BUILD_CONVERT)
|
||||
add_subdirectory(../src/ifcconvert ifcconvert)
|
||||
@@ -622,8 +568,8 @@ if(ADD_COMMIT_SHA)
|
||||
endif()
|
||||
|
||||
if(GIT_FOUND)
|
||||
if(VERSION_OVERRIDE)
|
||||
set(git_branch ${RELEASE_VERSION})
|
||||
if (VERSION_OVERRIDE)
|
||||
set (git_branch ${RELEASE_VERSION})
|
||||
else()
|
||||
message("git found: ${GIT_EXECUTABLE} with version ${GIT_VERSION_STRING}")
|
||||
execute_process(
|
||||
@@ -635,8 +581,8 @@ if(ADD_COMMIT_SHA)
|
||||
string(REPLACE "\n" ";" git_branch_list "${git_branches}")
|
||||
|
||||
foreach(git_branch_candidate IN ITEMS ${git_branch_list})
|
||||
string(REPLACE "*" "" git_branch_candidate_temp "${git_branch_candidate}")
|
||||
string(STRIP "${git_branch_candidate_temp}" git_branch_candidate_2)
|
||||
string(REPLACE "*" "" git_branch_candidate_temp "${git_branch_candidate}")
|
||||
string(STRIP "${git_branch_candidate_temp}" git_branch_candidate_2)
|
||||
if(NOT git_branch_candidate_2 MATCHES "^HEAD$")
|
||||
string(REPLACE "/" ";" git_branch_candidate_2_list "${git_branch_candidate_2}")
|
||||
list(GET git_branch_candidate_2_list -1 git_branch)
|
||||
@@ -654,22 +600,17 @@ if(ADD_COMMIT_SHA)
|
||||
message(STATUS "IfcOpenShell branch: \"${git_branch}\"")
|
||||
message(STATUS "IfcOpenShell commit: \"${git_sha}\"")
|
||||
|
||||
if("${git_branch}" STREQUAL "" OR "${git_sha}" STREQUAL "")
|
||||
if ("${git_branch}" STREQUAL "" OR "${git_sha}" STREQUAL "")
|
||||
message(FATAL_ERROR "Unable to determine commit sha and/or branch")
|
||||
endif()
|
||||
|
||||
target_compile_definitions(
|
||||
IfcParse
|
||||
PRIVATE -DIFCOPENSHELL_BRANCH=${git_branch} -DIFCOPENSHELL_COMMIT=${git_sha}
|
||||
target_compile_definitions(IfcParse PRIVATE
|
||||
-DIFCOPENSHELL_BRANCH=${git_branch}
|
||||
-DIFCOPENSHELL_COMMIT=${git_sha}
|
||||
)
|
||||
endif()
|
||||
endif(ADD_COMMIT_SHA)
|
||||
|
||||
# Always expose the release version (from the VERSION file) to buildinfo.cpp so
|
||||
# that a build without commit-sha info reports the correct version instead of a
|
||||
# stale hardcoded fallback. See #8164.
|
||||
target_compile_definitions(IfcParse PRIVATE IFCOPENSHELL_VERSION_STRING=${RELEASE_VERSION})
|
||||
|
||||
if(MSVC)
|
||||
# @todo still needs to be understood better, but the cgal and cgal-simple kernel cause multiply defined boost lambda placeholders _1 ... _3
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /FORCE:MULTIPLE")
|
||||
@@ -683,10 +624,6 @@ if(BUILD_DOCUMENTATION)
|
||||
add_subdirectory(../docs docs)
|
||||
endif()
|
||||
|
||||
if(BUILD_IFCPYTHON)
|
||||
add_subdirectory(../src/ifcwrap ifcwrap)
|
||||
endif()
|
||||
|
||||
if(BUILD_EXAMPLES)
|
||||
add_subdirectory(../src/examples examples)
|
||||
endif()
|
||||
@@ -699,32 +636,82 @@ if(BUILD_IFCPYTHON AND WITH_CGAL)
|
||||
add_subdirectory(../src/svgfill svgfill)
|
||||
endif()
|
||||
|
||||
if(BUILD_IFCPYTHON)
|
||||
add_subdirectory(../src/ifcwrap ifcwrap)
|
||||
endif()
|
||||
|
||||
if(BUILD_QTVIEWER)
|
||||
add_subdirectory(../src/qtviewer qtviewer)
|
||||
endif()
|
||||
|
||||
if(BUILD_IFCGEOM)
|
||||
# install(FILES ${IFCGEOM_H_FILES}
|
||||
# DESTINATION ${INCLUDEDIR}/ifcgeom
|
||||
# )
|
||||
|
||||
install(FILES ${SCHEMA_AGNOSTIC_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom
|
||||
)
|
||||
|
||||
file(GLOB SERIALIZATION_H_FILES ../src/ifcgeom/serialization/*.h)
|
||||
install(FILES ${SERIALIZATION_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom/serialization
|
||||
)
|
||||
|
||||
foreach(kernel ${GEOMETRY_KERNELS})
|
||||
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/kernels/${kernel}/*.h)
|
||||
install(FILES ${IFCGEOM_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom/kernels/${kernel}
|
||||
)
|
||||
endforeach()
|
||||
|
||||
install(TARGETS ${IFCGEOM_SCHEMA_LIBRARIES} ${kernel_libraries} IfcGeom)
|
||||
endif(BUILD_IFCGEOM)
|
||||
if(BUILD_BONSAIVIEWER)
|
||||
if(BUILD_BONSAIVIEWER_TESTS)
|
||||
# Catch2 v3 — fetched on demand. Test option is OFF by default so the
|
||||
# default build remains offline-capable.
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
Catch2
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||
GIT_TAG v3.5.4
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
FetchContent_MakeAvailable(Catch2)
|
||||
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
|
||||
include(CTest)
|
||||
include(Catch)
|
||||
enable_testing()
|
||||
endif()
|
||||
|
||||
add_subdirectory(../src/ifcviewer ifcviewer)
|
||||
add_subdirectory(../src/ifcviewer-minimal ifcviewer-minimal)
|
||||
add_subdirectory(../src/bonsaiviewer bonsaiviewer)
|
||||
endif()
|
||||
|
||||
# Cmake uninstall target
|
||||
if(NOT TARGET uninstall)
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||
IMMEDIATE
|
||||
@ONLY
|
||||
)
|
||||
IMMEDIATE @ONLY)
|
||||
|
||||
add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
endif()
|
||||
|
||||
# Packaging
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES "/\\\\.git" "/build/" "/.pytest_cache/" "/__pycache__/")
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES
|
||||
"/\\\\.git"
|
||||
"/build/"
|
||||
"/.pytest_cache/"
|
||||
"/__pycache__/"
|
||||
)
|
||||
set(CPACK_SOURCE_INSTALLED_DIRECTORIES "${CMAKE_SOURCE_DIR}/..;/")
|
||||
set(CPACK_PACKAGE_NAME
|
||||
"${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}"
|
||||
)
|
||||
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}${EXTRA_VERSION}")
|
||||
set(CPACK_PACKAGE_FILE_NAME
|
||||
"${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}-${CMAKE_SYSTEM_NAME}"
|
||||
)
|
||||
SET(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}-${CMAKE_SYSTEM_NAME}")
|
||||
set(CPACK_PACKAGE_DIRECTORY "${PROJECT_BINARY_DIR}/assets")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IfcOpenShell")
|
||||
set(CPACK_PACKAGE_DESCRIPTION "IfcOpenShell.")
|
||||
@@ -737,7 +724,6 @@ set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
|
||||
set(CPACK_GENERATOR "TGZ;DEB")
|
||||
set(CPACK_SOURCE_GENERATOR "TGZ")
|
||||
|
||||
set(BOOST_DEPS "")
|
||||
foreach(COMPONENT IN ITEMS ${BOOST_COMPONENTS})
|
||||
string(REPLACE "_" "-" COMP ${COMPONENT})
|
||||
set(BOOST_DEPS "${BOOST_DEPS}, libboost-${COMP}-dev")
|
||||
@@ -745,19 +731,13 @@ endforeach(COMPONENT)
|
||||
|
||||
set(CPACK_DEBIAN_PACKAGE_NAME "${PROJECT_NAME}")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_CONTACT}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS
|
||||
"python3, libxml2, libocct-foundation-dev, libocct-modeling-algorithms-dev, libocct-modeling-data-dev, libocct-ocaf-dev, libocct-visualization-dev, libocct-data-exchange-dev, libhdf5-serial-dev, libpython3-dev, python3-pytest ${BOOST_DEPS}"
|
||||
)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "python3, libxml2, libocct-foundation-dev, libocct-modeling-algorithms-dev, libocct-modeling-data-dev, libocct-ocaf-dev, libocct-visualization-dev, libocct-data-exchange-dev, libpython3-dev, python3-pytest ${BOOST_DEPS}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION_SUMMARY "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION}")
|
||||
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION "science")
|
||||
set(CPACK_DEBIAN_PACKAGE_VERSION
|
||||
"${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}${EXTRA_VERSION}"
|
||||
)
|
||||
set(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}${EXTRA_VERSION}")
|
||||
set(CPACK_DEBIAN_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}")
|
||||
# set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/cmake/debian/postinst")
|
||||
|
||||
include(CPack)
|
||||
|
||||
include(package_export.cmake)
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
"BUILD_CONVERT": "ON",
|
||||
"BUILD_IFCMAX": "OFF",
|
||||
"IFCXML_SUPPORT": "ON",
|
||||
"HDF5_SUPPORT": "ON",
|
||||
"SCHEMA_VERSIONS": "4x3_add2",
|
||||
"CMAKE_GENERATOR_PLATFORM": "",
|
||||
"CMAKE_GENERATOR_TOOLSET": ""
|
||||
@@ -50,8 +49,6 @@
|
||||
"MPFR_LIBRARY_DIR": "$env{LIBRARY_PREFIX}/lib",
|
||||
"Boost_LIBRARY_DIR": "$env{LIBRARY_PREFIX}/lib",
|
||||
"Boost_INCLUDE_DIR": "$env{LIBRARY_PREFIX}/include",
|
||||
"HDF5_INCLUDE_DIR": "$env{LIBRARY_PREFIX}/include",
|
||||
"HDF5_LIBRARY_DIR": "$env{LIBRARY_PREFIX}/lib",
|
||||
"ZLIB_INCLUDE_DIR": "$env{LIBRARY_PREFIX}/include"
|
||||
}
|
||||
},
|
||||
@@ -110,4 +107,4 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# - `GMP_LIBRARY_DIR`
|
||||
# - `MPFR_INCLUDE_DIR`
|
||||
# - `MPFR_LIBRARY_DIR`
|
||||
# If input variables are not specified, try to find HDF5 config.
|
||||
# If input variables are not specified, try to find CGAL config.
|
||||
# Input variables could also be provided as environment variables.
|
||||
#
|
||||
# Output targets:
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
#
|
||||
# Input variables:
|
||||
# - `HDF5_INCLUDE_DIR`
|
||||
# - `HDF5_LIBRARY_DIR`
|
||||
# - `HDF5_LIBRARIES`
|
||||
# If input variables are not specified, try to find HDF5 config.
|
||||
# Input variables could also be provided as environment variables.
|
||||
#
|
||||
# Output variables:
|
||||
# - `HDF5_INCLUDE_DIR`
|
||||
# - `HDF5_LIBRARY_DIR`
|
||||
# - `HDF5_LIBRARIES`
|
||||
#
|
||||
|
||||
UNIFY_ENVVARS_AND_CACHE(HDF5_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(HDF5_LIBRARY_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(HDF5_LIBRARIES)
|
||||
|
||||
# To avoid cyclic calls to this file
|
||||
list(REMOVE_ITEM CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR})
|
||||
|
||||
if(NOT HDF5_INCLUDE_DIR)
|
||||
message(STATUS "No HDF5 include directory specified")
|
||||
else()
|
||||
set(HDF5_INCLUDE_DIR "${HDF5_INCLUDE_DIR}" CACHE FILEPATH "HDF5 header files")
|
||||
endif()
|
||||
|
||||
if(NOT HDF5_LIBRARY_DIR)
|
||||
message(STATUS "No HDF5 library directory specified")
|
||||
else()
|
||||
set(HDF5_LIBRARY_DIR "${HDF5_LIBRARY_DIR}" CACHE FILEPATH "HDF5 library files")
|
||||
endif()
|
||||
|
||||
if(HDF5_LIBRARY_DIR)
|
||||
# result of the HDF5 ctest package
|
||||
# Find zlib using cmake find_library. How should this be implemented?
|
||||
# FIND_LIBRARY(NAMES z libz libz_debug PATHS ... NO_DEFAULT_PATH)
|
||||
if(NOT DEFINED ENV{CONDA_BUILD})
|
||||
# result of the HDF5 ctest package
|
||||
if(WIN32)
|
||||
set(zlib_post lib)
|
||||
set(lib_ext lib)
|
||||
else()
|
||||
set(lib_ext a)
|
||||
endif()
|
||||
|
||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
set(debug_postfix "_debug")
|
||||
endif()
|
||||
|
||||
set(HDF5_LIBRARIES
|
||||
"${HDF5_LIBRARY_DIR}/libhdf5_cpp${debug_postfix}.${lib_ext}"
|
||||
"${HDF5_LIBRARY_DIR}/libhdf5${debug_postfix}.${lib_ext}"
|
||||
"${HDF5_LIBRARY_DIR}/libz${zlib_post}${debug_postfix}.${lib_ext}"
|
||||
"${HDF5_LIBRARY_DIR}/libsz${debug_postfix}.${lib_ext}"
|
||||
"${HDF5_LIBRARY_DIR}/libaec${debug_postfix}.${lib_ext}"
|
||||
)
|
||||
else()
|
||||
message(STATUS "Packaging hdf5 and zlib for conda distribution")
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
# macOS
|
||||
set(zlib_post libz)
|
||||
set(lib_ext dylib)
|
||||
set(HDF5_LIBRARIES
|
||||
"${HDF5_LIBRARY_DIR}/libhdf5_cpp.${lib_ext}"
|
||||
"${HDF5_LIBRARY_DIR}/libhdf5.${lib_ext}"
|
||||
"${HDF5_LIBRARY_DIR}/${zlib_post}.${lib_ext}"
|
||||
)
|
||||
else()
|
||||
# linux and windows
|
||||
# Find HDF5 package
|
||||
find_package(HDF5 REQUIRED COMPONENTS C CXX)
|
||||
# Find ZLIB package
|
||||
find_package(ZLIB REQUIRED)
|
||||
# Include directories
|
||||
include_directories(${HDF5_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS})
|
||||
# Link libraries
|
||||
set(HDF5_LIBRARIES ${HDF5_LIBRARIES} ${ZLIB_LIBRARIES})
|
||||
message(STATUS "HDF5 libraries: ${HDF5_LIBRARIES}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT HDF5_INCLUDE_DIR OR NOT HDF5_LIBRARY_DIR)
|
||||
# First try to find it as a config.
|
||||
find_package(HDF5 CONFIG)
|
||||
mark_as_advanced(HDF5_DIR)
|
||||
if(HDF5_DIR)
|
||||
message(STATUS "HDF5: found config at '${HDF5_DIR}'.")
|
||||
if(TARGET hdf5_cpp-static)
|
||||
set(HDF5_LIBRARIES hdf5_cpp-static)
|
||||
elseif(TARGET hdf5_cpp-shared)
|
||||
set(HDF5_LIBRARIES hdf5_cpp-shared)
|
||||
elseif(TARGET hdf5::hdf5_cpp-shared)
|
||||
set(HDF5_LIBRARIES hdf5::hdf5_cpp-shared)
|
||||
else()
|
||||
find_package(HDF5 REQUIRED COMPONENTS CXX)
|
||||
endif()
|
||||
else()
|
||||
# If it failed, still try to find as a module.
|
||||
# E.g. on Ubuntu `libhdf5-dev` doesn't provie hdf5-config.cmake.
|
||||
# Will automatically fill HDF5_LIBRARIES and HDF5_INCLUDE_DIR.
|
||||
find_package(HDF5 COMPONENTS CXX)
|
||||
if(NOT HDF5_INCLUDE_DIR)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"HDF5_INCLUDE_DIR is not provided (current value: '${HDF5_INCLUDE_DIR}'). "
|
||||
"HDF5_LIBRARY_DIR is not provided (current value: '${HDF5_LIBRARY_DIR}'). "
|
||||
"Also could not find HDF5 package (neither module or config)."
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Restore module path.
|
||||
list(PREPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR})
|
||||
@@ -1,131 +0,0 @@
|
||||
# This file was generated with the assistance of an AI coding tool.
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/utilities.cmake" OPTIONAL)
|
||||
|
||||
set(_IfcOpenShell_find_args)
|
||||
if(IfcOpenShell_FIND_VERSION)
|
||||
list(APPEND _IfcOpenShell_find_args "${IfcOpenShell_FIND_VERSION}")
|
||||
if(IfcOpenShell_FIND_VERSION_EXACT)
|
||||
list(APPEND _IfcOpenShell_find_args EXACT)
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND _IfcOpenShell_find_args CONFIG QUIET)
|
||||
if(IfcOpenShell_FIND_COMPONENTS)
|
||||
list(APPEND _IfcOpenShell_find_args COMPONENTS ${IfcOpenShell_FIND_COMPONENTS})
|
||||
endif()
|
||||
|
||||
set(_IfcOpenShell_saved_module_path "${CMAKE_MODULE_PATH}")
|
||||
list(REMOVE_ITEM CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
|
||||
find_package(IfcOpenShell ${_IfcOpenShell_find_args})
|
||||
set(CMAKE_MODULE_PATH "${_IfcOpenShell_saved_module_path}")
|
||||
|
||||
if(NOT IfcOpenShell_FOUND)
|
||||
set(_IfcOpenShell_error "Could not find an IfcOpenShell CMake config package. Set IfcOpenShell_DIR or CMAKE_PREFIX_PATH.")
|
||||
if(IfcOpenShell_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "${_IfcOpenShell_error}")
|
||||
elseif(NOT IfcOpenShell_FIND_QUIETLY)
|
||||
message(STATUS "${_IfcOpenShell_error}")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(_IfcOpenShell_required_targets IfcOpenShell::IfcParse IfcOpenShell::IfcGeom)
|
||||
set(_IfcOpenShell_missing_targets "")
|
||||
foreach(_IfcOpenShell_target IN LISTS _IfcOpenShell_required_targets)
|
||||
if(NOT TARGET ${_IfcOpenShell_target})
|
||||
list(APPEND _IfcOpenShell_missing_targets ${_IfcOpenShell_target})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(_IfcOpenShell_missing_targets)
|
||||
set(IfcOpenShell_FOUND FALSE)
|
||||
string(REPLACE ";" ", " _IfcOpenShell_missing_targets_text "${_IfcOpenShell_missing_targets}")
|
||||
set(_IfcOpenShell_error "IfcOpenShell config was found, but required targets are missing: ${_IfcOpenShell_missing_targets_text}.")
|
||||
if(IfcOpenShell_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "${_IfcOpenShell_error}")
|
||||
elseif(NOT IfcOpenShell_FIND_QUIETLY)
|
||||
message(STATUS "${_IfcOpenShell_error}")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED IFCOPENSHELL_WITH_OPENCASCADE)
|
||||
set(IFCOPENSHELL_WITH_OPENCASCADE OFF)
|
||||
if(TARGET IfcOpenShell::geometry_kernel_opencascade)
|
||||
set(IFCOPENSHELL_WITH_OPENCASCADE ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED IFCOPENSHELL_WITH_CGAL)
|
||||
set(IFCOPENSHELL_WITH_CGAL OFF)
|
||||
if(TARGET IfcOpenShell::IFCOPENSHELL_CGAL)
|
||||
set(IFCOPENSHELL_WITH_CGAL ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED IFCOPENSHELL_IFCXML)
|
||||
set(IFCOPENSHELL_IFCXML OFF)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED IFCOPENSHELL_WITH_ROCKSDB)
|
||||
set(IFCOPENSHELL_WITH_ROCKSDB OFF)
|
||||
endif()
|
||||
|
||||
set(IFCOPENSHELL_LIBRARIES IfcOpenShell::IfcParse)
|
||||
foreach(_IfcOpenShell_target IN ITEMS IfcOpenShell::geometry_serializer IfcOpenShell::Serializers)
|
||||
if(TARGET ${_IfcOpenShell_target})
|
||||
list(APPEND IFCOPENSHELL_LIBRARIES ${_IfcOpenShell_target})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(IFCOPENSHELL_KERNEL_LIBRARIES "")
|
||||
foreach(_IfcOpenShell_target IN ITEMS
|
||||
IfcOpenShell::geometry_kernel_opencascade
|
||||
IfcOpenShell::geometry_kernel_cgal
|
||||
IfcOpenShell::geometry_kernel_cgal_simple
|
||||
)
|
||||
if(TARGET ${_IfcOpenShell_target})
|
||||
list(APPEND IFCOPENSHELL_KERNEL_LIBRARIES ${_IfcOpenShell_target})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(IFCOPENSHELL_GEOMETRY_LIBRARIES IfcOpenShell::IfcGeom ${IFCOPENSHELL_KERNEL_LIBRARIES})
|
||||
|
||||
if(TARGET IfcOpenShell::OpenCASCADE_INTERFACE)
|
||||
set(OpenCASCADE_LIBRARIES IfcOpenShell::OpenCASCADE_INTERFACE)
|
||||
endif()
|
||||
|
||||
if(TARGET IfcOpenShell::IFCOPENSHELL_CGAL)
|
||||
set(CGAL_LIBRARIES IfcOpenShell::IFCOPENSHELL_CGAL)
|
||||
endif()
|
||||
|
||||
if(TARGET IfcOpenShell::svgfill)
|
||||
set(IFCOPENSHELL_SVGFILL_LIBRARY IfcOpenShell::svgfill)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(IfcOpenShell_DIR)
|
||||
|
||||
unset(_IfcOpenShell_error)
|
||||
unset(_IfcOpenShell_find_args)
|
||||
unset(_IfcOpenShell_missing_targets)
|
||||
unset(_IfcOpenShell_missing_targets_text)
|
||||
unset(_IfcOpenShell_required_targets)
|
||||
unset(_IfcOpenShell_target)
|
||||
@@ -139,7 +139,8 @@ if(NOT OpenCOLLADA_DIR)
|
||||
endif()
|
||||
endif(NOT OpenCOLLADA_DIR)
|
||||
|
||||
if(OPENCOLLADA_FOUND)
|
||||
add_definitions(-DWITH_OPENCOLLADA)
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_OPENCOLLADA)
|
||||
if(OPENCOLLADA_FOUND AND NOT TARGET OpenCOLLADA::OpenCOLLADA)
|
||||
add_library(OpenCOLLADA::OpenCOLLADA INTERFACE IMPORTED)
|
||||
target_include_directories(OpenCOLLADA::OpenCOLLADA INTERFACE ${OPENCOLLADA_INCLUDE_DIRS})
|
||||
target_link_libraries(OpenCOLLADA::OpenCOLLADA INTERFACE ${OPENCOLLADA_LIBRARIES})
|
||||
endif()
|
||||
|
||||
+12
-6
@@ -6,7 +6,7 @@
|
||||
# Input variables could also be provided as environment variables.
|
||||
#
|
||||
# Output targets:
|
||||
# - `PROJ::proj`
|
||||
# - `proj::proj`
|
||||
#
|
||||
|
||||
# To avoid cyclic calls to this file
|
||||
@@ -34,10 +34,12 @@ if((NOT PROJ_INCLUDE_DIR AND NOT PROJ_LIBRARIES))
|
||||
message(FATAL_ERROR "Unable to find PROJ libraries in: ${PROJ_LIBRARY_DIR}")
|
||||
endif()
|
||||
|
||||
add_library(PROJ::proj INTERFACE IMPORTED)
|
||||
target_include_directories(PROJ::proj INTERFACE "${PROJ_INCLUDE_DIR}")
|
||||
target_link_libraries(PROJ::proj INTERFACE ${PROJ_LIBRARIES})
|
||||
target_link_directories(PROJ::proj INTERFACE "${PROJ_LIBRARY}")
|
||||
if(NOT TARGET proj::proj)
|
||||
add_library(proj::proj INTERFACE IMPORTED)
|
||||
target_include_directories(proj::proj INTERFACE "${PROJ_INCLUDE_DIR}")
|
||||
target_link_libraries(proj::proj INTERFACE ${PROJ_LIBRARIES})
|
||||
target_link_directories(proj::proj INTERFACE "${PROJ_LIBRARY}")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
find_library(PROJ_LIBRARY NAMES proj PATHS ${PROJ_LIBRARY_DIR})
|
||||
@@ -50,7 +52,11 @@ else()
|
||||
|
||||
set(PROJ_INCLUDE_DIR ${PROJ_INCLUDE_DIR} CACHE FILEPATH "PROJ header files")
|
||||
message(STATUS "Looking for PROJ include files in: ${PROJ_INCLUDE_DIR}")
|
||||
include_directories(${PROJ_INCLUDE_DIR})
|
||||
if(NOT TARGET proj::proj)
|
||||
add_library(proj::proj INTERFACE IMPORTED)
|
||||
target_include_directories(proj::proj INTERFACE "${PROJ_INCLUDE_DIR}")
|
||||
target_link_libraries(proj::proj INTERFACE ${PROJ_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(PREPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR})
|
||||
|
||||
@@ -64,7 +64,6 @@ set(USD_LIBRARIES
|
||||
find_library(USD_LIBRARY NAMES ${USD_LIBRARIES} PATHS ${USD_LIBRARY_DIR})
|
||||
if(USD_LIBRARY)
|
||||
message(STATUS "USD libraries ${USD_LIBRARIES} found in: ${USD_LIBRARY_DIR}")
|
||||
link_directories(${USD_LIBRARY_DIR})
|
||||
else()
|
||||
message(FATAL_ERROR "Unable to find USD libraries in: ${USD_LIBRARY_DIR}")
|
||||
endif()
|
||||
@@ -82,5 +81,3 @@ if(MSVC)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(pxr::USD INTERFACE PXR_STATIC WITH_USD)
|
||||
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_USD)
|
||||
|
||||
@@ -7,26 +7,12 @@ set(IFCOPENSHELL_WITH_OPENCASCADE @WITH_OPENCASCADE@)
|
||||
set(IFCOPENSHELL_WITH_CGAL @WITH_CGAL@)
|
||||
set(IFCOPENSHELL_IFCXML @IFCXML_SUPPORT@)
|
||||
set(IFCOPENSHELL_WITH_ROCKSDB @WITH_ROCKSDB@)
|
||||
set(IFCOPENSHELL_COLLADA_SUPPORT @COLLADA_SUPPORT@)
|
||||
set(IFCOPENSHELL_GLTF_SUPPORT @GLTF_SUPPORT@)
|
||||
set(IFCOPENSHELL_HDF5_SUPPORT @HDF5_SUPPORT@)
|
||||
set(IFCOPENSHELL_WITH_PROJ @WITH_PROJ@)
|
||||
set(IFCOPENSHELL_USD_SUPPORT @USD_SUPPORT@)
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
set(IFCOPENSHELL_BOOST_USE_STATIC_LIBS "@Boost_USE_STATIC_LIBS@")
|
||||
set(IFCOPENSHELL_BOOST_USE_STATIC_RUNTIME "@Boost_USE_STATIC_RUNTIME@")
|
||||
set(IFCOPENSHELL_BOOST_USE_MULTITHREADED "@Boost_USE_MULTITHREADED@")
|
||||
if(NOT "${IFCOPENSHELL_BOOST_USE_STATIC_LIBS}" STREQUAL "")
|
||||
set(Boost_USE_STATIC_LIBS ${IFCOPENSHELL_BOOST_USE_STATIC_LIBS})
|
||||
endif()
|
||||
if(NOT "${IFCOPENSHELL_BOOST_USE_STATIC_RUNTIME}" STREQUAL "")
|
||||
set(Boost_USE_STATIC_RUNTIME ${IFCOPENSHELL_BOOST_USE_STATIC_RUNTIME})
|
||||
endif()
|
||||
if(NOT "${IFCOPENSHELL_BOOST_USE_MULTITHREADED}" STREQUAL "")
|
||||
set(Boost_USE_MULTITHREADED ${IFCOPENSHELL_BOOST_USE_MULTITHREADED})
|
||||
endif()
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_STATIC_RUNTIME OFF)
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
set(Boost_COMPONENTS
|
||||
system
|
||||
program_options
|
||||
@@ -57,33 +43,13 @@ if(IFCOPENSHELL_WITH_ROCKSDB)
|
||||
endif()
|
||||
|
||||
if(IFCOPENSHELL_IFCXML)
|
||||
find_dependency(LibXml2)
|
||||
find_dependency(LibXml2 CONFIG)
|
||||
endif()
|
||||
|
||||
if(IFCOPENSHELL_WITH_CGAL)
|
||||
find_dependency(CGAL CONFIG)
|
||||
endif()
|
||||
|
||||
if(IFCOPENSHELL_COLLADA_SUPPORT)
|
||||
find_dependency(OpenCOLLADA)
|
||||
endif()
|
||||
|
||||
if(IFCOPENSHELL_GLTF_SUPPORT)
|
||||
find_dependency(nlohmann_json CONFIG)
|
||||
endif()
|
||||
|
||||
if(IFCOPENSHELL_HDF5_SUPPORT)
|
||||
find_dependency(HDF5 COMPONENTS C CXX)
|
||||
endif()
|
||||
|
||||
if(IFCOPENSHELL_WITH_PROJ)
|
||||
find_dependency(PROJ)
|
||||
endif()
|
||||
|
||||
if(IFCOPENSHELL_USD_SUPPORT)
|
||||
find_dependency(USD)
|
||||
endif()
|
||||
|
||||
if(IFCOPENSHELL_WITH_OPENCASCADE)
|
||||
find_dependency(OpenCASCADE CONFIG)
|
||||
if(OpenCASCADE_VERSION VERSION_LESS "7.7.0")
|
||||
|
||||
@@ -41,6 +41,108 @@ macro(SET_INSTALL_RPATHS _target _paths)
|
||||
set_target_properties(${_target} PROPERTIES INSTALL_RPATH "${${_target}_rpaths}")
|
||||
endmacro()
|
||||
|
||||
function(ifcopenshell_plugin_target TARGET)
|
||||
set_target_properties(${TARGET} PROPERTIES PREFIX "")
|
||||
endfunction()
|
||||
|
||||
function(ifcopenshell_wasm_plugin_link_options TARGET REGISTRATION_SYMBOL)
|
||||
ifcopenshell_plugin_target(${TARGET})
|
||||
|
||||
if(NOT WASM_BUILD)
|
||||
return()
|
||||
endif()
|
||||
|
||||
cmake_parse_arguments(PLUGIN "" "OPTIMIZATION" "" ${ARGN})
|
||||
if(NOT PLUGIN_OPTIMIZATION)
|
||||
set(PLUGIN_OPTIMIZATION -O1)
|
||||
endif()
|
||||
|
||||
set(plugin_symbols
|
||||
ifcopenshell_plugin_abi_v1
|
||||
ifcopenshell_plugin_metadata_v1
|
||||
${REGISTRATION_SYMBOL}
|
||||
)
|
||||
|
||||
target_link_options(${TARGET} PRIVATE "SHELL:-s SIDE_MODULE=2" ${PLUGIN_OPTIMIZATION})
|
||||
foreach(symbol IN LISTS plugin_symbols)
|
||||
target_link_options(${TARGET} PRIVATE "LINKER:--export=${symbol}")
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
function(ifcopenshell_deploy_qt_runtime TARGET)
|
||||
if(NOT IFCOPENSHELL_DEPLOY_QT_RUNTIME)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET ${TARGET})
|
||||
message(FATAL_ERROR "Cannot deploy Qt runtime for unknown target '${TARGET}'.")
|
||||
endif()
|
||||
|
||||
get_target_property(target_type ${TARGET} TYPE)
|
||||
if(NOT target_type STREQUAL "EXECUTABLE")
|
||||
message(FATAL_ERROR "Qt runtime deployment target '${TARGET}' is not an executable.")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED QT_DEFAULT_MAJOR_VERSION)
|
||||
if(DEFINED QT_VERSION)
|
||||
set(QT_DEFAULT_MAJOR_VERSION ${QT_VERSION})
|
||||
else()
|
||||
set(QT_DEFAULT_MAJOR_VERSION 6)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET Qt${QT_DEFAULT_MAJOR_VERSION}::Core)
|
||||
set(qt_find_args Qt${QT_DEFAULT_MAJOR_VERSION} COMPONENTS Core REQUIRED)
|
||||
if(DEFINED QT_DIR AND NOT QT_DIR STREQUAL "")
|
||||
list(APPEND qt_find_args PATHS ${QT_DIR})
|
||||
endif()
|
||||
find_package(${qt_find_args})
|
||||
endif()
|
||||
|
||||
if(COMMAND _qt_internal_setup_deploy_support)
|
||||
if(NOT DEFINED QT_CMAKE_EXPORT_NAMESPACE AND TARGET Qt${QT_DEFAULT_MAJOR_VERSION}::Core)
|
||||
set(QT_CMAKE_EXPORT_NAMESPACE Qt${QT_DEFAULT_MAJOR_VERSION})
|
||||
endif()
|
||||
|
||||
if(QT_DEFAULT_MAJOR_VERSION EQUAL 6 AND TARGET Qt6::Core)
|
||||
get_target_property(qt_core_type Qt6::Core TYPE)
|
||||
if(qt_core_type STREQUAL "SHARED_LIBRARY")
|
||||
set(QT6_IS_SHARED_LIBS_BUILD ON)
|
||||
else()
|
||||
set(QT6_IS_SHARED_LIBS_BUILD OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
_qt_internal_setup_deploy_support()
|
||||
endif()
|
||||
|
||||
set(deploy_args
|
||||
TARGET ${TARGET}
|
||||
OUTPUT_SCRIPT deploy_script
|
||||
NO_UNSUPPORTED_PLATFORM_ERROR
|
||||
)
|
||||
|
||||
if(NOT IFCOPENSHELL_DEPLOY_QT_TRANSLATIONS)
|
||||
list(APPEND deploy_args NO_TRANSLATIONS)
|
||||
endif()
|
||||
|
||||
list(APPEND deploy_args ${ARGN})
|
||||
|
||||
if(COMMAND qt_generate_deploy_app_script)
|
||||
qt_generate_deploy_app_script(${deploy_args})
|
||||
elseif(COMMAND qt6_generate_deploy_app_script)
|
||||
qt6_generate_deploy_app_script(${deploy_args})
|
||||
else()
|
||||
message(WARNING
|
||||
"Qt runtime deployment requested for '${TARGET}', but this Qt version "
|
||||
"does not provide qt_generate_deploy_app_script()."
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
|
||||
install(SCRIPT ${deploy_script})
|
||||
endfunction()
|
||||
|
||||
# Get a list of all OPTION flags from the CMakeLists.txt and store in an output LIST
|
||||
function(get_all_option_flags output_list)
|
||||
# Read the contents of the CMakeLists.txt
|
||||
|
||||
@@ -22,9 +22,6 @@ cmake -G "Ninja" ^
|
||||
-D GMP_LIBRARY_DIR:FILEPATH="%LIBRARY_PREFIX%\lib" ^
|
||||
-D MPFR_LIBRARY_DIR:FILEPATH="%LIBRARY_PREFIX%\lib" ^
|
||||
-D COLLADA_SUPPORT=OFF ^
|
||||
-D HDF5_SUPPORT=ON ^
|
||||
-D HDF5_INCLUDE_DIR="%LIBRARY_PREFIX%\include" ^
|
||||
-D HDF5_LIBRARY_DIR="%LIBRARY_PREFIX%\lib" ^
|
||||
-D JSON_INCLUDE_DIR="%LIBRARY_PREFIX%\include" ^
|
||||
-D PYTHON_INCLUDE_DIR=%PREFIX%\include ^
|
||||
-D PYTHON_EXECUTABLE:FILEPATH=%PREFIX%\python.exe ^
|
||||
@@ -37,7 +34,6 @@ cmake -G "Ninja" ^
|
||||
-D GLTF_SUPPORT:BOOL=ON ^
|
||||
-D BUILD_CONVERT:BOOL=ON ^
|
||||
-D BUILD_IFCMAX:BOOL=OFF ^
|
||||
-D IFCXML_SUPPORT:BOOL=ON ^
|
||||
-D Boost_LIBRARY_DIR:FILEPATH="%LIBRARY_PREFIX%\lib" ^
|
||||
-D Boost_INCLUDE_DIR:FILEPATH="%LIBRARY_PREFIX%\include" ^
|
||||
-D Boost_USE_STATIC_LIBS:BOOL=OFF ^
|
||||
|
||||
+1
-5
@@ -24,9 +24,6 @@ cmake ${CMAKE_ARGS} -G Ninja \
|
||||
-DMPFR_LIBRARY_DIR=$PREFIX/lib \
|
||||
-DOCC_INCLUDE_DIR=$PREFIX/include/opencascade \
|
||||
-DOCC_LIBRARY_DIR=$PREFIX/lib \
|
||||
-DHDF5_SUPPORT:BOOL=ON \
|
||||
-DHDF5_INCLUDE_DIR=$PREFIX/include \
|
||||
-DHDF5_LIBRARY_DIR=$PREFIX/lib \
|
||||
-DJSON_INCLUDE_DIR=$PREFIX/include \
|
||||
-DCGAL_INCLUDE_DIR=$PREFIX/include \
|
||||
-DLIBXML2_INCLUDE_DIR=$PREFIX/include/libxml2 \
|
||||
@@ -34,7 +31,6 @@ cmake ${CMAKE_ARGS} -G Ninja \
|
||||
-DEIGEN_DIR:FILEPATH=$PREFIX/include/eigen3 \
|
||||
-DCOLLADA_SUPPORT:BOOL=OFF \
|
||||
-DBUILD_EXAMPLES:BOOL=OFF \
|
||||
-DIFCXML_SUPPORT:BOOL=ON \
|
||||
-DGLTF_SUPPORT:BOOL=ON \
|
||||
-DBUILD_CONVERT:BOOL=ON \
|
||||
-DBUILD_IFCPYTHON:BOOL=ON \
|
||||
@@ -47,4 +43,4 @@ ninja
|
||||
|
||||
ninja install -j 1
|
||||
|
||||
python "${RECIPE_DIR}/update_version_init.py" "${PKG_VERSION}" "${SP_DIR}/ifcopenshell/__init__.py"
|
||||
python "${RECIPE_DIR}/update_version_init.py" "${PKG_VERSION}" "${SP_DIR}/ifcopenshell/__init__.py"
|
||||
|
||||
@@ -26,8 +26,6 @@ c_stdlib_version:
|
||||
- 2.17 # [linux]
|
||||
- 10.13 # [osx and x86_64]
|
||||
- 11.0 # [osx and arm64]
|
||||
hdf5:
|
||||
- 1.14.6
|
||||
libboost_devel:
|
||||
- '1.86'
|
||||
libxml2:
|
||||
|
||||
@@ -33,7 +33,6 @@ requirements:
|
||||
- occt
|
||||
- libxml2
|
||||
- cgal-cpp
|
||||
- hdf5
|
||||
- eigen
|
||||
- mpfr
|
||||
- nlohmann_json
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
.env
|
||||
*.pyc
|
||||
__pycache__
|
||||
@@ -1,3 +0,0 @@
|
||||
.env
|
||||
*.pyc
|
||||
__pycache__
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# .ifcos_env
|
||||
# register autocompletes. just source the file in your shell, i.e.
|
||||
# source .ifcos_env
|
||||
|
||||
.ifcos_env() {
|
||||
local cur prev opts
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
|
||||
opts="create update up down restart build attach logs ps config remove help"
|
||||
|
||||
# Basic static completion
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Register the completion for the command "ifcos_env"
|
||||
complete -F .ifcos_env ./ifcos_env
|
||||
@@ -1,67 +0,0 @@
|
||||
FROM rockylinux:9
|
||||
|
||||
# Update system, enable CRB (needed by some EPEL packages) and install EPEL,
|
||||
# then install required packages + some common tools for a bit of command
|
||||
# line comfort. Combined into one layer so a later `create` always installs
|
||||
# against packages from the same dnf update, rather than layering fresh
|
||||
# installs on top of a stale cached "update" layer.
|
||||
RUN dnf update -y && \
|
||||
dnf install -y epel-release && \
|
||||
dnf config-manager --set-enabled crb && \
|
||||
dnf install -y --allowerasing --setopt=install_weak_deps=False --setopt=tsflags=nodocs \
|
||||
bash-completion vim git curl wget which tree htop sudo \
|
||||
gcc gcc-c++ 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 libuuid-devel git-lfs \
|
||||
findutils xz byacc ccache && \
|
||||
git lfs install --system && \
|
||||
dnf clean all && \
|
||||
rm -rf /var/cache/dnf
|
||||
|
||||
# Trust bind-mounted repos regardless of which user (root or builder) or host
|
||||
# UID owns them, rather than a per-user config that only one of them sees.
|
||||
RUN git config --system --add safe.directory '*'
|
||||
|
||||
# Configure ccache. CCACHE_MAXSIZE (not `ccache -M`) because /ccache is a
|
||||
# volume mount point at runtime - anything `ccache -M` writes to a config
|
||||
# file under it during this build gets shadowed once the real volume is
|
||||
# mounted, so the size cap only actually takes effect via the env var.
|
||||
# 2G is generous: a full build (IfcParse+IfcGeom+IfcConvert+wrapper, one
|
||||
# Python version) measures ~300MB, and the volume is now shared across all
|
||||
# checkouts (see compose.yaml), so this covers several diverging branches.
|
||||
ENV CCACHE_DIR=/ccache
|
||||
ENV CCACHE_MAXSIZE=2G
|
||||
ENV PATH="/usr/lib/ccache:$PATH"
|
||||
|
||||
# Non-root user matching the host UID/GID that bind-mounts the repo (default
|
||||
# 1000:1000, the common single-user-Linux-box case), so files the build
|
||||
# creates under the mount keep sane, non-root ownership on the host side.
|
||||
# Override with --build-arg USER_UID=$(id -u) --build-arg USER_GID=$(id -g)
|
||||
# if your host user has a different UID/GID.
|
||||
ARG USER_UID=1000
|
||||
ARG USER_GID=1000
|
||||
# groupadd fails outright if USER_GID is already taken by an existing
|
||||
# system group - which happens whenever a host's primary GID collides with
|
||||
# one baked into the rockylinux9 base image. The main real-world case is
|
||||
# macOS, where the default user's primary group is "staff" at GID 20, and
|
||||
# GID 20 is "games" on RHEL-family images. Only create the "builder" group
|
||||
# when that GID is actually free; otherwise useradd just attaches to
|
||||
# whichever group already owns it. Either way the builder user ends up
|
||||
# with the right GID for bind-mount ownership, which is all that matters.
|
||||
RUN (getent group "${USER_GID}" >/dev/null || groupadd -g "${USER_GID}" builder) \
|
||||
&& useradd -m -u "${USER_UID}" -g "${USER_GID}" -s /bin/bash builder \
|
||||
&& echo "builder ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/builder
|
||||
|
||||
# Copied while still root: /bin is not writable by the builder user.
|
||||
COPY --from=ghcr.io/astral-sh/uv:0.11.27 /uv /uvx /bin/
|
||||
|
||||
USER builder
|
||||
WORKDIR /__w/IfcOpenShell/IfcOpenShell
|
||||
|
||||
# Installed as builder so managed Python interpreters land under builder's
|
||||
# $HOME, matching the user that actually runs the build.
|
||||
RUN uv python install
|
||||
|
||||
CMD ["sleep", "infinity"]
|
||||
@@ -1,78 +0,0 @@
|
||||
Docker build environment
|
||||
========================
|
||||
|
||||
This is a small utility to make it easy to compile a perfect `_ifcopenshell_wrapper.cpython-*-x86_64-linux-gnu.so`
|
||||
files.
|
||||
|
||||
The reason for this tool is that I was trying to follow the web page directions, and my build was behaving differently
|
||||
to the release builds. Eventually I concluded that the differences between toolchains on the RHEL based rocky9 image
|
||||
and Ubuntu were just too great. Getting the build setup was already a lot of trial and error, so I thought I'd spend
|
||||
more time trying to reuse the github actions that perform the build, using a utility called `act`. I learnt a lot, in
|
||||
particular how much time, energy, and bandwidth Github waste. I also realised I was most of the way to a regular docker
|
||||
setup anyway, so I might as well just do that. So I've deconstructed all the github action steps, and turned it into
|
||||
a local docker build environment that uses the exact same base, tools, libraries, and build command/flags etc.
|
||||
|
||||
Right now a Github action will:
|
||||
- launch the rocky9 base
|
||||
- upgrade all the packages
|
||||
- install a bunch of extra tools
|
||||
- do a recursive checkout of your repo
|
||||
- checkout the build repository
|
||||
- unpack dependencies
|
||||
- run the build script, making all python versions (5? right now I think)
|
||||
- create the .zip release files
|
||||
|
||||
And it does _all_ of that _every_ time. This is not a fault of the action writers - it's just how Github seems to work.
|
||||
|
||||
These dockers tools do the following differently, and it's actually a bit more powerful too:
|
||||
- build the base image once.
|
||||
- update the packages once.
|
||||
- install the extra tools once.
|
||||
- the repository is the one on your host, that gets bind mounted in the container as the working directory.
|
||||
- by adding an environment variable to .env, restricts to compiling for just a single python version.
|
||||
- when the build is finished the created files are right there under your local repositry (but not added to git) for
|
||||
ease of access
|
||||
- each repository can have it's own build environment container.
|
||||
- the image is shared between those environments.
|
||||
- the containers share the ccache, so additional envs should get a helping hand.
|
||||
- it has a simple set of user friendly commands to drive it all.
|
||||
|
||||
For example:
|
||||
``` bash
|
||||
# To see the commands (a superset of docker compose commands)
|
||||
./ifcos_env
|
||||
|
||||
# Enable autocomplete of commands
|
||||
source .ifcos_env
|
||||
|
||||
# First time commands
|
||||
./ifcos_env create
|
||||
./ifcos_env up
|
||||
./ifcos_env build
|
||||
|
||||
# install and test library
|
||||
# find an issue
|
||||
# edit code
|
||||
./ifcos_env build
|
||||
|
||||
# and so on. When done stop and optionally delete the container
|
||||
./ifcos_env stop
|
||||
./ifcos_env remove
|
||||
```
|
||||
|
||||
To limit the build to one python version just add
|
||||
``` bash
|
||||
PY_TGT=py-311
|
||||
```
|
||||
or whichever version your Blender requires.
|
||||
|
||||
You might see UNIQUE_ID in the .env file too. This keeps containers for separate folders, separate.
|
||||
|
||||
System requirements
|
||||
1. Linux-x64 only at this time.
|
||||
2. Docker and docker-compose need to be installed.
|
||||
3. Have a good amount of disk space. (image is in /var (typically the root partition) and will be about 1.7 GB)
|
||||
4. The build action will create about 10GB in your repository folder. Make sure this partition is spacious
|
||||
particularly if you intent on having multiple clones building.
|
||||
5. ... I think that covers most of it.
|
||||
|
||||
-186
@@ -1,186 +0,0 @@
|
||||
---
|
||||
name: ifcopenshell-docker-build
|
||||
description: >-
|
||||
Build a real ifcopenshell_wrapper (.so + .py) and IfcConvert locally via
|
||||
the docker/ifcos_env toolchain, then wire them into a checkout for
|
||||
running C++-dependent parts of the test suite (geometry, the SWIG
|
||||
wrapper stub, the C++ parser). Use whenever a task needs to compile
|
||||
IfcOpenShell's C++ core rather than just read/patch source - e.g.
|
||||
reproducing or fixing a bug in src/ifcgeom, src/ifcparse, src/ifcwrap,
|
||||
or validating util/scripts/validate_stub.py against the actual
|
||||
generated wrapper.
|
||||
---
|
||||
|
||||
# Building IfcOpenShell locally with docker/ifcos_env
|
||||
|
||||
`docker/` mirrors the project's GitHub Actions build environment locally,
|
||||
in a persistent, non-root container with ccache so repeat builds are fast.
|
||||
See `docker/README.md` for the design rationale. Pure-Python changes don't
|
||||
need any of this - only reach for it when you need a real compiled
|
||||
`_ifcopenshell_wrapper*.so` or `IfcConvert` binary.
|
||||
|
||||
## Placement
|
||||
|
||||
This `docker/` folder must live as a direct child of the repo root you want
|
||||
to build (sibling of `src/`, `cmake/`, etc.) - `compose.yaml` and
|
||||
`ifcos_env` resolve the repo via `../` relative to wherever `docker/`
|
||||
itself sits, and bind-mount it into the container. If you're setting this
|
||||
up in a fresh clone, copy the whole `docker/` directory there first.
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
cd docker
|
||||
./ifcos_env create # build the image (shared by name across all your clones/checkouts, so usually instant after the first time anywhere)
|
||||
./ifcos_env up # create + start the container, clone/unpack the third-party dependency cache (~10GB, one-time per container)
|
||||
./ifcos_env build # full build: all deps + IfcParse + IfcGeom + IfcConvert + the Python wrapper, for one Python version
|
||||
```
|
||||
|
||||
`PY_TGT` and `UNIQUE_ID` live in `docker/.env` - `PY_TGT` (e.g. `py-311`)
|
||||
restricts the build to one Python version instead of building five;
|
||||
`UNIQUE_ID` is a hash of the folder path, recalculated on every `up`, so
|
||||
each checkout gets its own container/volumes automatically.
|
||||
|
||||
A full first build takes ~1.5 hours (mostly compiling IfcOpenShell's own
|
||||
C++, not the cached third-party deps). After that, ccache makes incremental
|
||||
rebuilds of a couple of touched `.cpp` files **under a minute**.
|
||||
|
||||
## Container lifecycle
|
||||
|
||||
The container is long-lived (`sleep infinity`) so exec'd commands and
|
||||
ccache state persist between builds. Commands map directly onto Docker
|
||||
Compose's own container-vs-image distinction:
|
||||
|
||||
```bash
|
||||
./ifcos_env up # create the container if it doesn't exist, then start it (runs ready_repo too)
|
||||
./ifcos_env stop # stop the container, keep it around
|
||||
./ifcos_env start # start it back up (same container, same filesystem layer)
|
||||
./ifcos_env restart # stop, then start
|
||||
./ifcos_env down # remove the container (and its network) entirely
|
||||
./ifcos_env recreate # down, then up - a fresh container
|
||||
```
|
||||
|
||||
Named volumes (`ccache`) and the bind-mounted repo/`build/` are unaffected
|
||||
by `down`/`recreate` - only the container itself goes away, and `up`
|
||||
recreates it from the image.
|
||||
|
||||
## Fast iteration
|
||||
|
||||
Pass a target to `build` to skip the parts you don't need:
|
||||
|
||||
```bash
|
||||
./ifcos_env build IfcConvert # only the executables (IfcConvert, IfcGeomServer) - skips the Python wrapper entirely
|
||||
./ifcos_env build IfcOpenShell-Python # only the SWIG Python wrapper - skips executables entirely
|
||||
./ifcos_env build # no target = everything (needed the first time, or after touching shared headers)
|
||||
```
|
||||
|
||||
Use this to keep the edit -> rebuild -> test loop fast when debugging: if
|
||||
you're only touching `src/ifcgeom/`, build `IfcConvert`; if you're only
|
||||
exercising the Python API, build `IfcOpenShell-Python`.
|
||||
|
||||
## Where the artifacts land
|
||||
|
||||
Build output goes to `<repo_root>/build/Linux/x86_64/install/` on the host
|
||||
(bind-mounted, not just inside the container), owned by you (see
|
||||
"Container user" below):
|
||||
|
||||
- `ifcopenshell/bin/IfcConvert` - the CLI binary
|
||||
- `python-<version>/lib/python<X.Y>/site-packages/ifcopenshell/_ifcopenshell_wrapper*.so`
|
||||
and `ifcopenshell_wrapper.py` - the compiled wrapper + its generated
|
||||
Python glue
|
||||
|
||||
## Testing against a checkout (automated / AI-driven)
|
||||
|
||||
`_ifcopenshell_wrapper*.so` and `ifcopenshell_wrapper.py` are already
|
||||
gitignored under `src/ifcopenshell-python/ifcopenshell/`, which is exactly
|
||||
where a normal in-tree build would put them - copy the two files there:
|
||||
|
||||
```bash
|
||||
SRC=build/Linux/x86_64/install/python-3.11.8/lib/python3.11/site-packages/ifcopenshell
|
||||
cp "$SRC/_ifcopenshell_wrapper.cpython-311-x86_64-linux-gnu.so" src/ifcopenshell-python/ifcopenshell/
|
||||
cp "$SRC/ifcopenshell_wrapper.py" src/ifcopenshell-python/ifcopenshell/
|
||||
```
|
||||
|
||||
Then, to run the test suite against it:
|
||||
|
||||
```bash
|
||||
export PATH="$PWD/build/Linux/x86_64/install/ifcopenshell/bin:$PATH" # for IfcConvert-dependent tests
|
||||
cd src/ifcopenshell-python/test
|
||||
PYTHONPATH="$PWD/.." python3.11 -m pytest -p no:pytest-blender .
|
||||
```
|
||||
|
||||
(`-p no:pytest-blender` avoids the pytest-blender plugin trying to find a
|
||||
`blender` executable and failing collection entirely, even for non-Blender
|
||||
tests.) You'll need the matching Python version's `pip install`s too
|
||||
(numpy, shapely, isodate, lark, tabulate, pytest, ... - whatever the
|
||||
modules under test import) since this is a bare interpreter, not the
|
||||
project's pixi env.
|
||||
|
||||
**This is the pattern to use for automated or AI-driven verification.**
|
||||
Don't use `try` (below) for that - it overwrites files in a real, live
|
||||
Blender installation, which isn't something an automated/AI workflow
|
||||
should ever do without the human explicitly asking for it in the moment.
|
||||
|
||||
## Testing in Blender itself (human only)
|
||||
|
||||
`try` copies the built wrapper straight into your actual Blender/Bonsai
|
||||
extension install, for manual in-Blender testing:
|
||||
|
||||
```bash
|
||||
./ifcos_env try
|
||||
```
|
||||
|
||||
It reads `BLENDER_USER_RESOURCE` from `.env` - set this to wherever
|
||||
Blender's user resource folder for the Bonsai extension actually lives on
|
||||
your system, which depends on your own Blender setup:
|
||||
|
||||
```bash
|
||||
# in docker/.env
|
||||
BLENDER_USER_RESOURCE=~/.config/blender/bonsai/
|
||||
```
|
||||
|
||||
`try` figures out the built Python version from `build/.../install/`
|
||||
(disambiguating with `PY_TGT` if more than one version was built) and
|
||||
copies the wrapper to
|
||||
`$BLENDER_USER_RESOURCE/extensions/.local/lib/python<X.Y>/site-packages/ifcopenshell/`.
|
||||
|
||||
## Container user
|
||||
|
||||
The image runs as a non-root `builder` user, UID/GID matching your host
|
||||
account (passed as `--build-arg` by `create` from `id -u`/`id -g`, so it
|
||||
adjusts automatically - no manual flag needed even if you're not 1000:1000).
|
||||
Files the build creates under the bind mount come out owned by you, not
|
||||
root. Passwordless `sudo` is available inside the container (e.g. via
|
||||
`attach`) for the rare case you need root for something ad hoc.
|
||||
|
||||
If you're picking up an existing checkout that was previously built with
|
||||
an older, root-based image, you may hit `Permission denied` the first time
|
||||
you run `up`/`build` under the new image - `build/`, `.git/modules/`, the
|
||||
`ccache` volume, `output/`, and `build.log` can all be left root-owned from
|
||||
before. Fix it once via the container's own root (no host `sudo` needed):
|
||||
|
||||
```bash
|
||||
docker exec -u root -w /__w/IfcOpenShell/IfcOpenShell <container-name> \
|
||||
chown -R "$(id -u)":"$(id -g)" .git/modules build output build.log /ccache
|
||||
```
|
||||
|
||||
(`<container-name>` is `ifcopenshell-<UNIQUE_ID>` - see `docker ps -a`.)
|
||||
|
||||
## Other things worth knowing
|
||||
|
||||
- **Linux x64 only.** `compose.yaml` pins `platform: linux/amd64`; on an
|
||||
ARM host (e.g. Apple Silicon) this build isn't available.
|
||||
- **The final "Package .zip archives" step of `build()` has a pre-existing
|
||||
bash syntax error**, unrelated to compilation - the actual build already
|
||||
succeeded by that point (look for `Built IfcOpenShell...` in the output),
|
||||
so this is safe to ignore if you only need the raw artifacts under
|
||||
`build/.../install/`, not packaged release zips.
|
||||
- **`test_mmaped_stream` and similar `USE_MMAP`-dependent tests will fail**
|
||||
against this build - `nix/build-all.py` is invoked with `USE_MMAP=OFF`
|
||||
here. Not a bug in your code if you see it fail.
|
||||
- Only the bind-mounted `<repo>/build` lives on the host filesystem your
|
||||
repo is checked out on. Anything the container writes *outside* that
|
||||
mount lives in the container's own writable layer under Docker's data
|
||||
root (commonly `/var/lib/docker`, i.e. usually your root partition) -
|
||||
keep an eye on `df -h /` if you're running several of these containers
|
||||
at once.
|
||||
@@ -1,15 +0,0 @@
|
||||
name: ifcopenshell-${UNIQUE_ID}
|
||||
services:
|
||||
ifcopenshell:
|
||||
container_name: ifcopenshell-${UNIQUE_ID}
|
||||
image: ifcopenshell-build-env:updated
|
||||
platform: linux/amd64
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ../
|
||||
target: /__w/IfcOpenShell/IfcOpenShell
|
||||
- ccache:/ccache
|
||||
|
||||
volumes:
|
||||
ccache:
|
||||
name: ifcopenshell-ccache-shared
|
||||
@@ -1,339 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ================== CONFIG ==================
|
||||
SCRIPT_NAME=$(basename "$0")
|
||||
ENV_FILE=".env"
|
||||
WORKDIR="/__w/IfcOpenShell/IfcOpenShell"
|
||||
NAMEPREFIX=ifcopenshell
|
||||
|
||||
function set_env() {
|
||||
# Load .env file if it exists
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
set -a
|
||||
source "$ENV_FILE"
|
||||
set +a
|
||||
echo "✅ Loaded environment variables from $ENV_FILE"
|
||||
else
|
||||
echo "⚠️ No $ENV_FILE found, proceeding without it."
|
||||
fi
|
||||
}
|
||||
|
||||
set_env
|
||||
|
||||
# ================ FUNCTIONS =================
|
||||
|
||||
function create() {
|
||||
echo "⭐ Creating image: ifcopenshell-build-env"
|
||||
docker build -f Dockerfile \
|
||||
--build-arg USER_UID="$(id -u)" --build-arg USER_GID="$(id -g)" \
|
||||
-t ifcopenshell-build-env:updated .
|
||||
}
|
||||
|
||||
function update() {
|
||||
# The Dockerfile always builds FROM a clean rockylinux:9 and does
|
||||
# `dnf update -y` as its first step, so re-running create() is enough
|
||||
# to get fresh packages.
|
||||
echo "⚡ Updating image: ifcopenshell-build-env"
|
||||
create
|
||||
}
|
||||
|
||||
function up() {
|
||||
# Creates the container if it doesn't exist yet (and starts it either
|
||||
# way) - this is the one that needs ready_repo, since a freshly created
|
||||
# container has no submodules/dependency cache in place yet.
|
||||
echo "🚀 Creating/starting stack: ifcopenshell-${UNIQUE_ID}"
|
||||
unique # Update UNIQUE_ID first
|
||||
docker compose up -d "$@" # Container must exist before ready_repo can exec into it.
|
||||
ready_repo # Ensure repo is recursive, and the build repo is in place.
|
||||
}
|
||||
|
||||
function down() {
|
||||
# Removes the container (and its network) entirely. Named volumes
|
||||
# (ccache) and the bind-mounted repo/build/ survive; up() will recreate
|
||||
# the container from scratch next time.
|
||||
echo "🔥 Removing stack: ifcopenshell-${UNIQUE_ID}"
|
||||
docker compose down "$@"
|
||||
}
|
||||
|
||||
function stop() {
|
||||
# Stops the existing container without removing it - the container,
|
||||
# its filesystem layer, and its exec history all remain intact.
|
||||
echo "🛑 Stopping stack: ifcopenshell-${UNIQUE_ID}"
|
||||
docker compose stop "$@"
|
||||
}
|
||||
|
||||
function start() {
|
||||
# Starts a previously-stopped container back up. Does nothing (and
|
||||
# won't create anything) if the container doesn't exist - use up() for
|
||||
# that.
|
||||
echo "▶️ Starting stack: ifcopenshell-${UNIQUE_ID}"
|
||||
docker compose start "$@"
|
||||
}
|
||||
|
||||
function restart() {
|
||||
echo "🔄 Restarting stack (stop, then start)..."
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
function recreate() {
|
||||
echo "♻️ Recreating stack (down, then up)..."
|
||||
down
|
||||
up
|
||||
}
|
||||
|
||||
function logs() {
|
||||
echo "📜 Showing logs..."
|
||||
docker compose logs -f "$@"
|
||||
}
|
||||
|
||||
function ps() {
|
||||
docker compose ps
|
||||
}
|
||||
|
||||
function config() {
|
||||
echo "🔍 Validated compose configuration:"
|
||||
docker compose config
|
||||
}
|
||||
|
||||
function remove() {
|
||||
# Lower-level than down(): removes already-stopped containers without
|
||||
# touching the compose network. Mostly useful after a plain stop().
|
||||
echo "🗑️ Removing stopped containers: ifcopenshell-${UNIQUE_ID}"
|
||||
docker compose rm "$@"
|
||||
}
|
||||
|
||||
function unique() {
|
||||
echo "🔧 Making stack name folder specific..."
|
||||
|
||||
REGEX="^UNIQUE_ID="
|
||||
|
||||
if [[ ! -f "$ENV_FILE" ]] || ! grep -qE "$REGEX" "$ENV_FILE"; then
|
||||
echo -e "\nUNIQUE_ID=dummy\n" >> "$ENV_FILE"
|
||||
fi
|
||||
|
||||
export UNIQUE_ID="$(pwd | sha256sum | cut -c -8)"
|
||||
|
||||
# `sed -i` takes incompatible syntax between GNU sed (Linux) and BSD sed
|
||||
# (macOS) - `-si` is GNU-only and errors as "illegal option -- s" under
|
||||
# BSD/macOS sed. Avoid -i altogether and do the in-place edit via a temp
|
||||
# file + mv instead, which behaves identically with either sed.
|
||||
local tmp_file
|
||||
tmp_file="$(mktemp "${ENV_FILE}.XXXXXX")"
|
||||
sed "s/^UNIQUE_ID=.*$/UNIQUE_ID=${UNIQUE_ID}/" "$ENV_FILE" > "$tmp_file"
|
||||
mv "$tmp_file" "$ENV_FILE"
|
||||
|
||||
set_env
|
||||
}
|
||||
|
||||
function ready_repo() {
|
||||
echo "👍 Getting the repo ready to build..."
|
||||
docker exec -i -w "${WORKDIR}" "${NAMEPREFIX}-${UNIQUE_ID}" bash -c '
|
||||
set -euo pipefail # Recommended for robustness
|
||||
|
||||
git submodule update --init --recursive
|
||||
|
||||
if [[ ! -d "build" ]]; then
|
||||
git clone -b rockylinux9-x64 https://github.com/IfcOpenShell/build-outputs.git build
|
||||
else
|
||||
cd build
|
||||
git pull
|
||||
cd ..
|
||||
fi
|
||||
|
||||
if [[ ! -d "build/Linux/x86_64/install/boost-1.86.0/" ]]; then
|
||||
cd build
|
||||
uv run ../nix/cache_dependencies.py unpack
|
||||
cd ..
|
||||
fi
|
||||
'
|
||||
}
|
||||
|
||||
function build() {
|
||||
echo "☕ Execute the build, go make yourself a cuppa... I'll be a while"
|
||||
local BUILD_TARGET="$1"
|
||||
|
||||
docker exec -i -w "${WORKDIR}" -e PY_TGT="${PY_TGT}" -e BUILD_TARGET="${BUILD_TARGET}" "${NAMEPREFIX}-${UNIQUE_ID}" bash -c '
|
||||
set -o pipefail
|
||||
CXXFLAGS="-O3" CFLAGS="-O3 ${DARWIN_C_SOURCE}" ADD_COMMIT_SHA=1 BUILD_CFG=Release uv run ./nix/build-all.py -v ${PY_TGT:+-$PY_TGT} --diskcleanup ${BUILD_TARGET} 2>&1 | tee build.log
|
||||
'
|
||||
echo "🎒 Pack Dependencies"
|
||||
docker exec -i -w "${WORKDIR}" "${NAMEPREFIX}-${UNIQUE_ID}" bash -c '
|
||||
cd build
|
||||
uv run ../nix/cache_dependencies.py pack
|
||||
'
|
||||
|
||||
echo "🎁 Package .zip archives"
|
||||
docker exec -i -w "${WORKDIR}" -e GITHUB_SHA="$(git rev-parse HEAD)" "${NAMEPREFIX}-${UNIQUE_ID}" bash -c '
|
||||
OUTPUT_DIR=${PWD}/output
|
||||
VERSION=v`cat VERSION`
|
||||
mkdir -p ${OUTPUT_DIR}
|
||||
cd ./build/`uname`/*/install/ifcopenshell
|
||||
|
||||
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
|
||||
zip -r -qq ifcopenshell-${py_version_major}-${VERSION}-${GITHUB_SHA:0:7}-linux64.zip ifcopenshell/*
|
||||
mv *.zip ${OUTPUT_DIR}/
|
||||
popd > /dev/null
|
||||
done
|
||||
|
||||
cd bin
|
||||
if compgen -G "./*.zip" > /dev/null; then
|
||||
rm *.zip 2>&1 >/dev/null || true
|
||||
ls | while read exe; do
|
||||
zip -qq -r ${exe}-${VERSION}-${GITHUB_SHA:0:7}-linux64.zip $exe
|
||||
done
|
||||
mv *.zip ${OUTPUT_DIR}/
|
||||
cd ..
|
||||
'
|
||||
}
|
||||
|
||||
function attach() {
|
||||
echo "🔦 Connect to interactive shell"
|
||||
docker exec -it -w "${WORKDIR}" "${NAMEPREFIX}-${UNIQUE_ID}" /bin/bash
|
||||
}
|
||||
|
||||
function try() {
|
||||
# Copies the freshly built wrapper into your actual Blender/Bonsai
|
||||
# installation for manual, in-Blender testing. This is a human-only
|
||||
# convenience: it overwrites files in your live Blender setup, so it's
|
||||
# not something that should run unattended as part of an automated or
|
||||
# AI-driven build/test loop (which should instead copy the wrapper into
|
||||
# the repo's own src/ifcopenshell-python/ifcopenshell/ - see SKILL.md).
|
||||
echo "🚴 Copying build artifacts into your Blender resource folder for testing"
|
||||
|
||||
if [[ -z "${BLENDER_USER_RESOURCE:-}" ]]; then
|
||||
echo "❌ BLENDER_USER_RESOURCE is not set in .env."
|
||||
echo " Add a line pointing at wherever Blender's user resource folder for"
|
||||
echo " the Bonsai extension actually is on your system, e.g.:"
|
||||
echo " BLENDER_USER_RESOURCE=~/.config/blender/bonsai/"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Normalise: expand a leading ~ (in case it was quoted in .env and so
|
||||
# never went through shell tilde-expansion when set_env sourced it),
|
||||
# then resolve to an absolute, symlink-free path.
|
||||
local resource="${BLENDER_USER_RESOURCE/#\~/$HOME}"
|
||||
resource="$(realpath -m "$resource")"
|
||||
|
||||
local install_dir="../build/Linux/x86_64/install"
|
||||
local py_dirs=("$install_dir"/python-*)
|
||||
if [[ ${#py_dirs[@]} -gt 1 && -n "${PY_TGT:-}" ]]; then
|
||||
# PY_TGT is compact (py-311); the install dirs are dotted
|
||||
# (python-3.11.8) - reinsert the dot (assumes a single-digit major
|
||||
# version, true for the Python 3.x line) before matching.
|
||||
local py_tgt_digits="${PY_TGT#py-}"
|
||||
local py_tgt_dotted="${py_tgt_digits:0:1}.${py_tgt_digits:1}"
|
||||
local filtered=() d
|
||||
for d in "${py_dirs[@]}"; do
|
||||
[[ "$(basename "$d")" == "python-${py_tgt_dotted}."* ]] && filtered+=("$d")
|
||||
done
|
||||
[[ ${#filtered[@]} -gt 0 ]] && py_dirs=("${filtered[@]}")
|
||||
fi
|
||||
if [[ ${#py_dirs[@]} -ne 1 || ! -d "${py_dirs[0]}" ]]; then
|
||||
echo "❌ Expected exactly one built python-* dir under $install_dir, found ${#py_dirs[@]}."
|
||||
echo " Run 'build' first, or set PY_TGT in .env to disambiguate a multi-version build."
|
||||
return 1
|
||||
fi
|
||||
|
||||
local py_minor
|
||||
py_minor="$(basename "${py_dirs[0]}" | grep -oE '[0-9]+\.[0-9]+')"
|
||||
local wrapper_dir="${py_dirs[0]}/lib/python${py_minor}/site-packages/ifcopenshell"
|
||||
if [[ ! -f "$wrapper_dir/ifcopenshell_wrapper.py" ]]; then
|
||||
echo "❌ Built wrapper not found at $wrapper_dir - run 'build' first."
|
||||
return 1
|
||||
fi
|
||||
|
||||
local target="$resource/extensions/.local/lib/python${py_minor}/site-packages/ifcopenshell"
|
||||
mkdir -p "$target"
|
||||
cp "$wrapper_dir"/_ifcopenshell_wrapper*.so "$target/"
|
||||
cp "$wrapper_dir"/ifcopenshell_wrapper.py "$target/"
|
||||
echo "✅ Copied wrapper into $target"
|
||||
}
|
||||
|
||||
function clean() {
|
||||
# Host-side only - doesn't touch the container, image, or ccache volume.
|
||||
echo "💎 Clean the build and output folder up"
|
||||
if [[ -d "../build" ]]; then
|
||||
rm -rf ../build
|
||||
fi
|
||||
if [[ -d "../output" ]]; then
|
||||
rm -rf ../output
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function help() {
|
||||
cat <<EOF
|
||||
Usage: ./$SCRIPT_NAME <command>
|
||||
|
||||
Available commands:
|
||||
create Build the rocky9-based image
|
||||
update Rebuild the image fresh, picking up OS package updates
|
||||
up Create the container if it doesn't exist yet, and start it
|
||||
down Remove the container entirely (docker compose down)
|
||||
stop Stop the container without removing it
|
||||
start Start a previously-stopped container
|
||||
restart stop, then start (same container, no recreation)
|
||||
recreate down, then up (fresh container)
|
||||
build Execute the IfcOpenShell build
|
||||
attach Connect to an interactive shell in the container
|
||||
try Copy the built wrapper into your Blender resource folder
|
||||
(human-only - see BLENDER_USER_RESOURCE below, and SKILL.md
|
||||
for the AI/automated-testing equivalent)
|
||||
clean Remove the build and output folders
|
||||
logs Follow container logs
|
||||
ps Show running containers
|
||||
config Validate and show compose config
|
||||
remove Remove stopped containers (docker compose rm)
|
||||
help Show this help
|
||||
|
||||
Environment variables from .env are automatically loaded, including:
|
||||
PY_TGT Restrict the build to one Python version, e.g. py-311
|
||||
UNIQUE_ID Recalculated automatically on every 'up', don't set by hand
|
||||
BLENDER_USER_RESOURCE Where 'try' copies the wrapper for manual testing, e.g.
|
||||
~/.config/blender/bonsai/
|
||||
EOF
|
||||
}
|
||||
|
||||
# ================= MAIN =================
|
||||
|
||||
case "$1" in
|
||||
create) create ;;
|
||||
update) update ;;
|
||||
up) up "${@:2}" ;;
|
||||
down) down "${@:2}" ;;
|
||||
stop) stop "${@:2}" ;;
|
||||
start) start "${@:2}" ;;
|
||||
restart) restart ;;
|
||||
recreate) recreate ;;
|
||||
build) build "${@:2}" ;;
|
||||
attach) attach ;;
|
||||
try) try ;;
|
||||
clean) clean ;;
|
||||
logs) logs "${@:2}" ;;
|
||||
ps) ps ;;
|
||||
config) config ;;
|
||||
remove) remove ;;
|
||||
help|-h|--help) help ;;
|
||||
"")
|
||||
echo "❌ No command provided."
|
||||
help
|
||||
;;
|
||||
*)
|
||||
echo "❌ Unknown command: $1"
|
||||
echo "Type './$SCRIPT_NAME help' for available commands."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
# Build fix: remove `boost_system` from CMake components
|
||||
|
||||
`Boost.System` became header-only in Boost 1.69. Boost 1.90.0 no longer ships a compiled library or CMake config for it, so `find_package(Boost REQUIRED COMPONENTS system ...)` fails.
|
||||
|
||||
## Fix
|
||||
|
||||
`cmake/CMakeLists.txt`:
|
||||
|
||||
```diff
|
||||
- set(BOOST_COMPONENTS system program_options regex thread date_time iostreams)
|
||||
+ set(BOOST_COMPONENTS program_options regex thread date_time iostreams)
|
||||
```
|
||||
|
||||
The headers are still available; no linking is needed.
|
||||
|
||||
# Build fix: add `template` keyword for dependent template member calls
|
||||
|
||||
Calling a template member function through a dependent expression (e.g. `storage->has_attribute_value<T>(...)` where `storage`'s type depends on a template parameter) requires the `template` keyword to disambiguate from a less-than comparison.
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
src/ifcparse/IfcParse.cpp:1856:67: error: expected primary-expression before '>' token
|
||||
1856 | if (storage->has_attribute_value<express::Base>(attr_index)) {
|
||||
| ^
|
||||
```
|
||||
|
||||
Six identical errors at lines 1856, 1865, 1896, 1905, 1934, 1943.
|
||||
|
||||
## Fix
|
||||
|
||||
`src/ifcparse/IfcParse.cpp`:
|
||||
|
||||
```diff
|
||||
-storage->has_attribute_value<express::Base>(attr_index)
|
||||
+storage->template has_attribute_value<express::Base>(attr_index)
|
||||
|
||||
-storage->has_attribute_value<Blank>(attr_index)
|
||||
+storage->template has_attribute_value<Blank>(attr_index)
|
||||
```
|
||||
|
||||
Applied at all six call sites in `in_memory_file_storage::read_from_stream`.
|
||||
|
||||
# Linker fix: missing explicit template instantiations for `InstanceStreamer`
|
||||
|
||||
`InstanceStreamer` is a class template with methods defined in `IfcParse.cpp`, not the header. Without explicit instantiations, the linker can't find the symbols when the SWIG wrapper loads.
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
ImportError: undefined symbol: _ZN8IfcParse16InstanceStreamerINS_10FileReaderINS_14FullBufferImplEEEEC1EPS3_PNS_7IfcFileE
|
||||
(IfcParse::InstanceStreamer<FileReader<FullBufferImpl>>::InstanceStreamer(FileReader<FullBufferImpl>*, IfcFile*))
|
||||
```
|
||||
|
||||
## Fix
|
||||
|
||||
Cannot use `template class InstanceStreamer<...>` because some constructors have `static_assert` guards that reject certain reader types. Instead, instantiate each member function individually per reader type, only including the constructors valid for that type.
|
||||
|
||||
`src/ifcparse/IfcParse.cpp` (after the last `InstanceStreamer` method definition):
|
||||
|
||||
```cpp
|
||||
// FullBufferImpl
|
||||
template IfcParse::InstanceStreamer<FileReader<FullBufferImpl>>::InstanceStreamer(IfcParse::IfcFile*);
|
||||
template IfcParse::InstanceStreamer<FileReader<FullBufferImpl>>::InstanceStreamer(const std::string&, bool, IfcParse::IfcFile*);
|
||||
template IfcParse::InstanceStreamer<FileReader<FullBufferImpl>>::InstanceStreamer(void*, int, IfcParse::IfcFile*);
|
||||
template IfcParse::InstanceStreamer<FileReader<FullBufferImpl>>::InstanceStreamer(FileReader<FullBufferImpl>*, IfcParse::IfcFile*);
|
||||
// ... plus ensure_header, initialize_header, hasSemicolon, semicolonCount,
|
||||
// pushPage, bypassTypes, readInstance
|
||||
|
||||
// PushedSequentialImpl — same pattern, different valid constructors
|
||||
|
||||
// MMapFileReader (ifdef USE_MMAP) — same pattern
|
||||
```
|
||||
|
||||
# Linker fix: `FullBufferImpl` missing buffer constructor
|
||||
|
||||
SWIG's `stream_from_string` calls `InstanceStreamer<FileReader<FullBufferImpl>>(void*, int, IfcFile*)`, but the `(void*, int)` constructor previously hit a `static_assert` for `FullBufferImpl` — it only allowed `PushedSequentialImpl`.
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
ImportError: undefined symbol: _ZN8IfcParse16InstanceStreamerINS_10FileReaderINS_14FullBufferImplEEEEC1EPviPNS_7IfcFileE
|
||||
(InstanceStreamer<FileReader<FullBufferImpl>>::InstanceStreamer(void*, int, IfcFile*))
|
||||
```
|
||||
|
||||
## Fix
|
||||
|
||||
Three changes to make `FullBufferImpl` support buffer-based and default construction:
|
||||
|
||||
`src/ifcparse/FileReader.h` — add buffer constructor to `FullBufferImpl`:
|
||||
|
||||
```diff
|
||||
class IFC_PARSE_API FullBufferImpl {
|
||||
public:
|
||||
explicit FullBufferImpl(const std::string& fn);
|
||||
+ FullBufferImpl(void* data, size_t length);
|
||||
```
|
||||
|
||||
`src/ifcparse/FileReader.h` — add `FileReader(void*, size_t)` forwarding constructor:
|
||||
|
||||
```diff
|
||||
+ FileReader(void* data, size_t length)
|
||||
+ : cursor_(0) {
|
||||
+ if constexpr (std::is_same_v<Impl, FullBufferImpl>) {
|
||||
+ impl_ = std::make_shared<Impl>(data, length);
|
||||
+ } else {
|
||||
+ static_assert(...);
|
||||
+ }
|
||||
+ }
|
||||
```
|
||||
|
||||
`src/ifcparse/FileReader.cpp` — implement the constructor:
|
||||
|
||||
```cpp
|
||||
FullBufferImpl::FullBufferImpl(void* data, size_t length)
|
||||
: buf_(static_cast<char*>(data), static_cast<char*>(data) + length)
|
||||
, size_(length) {
|
||||
}
|
||||
```
|
||||
|
||||
`src/ifcparse/IfcParse.cpp` — extend the two `InstanceStreamer` constructors to accept `FullBufferImpl`:
|
||||
|
||||
```diff
|
||||
// InstanceStreamer(IfcFile*):
|
||||
+ } else if constexpr (std::is_same_v<Reader, FileReader<FullBufferImpl>>) {
|
||||
+ owned_stream_ = std::make_unique<Reader>(nullptr, (size_t)0);
|
||||
|
||||
// InstanceStreamer(void*, int, IfcFile*):
|
||||
+ } else if constexpr (std::is_same_v<Reader, FileReader<FullBufferImpl>>) {
|
||||
+ owned_stream_ = std::make_unique<Reader>(data, (size_t)length);
|
||||
```
|
||||
|
||||
# Runtime fix: segfault in `parse_context::push()` due to vector reallocation
|
||||
|
||||
`parse_context_pool` stores nodes in a `std::vector<parse_context>`. During parsing, `load()` takes a `parse_context&` parameter and calls `context.push()`, which calls `pool_->make()`. If the pool's vector reallocates (via `emplace_back`), all existing references into the vector — including the `context` reference held by the caller — become dangling. Subsequent access through the dangling reference causes a segfault.
|
||||
|
||||
Triggered by larger IFC files (e.g. `ISSUE_159_kleine_Wohnung_R22.ifc`, 9.5 MB) that cause enough pool growth to trigger reallocation.
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
Thread 1 received signal SIGSEGV, Segmentation fault.
|
||||
0x... in IfcParse::parse_context::push()
|
||||
#1 in_memory_file_storage::load(...) // context& is dangling after reallocation
|
||||
#2 in_memory_file_storage::load(...) // parent call
|
||||
#3 InstanceStreamer::readInstance()
|
||||
```
|
||||
|
||||
## Fix
|
||||
|
||||
`src/ifcparse/storage.h` — change the pool container from `std::vector` to `std::deque`, which does not invalidate references on `push_back`/`emplace_back`:
|
||||
|
||||
```diff
|
||||
+#include <deque>
|
||||
|
||||
struct parse_context_pool {
|
||||
- std::vector<parse_context> nodes_;
|
||||
+ std::deque<parse_context> nodes_;
|
||||
```
|
||||
|
||||
# Runtime fix: `express::Base` comparison operators throw on null/expired instances
|
||||
|
||||
`express::Base::operator<` and `operator==` called `data()`, which throws `std::runtime_error("Trying to access deleted instance reference")` when the internal `weak_ptr` is expired. A default-constructed `express::Base` (the value-type equivalent of a null pointer) always has an expired `weak_ptr`.
|
||||
|
||||
## Why this model triggers it
|
||||
|
||||
The bug requires two conditions to coincide:
|
||||
|
||||
1. A representation is shared by **more than one product** (via `IfcRepresentationMap` / `IfcMappedItem`).
|
||||
2. At least one of those products has **no material association**, so `get_single_material_association()` returns `express::Base{}` (the null equivalent).
|
||||
|
||||
In `advanced_model.ifc`, Body representations like `#449` (Body/Brep) have a single `IfcRepresentationMap` (`#453`) with 13 `IfcMappedItem` usages, meaning 13 products share the geometry. Some of those products (e.g. `IfcFlowTerminal` instances) have no `IfcRelAssociatesMaterial`, so `get_single_material_association` returns `express::Base{}`.
|
||||
|
||||
Smaller or simpler models don't hit this because either:
|
||||
- Every representation maps to only 1 product → `reuse_ok_` short-circuits at `products.size() == 1` before reaching the material check.
|
||||
- Every product has a material association → no null `express::Base` is ever inserted into the set.
|
||||
|
||||
## Exact call sequence
|
||||
|
||||
```
|
||||
Iterator::initialize()
|
||||
try {
|
||||
mapping::get_representations(reps, filters_)
|
||||
addRepresentationsFromDefaultContexts(representations)
|
||||
→ collects reps from subcontexts in order:
|
||||
Axis (#115): 143 reps
|
||||
Body (#117): 7550 reps
|
||||
FootPrint (#119): 12 reps
|
||||
|
||||
for (auto representation : representations):
|
||||
|
||||
── Axis reps (indices 0–142) ──────────────────────────
|
||||
products_represented_by(rep, rmap)
|
||||
→ OfProductRepresentation: 1 product each
|
||||
filter_products(products, filters) → 1 product
|
||||
reuse_ok_(ifcproducts)
|
||||
→ products.size() == 1 → return true ← SHORT-CIRCUIT, no material check
|
||||
representation_mapped_to(rep) → null (no MappedItem)
|
||||
→ task created. 143 tasks accumulated.
|
||||
|
||||
── First Body rep #449 (Body/Brep) ────────────────────
|
||||
products_represented_by(#449, rmap)
|
||||
→ OfProductRepresentation: empty
|
||||
→ RepresentationMap: 1 map (#453)
|
||||
→ MapUsage: 13 MappedItems → traces through to 13 IfcProducts
|
||||
filter_products(products, filters) → 13 products
|
||||
reuse_ok_(ifcproducts) ← CRASH HERE
|
||||
→ products.size() == 1? NO (13 products)
|
||||
→ for each product:
|
||||
find_openings(product) → OK
|
||||
get_single_material_association(product)
|
||||
→ some products have no IfcRelAssociatesMaterial
|
||||
→ returns express::Base{} (expired weak_ptr)
|
||||
associated_single_materials.insert(result)
|
||||
→ std::set::insert calls operator<
|
||||
→ operator< calls data()
|
||||
→ data() calls data_.lock() → expired → THROWS
|
||||
"Trying to access deleted instance reference"
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e) ← exception caught here, get_representations aborted
|
||||
}
|
||||
|
||||
→ reps contains only the 143 Axis tasks created before the throw
|
||||
→ all 143 Axis reps have Curve2D geometry → map(representation) returns null
|
||||
→ no valid elements produced → initialize() returns false
|
||||
```
|
||||
|
||||
In the old pointer-based code, `reuse_ok_` used `std::set<const IfcUtil::IfcBaseEntity*>` and `get_single_material_association` returned `nullptr`. Inserting `nullptr` into a `std::set<T*>` is a plain pointer comparison — no dereference, no throw. The refactoring to `std::set<express::Base>` changed the comparison from pointer comparison to `express::Base::operator<`, which unconditionally dereferences through `data()`.
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
[Error] Trying to access deleted instance reference
|
||||
[Notice] Created 143 tasks for 143 products ← only Axis reps; all Body reps lost
|
||||
initialize() returned: False
|
||||
```
|
||||
|
||||
## Fix
|
||||
|
||||
`src/ifcparse/express.h` — use `weak_ptr::lock().get()` instead of `data()` so that expired pointers compare as `nullptr` (matching old raw-pointer semantics):
|
||||
|
||||
```diff
|
||||
bool operator<(const Base& other) const {
|
||||
- return data() < other.data();
|
||||
+ auto a = data_.lock();
|
||||
+ auto b = other.data_.lock();
|
||||
+ return a.get() < b.get();
|
||||
}
|
||||
|
||||
bool operator==(const Base& other) const {
|
||||
- return data() == other.data();
|
||||
+ auto a = data_.lock();
|
||||
+ auto b = other.data_.lock();
|
||||
+ return a.get() == b.get();
|
||||
}
|
||||
```
|
||||
|
||||
# Runtime fix: `entity_instance` missing `get_inverse` due to SWIG `%rename` collision
|
||||
|
||||
Accessing inverse attributes (e.g. `element.IsDecomposedBy`) on any entity raises `AttributeError: entity instance of type 'IFC2X3.IfcProject' has no attribute 'get_inverse'`.
|
||||
|
||||
## Why
|
||||
|
||||
`entity_instance_mixin.__getattr__` (line 106 of `entity_instance.py`) calls `self.get_inverse(name)` when it detects an inverse attribute. Since the mixin inherits into the SWIG-generated `entity_instance` class (via the `object = custom_base` hack in `IfcParseWrapper.i:936`), `self.get_inverse` must resolve to a method on the SWIG class.
|
||||
|
||||
However, `IfcParseWrapper.i:70` has a global rename:
|
||||
|
||||
```
|
||||
%rename("get_inverses_by_declaration") get_inverse;
|
||||
```
|
||||
|
||||
This was intended for `ifcopenshell::file::get_inverse` (which takes an entity + declaration and returns instances by reference), but SWIG `%rename` is global — it also renames the `%extend express::Base` method `get_inverse(const std::string& a)` at line 551. So the Python-side `entity_instance` class exposes the method as `get_inverses_by_declaration`, not `get_inverse`.
|
||||
|
||||
The old code (`v0.8.0`) didn't hit this because `__getattr__` called `self.wrapped_data.get_inverse(name)` on an inner `ifcopenshell_wrapper.entity_instance` object — but in that old layout, the inner object was constructed differently and the rename didn't apply the same way (or the method had a different path). In the new mixin approach, `self` **is** the SWIG object, so the rename is directly visible.
|
||||
|
||||
## Fix
|
||||
|
||||
`src/ifcwrap/IfcParseWrapper.i` — override the global rename specifically for `express::Base::get_inverse`, restoring the original name on entity instances:
|
||||
|
||||
```diff
|
||||
+%rename("get_inverse") express::Base::get_inverse;
|
||||
%rename("get_inverses_by_declaration") get_inverse;
|
||||
```
|
||||
|
||||
Add this line **before** the global rename (or anywhere before the `%extend express::Base` block). This scoped rename takes precedence for `express::Base`, so:
|
||||
- `entity_instance.get_inverse(name)` works as the mixin expects
|
||||
- `file.get_inverses_by_declaration(...)` keeps its intended name
|
||||
|
||||
## Python-side workaround
|
||||
|
||||
`entity_instance.py:106` — call the method by its SWIG-renamed name:
|
||||
|
||||
```diff
|
||||
- vs = self.get_inverse(name)
|
||||
+ vs = self.get_inverses_by_declaration(name)
|
||||
```
|
||||
|
||||
# Runtime fix: `entity_instance` class no longer importable from `entity_instance` module
|
||||
|
||||
The class rename from `entity_instance` to `entity_instance_mixin` broke external code that does `from ifcopenshell.entity_instance import entity_instance`.
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
ImportError: cannot import name 'entity_instance' from 'ifcopenshell.entity_instance'
|
||||
```
|
||||
|
||||
Triggered at import time via `ifcopenshell.util.pset` (and likely other modules).
|
||||
|
||||
## Fix
|
||||
|
||||
`src/ifcopenshell-python/ifcopenshell/entity_instance.py` — add a backwards-compatible alias at the bottom of the module:
|
||||
|
||||
```python
|
||||
entity_instance = entity_instance_mixin
|
||||
```
|
||||
+191
-136
@@ -1,6 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
# /// script
|
||||
# ///
|
||||
###############################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
@@ -50,7 +48,7 @@ Used environment variables:
|
||||
- ``NO_CLEAN`` - do not clean `ifcopenshell` build directories but continue working on current build
|
||||
(installed dependencies are never cleared).
|
||||
By default option is disabled, to enable pass any value from `1`, `on`, `true`.
|
||||
- ``IFCOS_SCHEMAS`` - schemas to be built; defaults to cmake default (8 schemas), to be supplied as `2x3;4;4x3_add2`
|
||||
- ``IFCOS_SCHEMAS`` - schemas to be built; defaults to cmake default (IFC2X3; IFC4; IFC4X3_ADD2) - to be supplied as `2x3;4`
|
||||
- ``USE_OCCT`` - whether to use official Open CASCADE instead of Community Edition
|
||||
(`true` by default, any other value is considered `false`)
|
||||
- ``WASM_PYTHON_PATH`` - path to WASM Python installation,
|
||||
@@ -109,7 +107,6 @@ import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import shutil
|
||||
|
||||
# @todo temporary for expired mpfr.org certificate on 2023-04-08
|
||||
@@ -121,14 +118,21 @@ import tarfile
|
||||
import threading
|
||||
from datetime import datetime
|
||||
|
||||
ssl._create_default_https_context = ssl._create_unverified_context # ty:ignore[invalid-assignment]
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
|
||||
import time
|
||||
from collections.abc import Generator, Sequence
|
||||
from pathlib import Path
|
||||
from typing import Literal, Union
|
||||
from urllib.request import urlretrieve
|
||||
|
||||
try:
|
||||
from typing import Literal, Union
|
||||
except:
|
||||
# python 3.6 compatibility for rocky 8
|
||||
from typing import Union
|
||||
|
||||
from typing_extensions import Literal
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.INFO)
|
||||
ch = logging.StreamHandler()
|
||||
@@ -137,6 +141,7 @@ logger.addHandler(ch)
|
||||
PROJECT_NAME = "IfcOpenShell"
|
||||
USE_CURRENT_PYTHON_VERSION = os.getenv("USE_CURRENT_PYTHON_VERSION")
|
||||
ADD_COMMIT_SHA = os.getenv("ADD_COMMIT_SHA")
|
||||
BUILD_BONSAIVIEWER = os.getenv("BUILD_BONSAIVIEWER", "").lower() in {"1", "on", "true", "yes"}
|
||||
|
||||
PYTHON_VERSIONS = ["3.10.3", "3.11.8", "3.12.1", "3.13.6", "3.14.0"]
|
||||
JSON_VERSION = "3.11.3"
|
||||
@@ -148,15 +153,17 @@ PCRE_VERSION = "8.41"
|
||||
LIBXML2_VERSION = "2.13.8"
|
||||
SWIG_VERSION = "4.2.1"
|
||||
OPENCOLLADA_VERSION = "v1.6.68"
|
||||
HDF5_VERSION = "1.13.1"
|
||||
|
||||
GMP_VERSION = "6.3.0"
|
||||
MPFR_VERSION = "3.1.6" # latest is 4.1.0
|
||||
CGAL_VERSION = "v5.6.3"
|
||||
USD_VERSION = "23.05"
|
||||
TBB_VERSION = "2021.9.0"
|
||||
ROCKSDB_VERSION = "10.4.2"
|
||||
ROCKSDB_VERSION = "9.11.2"
|
||||
ZSTD_VERSION = "1.5.7"
|
||||
MANIFOLD_VERSION = "3.2.1"
|
||||
QT6_VERSION = os.getenv("QT6_VERSION", "6.8.3")
|
||||
|
||||
# binaries
|
||||
cp = "cp"
|
||||
bash = "bash"
|
||||
@@ -324,12 +331,13 @@ cecho(""" - IFC Schemas to compile. If not provided, fallback to default provide
|
||||
""")
|
||||
|
||||
dependency_tree: "dict[str, tuple[str, ...]]" = {
|
||||
"IfcParse": ("boost", "libxml2", "hdf5", "rocksdb"),
|
||||
"IfcGeom": ("IfcParse", "occ", "json", "cgal", "eigen", "OpenCOLLADA"),
|
||||
"IfcParse": ("boost", "libxml2", "rocksdb"),
|
||||
"IfcGeom": ("IfcParse", "occ", "manifold", "json", "cgal", "eigen", "OpenCOLLADA"),
|
||||
"IfcConvert": ("IfcGeom",),
|
||||
"OpenCOLLADA": ("libxml2", "pcre"),
|
||||
"IfcGeomServer": ("IfcGeom",),
|
||||
"IfcOpenShell-Python": ("python", "swig", "IfcGeom"),
|
||||
"BonsaiViewer": ("IfcGeom", "qt6"),
|
||||
"swig": (),
|
||||
"boost": (),
|
||||
"libxml2": (),
|
||||
@@ -337,11 +345,12 @@ dependency_tree: "dict[str, tuple[str, ...]]" = {
|
||||
"occ": (),
|
||||
"pcre": (),
|
||||
"json": (),
|
||||
"hdf5": (),
|
||||
"cgal": (),
|
||||
"eigen": (),
|
||||
"rocksdb": ("zstd",),
|
||||
"zstd": (),
|
||||
"manifold": (),
|
||||
"qt6": (),
|
||||
# 'usd': ('boost', 'oneTBB')
|
||||
}
|
||||
|
||||
@@ -395,9 +404,12 @@ else:
|
||||
targets = set(dependency_tree.keys())
|
||||
|
||||
targets = set(t for t in targets if "without-%s" % t.lower() not in flags)
|
||||
if not explicit_targets and not BUILD_BONSAIVIEWER:
|
||||
targets.difference_update({"BonsaiViewer", "qt6"})
|
||||
if BUILD_BONSAIVIEWER:
|
||||
targets.update(gather_dependencies("BonsaiViewer"))
|
||||
if WASM:
|
||||
SKIP_TARGETS_FOR_WASM = {
|
||||
"hdf5",
|
||||
"rocksdb",
|
||||
"opencollada",
|
||||
"swig",
|
||||
@@ -405,6 +417,8 @@ if WASM:
|
||||
"IfcGeom",
|
||||
"IfcConvert",
|
||||
"IfcGeomServer",
|
||||
"BonsaiViewer",
|
||||
"qt6",
|
||||
}
|
||||
SKIP_TARGETS_FOR_WASM = {t.lower() for t in SKIP_TARGETS_FOR_WASM}
|
||||
skip_targets = {t for t in targets if t.lower() in SKIP_TARGETS_FOR_WASM}
|
||||
@@ -578,6 +592,11 @@ def run_cmake(arg1, cmake_args: "list[str]", cmake_dir: Union[str, None] = None,
|
||||
]
|
||||
)
|
||||
|
||||
if not any("BUILD_SHARED_LIBS" in f for f in cmake_args):
|
||||
cmake_flags.append(
|
||||
f"-DBUILD_SHARED_LIBS={OFF_ON[not BUILD_STATIC]}",
|
||||
)
|
||||
|
||||
run(
|
||||
[
|
||||
*wasm,
|
||||
@@ -586,7 +605,6 @@ def run_cmake(arg1, cmake_args: "list[str]", cmake_dir: Union[str, None] = None,
|
||||
*cmake_flags,
|
||||
*cmake_args,
|
||||
f"-DCMAKE_BUILD_TYPE={BUILD_CFG}",
|
||||
f"-DBUILD_SHARED_LIBS={OFF_ON[not BUILD_STATIC]}",
|
||||
f"-DCMAKE_SHARED_LINKER_FLAGS={os.environ['LDFLAGS']}",
|
||||
],
|
||||
cwd=cwd,
|
||||
@@ -621,16 +639,14 @@ def build_dependency(
|
||||
mode: Literal[
|
||||
"cmake",
|
||||
"autoconf",
|
||||
"ctest",
|
||||
"bjam",
|
||||
],
|
||||
build_tool_args: "list[str]",
|
||||
download_url: str,
|
||||
download_name: str,
|
||||
*,
|
||||
download_tool: Literal["py", "git"] = download_tool_default,
|
||||
revision: "Union[str, None]" = None,
|
||||
patch: list[str] | None = None,
|
||||
patch: "Union[str, list[str], None]" = None,
|
||||
shell=None,
|
||||
pre_compile_subs: "Sequence[tuple[str, str, str]]" = (),
|
||||
additional_files: "Union[dict[str, str], None]" = None,
|
||||
@@ -697,10 +713,7 @@ def build_dependency(
|
||||
compr = "xz"
|
||||
else:
|
||||
raise RuntimeError("fix source for new download type")
|
||||
# ty: false positive bug upstream.
|
||||
download_tarfile = tarfile.open(
|
||||
name=download_tarfile_path, mode=f"r:{compr}"
|
||||
) # ty:ignore[no-matching-overload]
|
||||
download_tarfile = tarfile.open(name=download_tarfile_path, mode=f"r:{compr}")
|
||||
# tarfile seriously doesn't have a function to retrieve the root directory more easily
|
||||
extract_dir_name = os.path.commonprefix([x for x in download_tarfile.getnames() if x != "."])
|
||||
# run([tar, "--exclude=\"*/*\"", "-tf", download_name], cwd=build_dir).strip() no longer works
|
||||
@@ -718,6 +731,8 @@ def build_dependency(
|
||||
urlretrieve(url, os.path.join(extract_dir, path))
|
||||
|
||||
if patch is not None:
|
||||
if isinstance(patch, str):
|
||||
patch = [patch]
|
||||
for p in patch:
|
||||
patch_abs = (SCRIPT_PATH / p).absolute().__str__()
|
||||
if os.path.exists(patch_abs):
|
||||
@@ -726,29 +741,11 @@ def build_dependency(
|
||||
except Exception as e:
|
||||
# Assert that the patch has already been applied
|
||||
run(["patch", "-p1", "--batch", "--reverse", "--dry-run", "-i", patch_abs], cwd=extract_dir)
|
||||
else:
|
||||
raise FileNotFoundError(patch_abs)
|
||||
|
||||
if shell is not None:
|
||||
sp.run(shell, shell=True, check=True, cwd=extract_dir)
|
||||
|
||||
if mode == "ctest":
|
||||
try:
|
||||
run(
|
||||
["ctest", "-S", "HDF5config.cmake,BUILD_GENERATOR=Unix", "-C", BUILD_CFG, "-V", "-O", "hdf5.log"],
|
||||
cwd=extract_dir,
|
||||
)
|
||||
except Exception as e:
|
||||
print("-" * 70)
|
||||
print(open(os.path.join(extract_dir, "hdf5.log")))
|
||||
print("-" * 70)
|
||||
raise e
|
||||
run([tar, "-xf", kwargs["ctest_result"] + ".tar.gz"], cwd=os.path.join(extract_dir, "build"))
|
||||
shutil.copytree(
|
||||
os.path.join(extract_dir, "build", kwargs["ctest_result"], kwargs["ctest_result_path"]),
|
||||
os.path.join(DEPS_DIR, "install", name),
|
||||
)
|
||||
elif mode != "bjam":
|
||||
if mode != "bjam":
|
||||
extract_build_dir = os.path.join(extract_dir, *([cmake_dir] if cmake_dir else []), "build")
|
||||
if os.path.exists(extract_build_dir):
|
||||
shutil.rmtree(extract_build_dir)
|
||||
@@ -787,6 +784,61 @@ def build_dependency(
|
||||
shutil.rmtree(build_dir, ignore_errors=True)
|
||||
|
||||
|
||||
def get_qt6_aqt_config() -> "tuple[str, str, str]":
|
||||
if platform.system() != "Linux":
|
||||
raise ValueError("Automatic Qt6 installation with aqtinstall is only configured for Linux builds.")
|
||||
|
||||
machine = platform.machine().lower()
|
||||
if machine in {"x86_64", "amd64"}:
|
||||
return "linux", "linux_gcc_64", "gcc_64"
|
||||
if machine in {"aarch64", "arm64"}:
|
||||
return "linux_arm64", "linux_gcc_arm64", "gcc_arm64"
|
||||
|
||||
raise ValueError(f"Automatic Qt6 installation is not configured for architecture '{platform.machine()}'.")
|
||||
|
||||
|
||||
def install_qt6() -> str:
|
||||
host, qt_arch, install_suffix = get_qt6_aqt_config()
|
||||
qt_install_root = INSTALL_DIR / f"qt6-{QT6_VERSION}-{install_suffix}"
|
||||
qt_dir = qt_install_root / QT6_VERSION / install_suffix
|
||||
os.environ["QT_DIR"] = str(qt_dir)
|
||||
|
||||
qt_config = qt_dir / "lib" / "cmake" / "Qt6" / "Qt6Config.cmake"
|
||||
qt_core = qt_dir / "lib" / "libQt6Core.so.6"
|
||||
qt_svg = qt_dir / "lib" / "cmake" / "Qt6Svg" / "Qt6SvgConfig.cmake"
|
||||
if qt_config.exists() and qt_core.exists() and qt_svg.exists():
|
||||
logger.info(f"Found existing Qt6 at {qt_dir}, skipping")
|
||||
return str(qt_dir)
|
||||
|
||||
os.makedirs(qt_install_root, exist_ok=True)
|
||||
run(
|
||||
[
|
||||
sys.executable,
|
||||
"-m",
|
||||
"aqt",
|
||||
"install-qt",
|
||||
host,
|
||||
"desktop",
|
||||
QT6_VERSION,
|
||||
qt_arch,
|
||||
"-O",
|
||||
str(qt_install_root),
|
||||
# Keep the install lean by filtering archives: qtbase provides
|
||||
# Core/Gui/Widgets (and the Qt6::CorePrivate target), qtsvg provides
|
||||
# Qt6::Svg. Both are base-Qt archives, not add-on modules.
|
||||
"--archives",
|
||||
"icu",
|
||||
"qtbase",
|
||||
"qtsvg",
|
||||
]
|
||||
)
|
||||
|
||||
if not (qt_config.exists() and qt_core.exists() and qt_svg.exists()):
|
||||
raise RuntimeError(f"Qt6 installation did not produce a usable Qt at {qt_dir}.")
|
||||
|
||||
return str(qt_dir)
|
||||
|
||||
|
||||
cecho("Collecting dependencies:", GREEN)
|
||||
|
||||
# Set compiler flags for 32bit builds on 64bit system
|
||||
@@ -844,37 +896,6 @@ os.environ["LDFLAGS"] = LDFLAGS
|
||||
# @tfk: this is no longer needed
|
||||
# build_dependency(name="cmake-%s" % (CMAKE_VERSION,), mode="autoconf", build_tool_args=[], download_url="https://cmake.org/files/v%s" % (CMAKE_VERSION_2,), download_name="cmake-%s.tar.gz" % (CMAKE_VERSION,))
|
||||
|
||||
if "hdf5" in targets:
|
||||
# not supported
|
||||
orig = [os.environ[f] for f in compiler_flags]
|
||||
for f in compiler_flags:
|
||||
os.environ[f] = re.sub(r"-flto(=\w+)?", "", os.environ[f])
|
||||
|
||||
HDF5_UNDERSCORE = "_".join(HDF5_VERSION.split("."))
|
||||
HDF5_MAJOR = ".".join(HDF5_VERSION.split(".")[:-1])
|
||||
dependency_name = f"hdf5-{HDF5_VERSION}"
|
||||
build_dependency(
|
||||
name=dependency_name,
|
||||
mode="cmake",
|
||||
build_tool_args=[
|
||||
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/{dependency_name}",
|
||||
"-DHDF5_ENABLE_Z_LIB_SUPPORT=OFF",
|
||||
"-DBUILD_TESTING=OFF",
|
||||
"-DHDF5_BUILD_TOOLS=OFF",
|
||||
"-DHDF5_BUILD_EXAMPLES=OFF",
|
||||
"-DBUILD_SHARED_LIBS=OFF",
|
||||
"-DHDF5_BUILD_UTILS=OFF",
|
||||
"-DHDF5_BUILD_CPP_LIB=ON",
|
||||
*MAC_CROSS_COMPILE_INTEL_ARGS,
|
||||
],
|
||||
download_url=f"https://github.com/HDFGroup/hdf5/archive/refs/tags/",
|
||||
download_name=f"hdf5-{HDF5_UNDERSCORE}.tar.gz",
|
||||
)
|
||||
|
||||
for f, o in zip(compiler_flags, orig):
|
||||
os.environ[f] = o
|
||||
|
||||
|
||||
if "json" in targets:
|
||||
dependency_name = f"json-{JSON_VERSION}"
|
||||
build_dependency(
|
||||
@@ -993,6 +1014,33 @@ elif "occ" in targets:
|
||||
download_name=f"OCE-{OCE_VERSION}.tar.gz",
|
||||
)
|
||||
|
||||
if "manifold" in targets:
|
||||
dependency_name = f"manifold-{MANIFOLD_VERSION}"
|
||||
patches = []
|
||||
if WASM:
|
||||
patches.append("./patches/manifold/install-metadata-for-emscripten.patch")
|
||||
build_dependency(
|
||||
name=dependency_name,
|
||||
mode="cmake",
|
||||
build_tool_args=[
|
||||
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/{dependency_name}",
|
||||
"-DMANIFOLD_PAR=OFF",
|
||||
"-DMANIFOLD_CROSS_SECTION=OFF",
|
||||
"-DMANIFOLD_PYBIND=OFF",
|
||||
"-DMANIFOLD_JSBIND=OFF",
|
||||
"-DMANIFOLD_CBIND=OFF",
|
||||
"-DMANIFOLD_TEST=OFF",
|
||||
"-DMANIFOLD_EXPORT=OFF",
|
||||
"-DMANIFOLD_DOWNLOADS=OFF",
|
||||
*MAC_CROSS_COMPILE_INTEL_ARGS,
|
||||
],
|
||||
download_url="https://github.com/elalish/manifold.git",
|
||||
download_name="manifold",
|
||||
download_tool=download_tool_git,
|
||||
revision=f"v{MANIFOLD_VERSION}",
|
||||
patch=patches,
|
||||
)
|
||||
|
||||
if "libxml2" in targets:
|
||||
OLD_CC = ""
|
||||
if MAC_CROSS_COMPILE_INTEL:
|
||||
@@ -1175,14 +1223,6 @@ if "cgal" in targets:
|
||||
os.environ["CC"] = MAC_CROSS_COMPILE_INTEL_CC
|
||||
gmp_args.extend(MAC_CROSS_COMPILE_INTEL_AUTOCONF_HOST_ARGS)
|
||||
|
||||
# Fixes configure failing to find a working compiler under GCC 15's default -std=gnu23.
|
||||
# Issue presumably will be resolved in any next gmp version, but currently the last one is 6.3.0.
|
||||
# Patch is just applying fix from upstream meantion below:
|
||||
# https://gmplib.org/list-archives/gmp-bugs/2025-February/005561.html
|
||||
gmp_patches = ["./patches/gmp/001-fix-std23.patch"]
|
||||
if GMP_VERSION != "6.3.0":
|
||||
raise Exception(f"GMP_VERSION changed to {GMP_VERSION}, check whether {gmp_patches} is still needed.")
|
||||
|
||||
build_dependency(
|
||||
name=f"gmp-{GMP_VERSION}",
|
||||
mode="autoconf",
|
||||
@@ -1190,7 +1230,6 @@ if "cgal" in targets:
|
||||
pre_compile_subs=(
|
||||
[("build/config.h", "HAVE_OBSTACK_VPRINTF 1", "HAVE_OBSTACK_VPRINTF 0")] if "wasm" in flags else []
|
||||
),
|
||||
patch=gmp_patches,
|
||||
# Sometimes ftp.gnu.org is very slow, use ftpmirror.gnu.org as a workaround.
|
||||
download_url="https://ftpmirror.gnu.org/gnu/gmp/",
|
||||
download_name=f"gmp-{GMP_VERSION}.tar.bz2",
|
||||
@@ -1305,6 +1344,9 @@ if "rocksdb" in targets:
|
||||
revision=f"v{ROCKSDB_VERSION}",
|
||||
)
|
||||
|
||||
if "qt6" in targets:
|
||||
install_qt6()
|
||||
|
||||
cecho("Building IfcOpenShell:", GREEN)
|
||||
|
||||
IFCOS_DIR = os.path.join(DEPS_DIR, "build", "ifcopenshell")
|
||||
@@ -1312,8 +1354,8 @@ if os.environ.get("NO_CLEAN", "").lower() not in {"1", "on", "true"}:
|
||||
if os.path.exists(IFCOS_DIR):
|
||||
shutil.rmtree(IFCOS_DIR)
|
||||
os.makedirs(IFCOS_DIR, exist_ok=True)
|
||||
executables_dir = os.path.join(IFCOS_DIR, "executables")
|
||||
os.makedirs(executables_dir, exist_ok=True)
|
||||
ifcos_build_dir = os.path.join(IFCOS_DIR, "build")
|
||||
os.makedirs(ifcos_build_dir, exist_ok=True)
|
||||
|
||||
|
||||
cmake_args = [
|
||||
@@ -1322,6 +1364,7 @@ cmake_args = [
|
||||
"-DBUILD_SHARED_LIBS=" + OFF_ON[not BUILD_STATIC],
|
||||
"-DGLTF_SUPPORT=ON",
|
||||
"-DBoost_NO_BOOST_CMAKE=On",
|
||||
"-DCREATE_BUNDLE=On",
|
||||
"-DADD_COMMIT_SHA=" + ("On" if ADD_COMMIT_SHA else "Off"),
|
||||
"-DVERSION_OVERRIDE=" + ("On" if ADD_COMMIT_SHA else "Off"),
|
||||
*MAC_CROSS_COMPILE_INTEL_ARGS,
|
||||
@@ -1371,6 +1414,10 @@ elif "occ" in targets:
|
||||
occ_library_dir = f"{DEPS_DIR}/install/oce-{OCE_VERSION}/lib"
|
||||
cmake_args.extend(["-DOCC_INCLUDE_DIR=" + occ_include_dir, "-DOCC_LIBRARY_DIR=" + occ_library_dir])
|
||||
|
||||
if "manifold" in targets:
|
||||
cmake_args_prefix_path.append(f"{DEPS_DIR}/install/manifold-{MANIFOLD_VERSION}")
|
||||
cmake_args.append("-DWITH_MANIFOLD=On")
|
||||
|
||||
if "OpenCOLLADA" in targets:
|
||||
# pcre is a dependency of OpenCOLLADA, but since we `find_package`,
|
||||
# we don't need to add it explicitly here as cmake will find it from the config.
|
||||
@@ -1385,11 +1432,6 @@ else:
|
||||
if "libxml2" in targets:
|
||||
cmake_args_prefix_path.append(f"{DEPS_DIR}/install/libxml2-{LIBXML2_VERSION}")
|
||||
|
||||
if "hdf5" in targets:
|
||||
cmake_args_prefix_path.append(f"{DEPS_DIR}/install/hdf5-{HDF5_VERSION}")
|
||||
else:
|
||||
cmake_args.append("-DHDF5_SUPPORT=Off")
|
||||
|
||||
if "usd" in targets:
|
||||
cmake_args.append("-DUSD_SUPPORT=ON")
|
||||
cmake_args_prefix_path.extend(
|
||||
@@ -1416,40 +1458,44 @@ if "rocksdb" in targets:
|
||||
if "swig" in targets:
|
||||
cmake_args_prefix_path.append(f"{DEPS_DIR}/install/swig-{SWIG_VERSION}")
|
||||
|
||||
if not WASM and (not explicit_targets or {"IfcGeom", "IfcConvert", "IfcGeomServer"} & set(explicit_targets)):
|
||||
if os.environ.get("QT_DIR"):
|
||||
cmake_args_prefix_path.append(os.environ["QT_DIR"])
|
||||
cmake_args.append(f"-DQT_DIR={os.environ['QT_DIR']}")
|
||||
|
||||
build_bonsaiviewer = BUILD_BONSAIVIEWER or "BonsaiViewer" in targets
|
||||
|
||||
ifcos_build_args = [
|
||||
f"-DBUILD_IFCGEOM={OFF_ON['IfcGeom' in targets]}",
|
||||
f"-DBUILD_GEOMSERVER={OFF_ON['IfcGeomServer' in targets]}",
|
||||
f"-DBUILD_CONVERT={OFF_ON['IfcConvert' in targets]}",
|
||||
f"-DBUILD_BONSAIVIEWER={OFF_ON[build_bonsaiviewer]}",
|
||||
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/ifcopenshell",
|
||||
]
|
||||
|
||||
if not WASM and (
|
||||
build_bonsaiviewer
|
||||
or not explicit_targets
|
||||
or {"IfcGeom", "IfcConvert", "IfcGeomServer", "BonsaiViewer"} & set(explicit_targets)
|
||||
):
|
||||
logger.info("\rConfiguring executables...")
|
||||
|
||||
exec_args = [
|
||||
f"-DBUILD_IFCGEOM={OFF_ON['IfcGeom' in targets]}",
|
||||
f"-DBUILD_GEOMSERVER={OFF_ON['IfcGeomServer' in targets]}",
|
||||
f"-DBUILD_CONVERT={OFF_ON['IfcConvert' in targets]}",
|
||||
*ifcos_build_args,
|
||||
f"-DBUILD_IFCPYTHON=OFF",
|
||||
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/ifcopenshell",
|
||||
]
|
||||
|
||||
run_cmake("", exec_args + cmake_args + get_cmake_args_prefix_path(), cmake_dir=CMAKE_DIR, cwd=executables_dir)
|
||||
run_cmake("", exec_args + cmake_args + get_cmake_args_prefix_path(), cmake_dir=CMAKE_DIR, cwd=ifcos_build_dir)
|
||||
|
||||
logger.info("\rBuilding executables... ")
|
||||
|
||||
run([make, f"-j{IFCOS_NUM_BUILD_PROCS}", "VERBOSE=1"], cwd=executables_dir)
|
||||
run([make, "install/strip" if BUILD_CFG == "Release" else "install"], cwd=executables_dir)
|
||||
run([make, f"-j{IFCOS_NUM_BUILD_PROCS}", "VERBOSE=1"], cwd=ifcos_build_dir)
|
||||
run([make, "install/strip" if BUILD_CFG == "Release" else "install"], cwd=ifcos_build_dir)
|
||||
|
||||
if "IfcOpenShell-Python" in targets:
|
||||
# On OSX the actual Python library is not linked against.
|
||||
ADDITIONAL_ARGS = ""
|
||||
wrapper_ldflags = ""
|
||||
if platform.system() == "Darwin":
|
||||
ADDITIONAL_ARGS = "-Wl,-undefined,dynamic_lookup"
|
||||
|
||||
# NOTE: We don't use `CXXFLAGS` for wrappers, so wrapper is compiled with different flags
|
||||
# (e.g. ` -fdata-sections` is missing, which is set by default for executables)
|
||||
# So cache doesn't match and running build-all.py builds most of ifcopenshell libraries twice.
|
||||
os.environ["CPPFLAGS"] = f"{CXXFLAGS_MINIMAL} {ADDITIONAL_ARGS}"
|
||||
os.environ["CXXFLAGS"] = f"{CXXFLAGS_MINIMAL} {ADDITIONAL_ARGS}"
|
||||
os.environ["CFLAGS"] = f"{CFLAGS_MINIMAL} {ADDITIONAL_ARGS}"
|
||||
os.environ["LDFLAGS"] = f"{LDFLAGS} {ADDITIONAL_ARGS}"
|
||||
|
||||
python_dir = os.path.join(IFCOS_DIR, "pythonwrapper")
|
||||
os.makedirs(python_dir, exist_ok=True)
|
||||
# On OSX the actual Python library is not linked against.
|
||||
wrapper_ldflags = "-Wl,-undefined,dynamic_lookup"
|
||||
|
||||
def compile_python_wrapper(
|
||||
python_version: str,
|
||||
@@ -1464,10 +1510,6 @@ if "IfcOpenShell-Python" in targets:
|
||||
|
||||
logger.info(f"\rConfiguring python {python_version} wrapper...")
|
||||
|
||||
cache_path = os.path.join(python_dir, "CMakeCache.txt")
|
||||
if os.path.exists(cache_path):
|
||||
os.remove(cache_path)
|
||||
|
||||
if python_path:
|
||||
# We couldn't just prefix PATH and have to provide all variables explicitly,
|
||||
# see ifcwrap/cmake for the details.
|
||||
@@ -1481,27 +1523,38 @@ if "IfcOpenShell-Python" in targets:
|
||||
)
|
||||
|
||||
assert python_include
|
||||
run_cmake(
|
||||
"",
|
||||
cmake_args
|
||||
+ get_cmake_args_prefix_path()
|
||||
+ [
|
||||
*([f"-DPYTHON_EXECUTABLE={python_executable}"] if python_executable else []),
|
||||
# Needed because pyodide is expecting setup.py to be in the root.
|
||||
*([f"-DPYTHON_MODULE_INSTALL_DIR={REPO_PATH}"] * WASM),
|
||||
f"-DPYTHON_INCLUDE_DIR={python_include}",
|
||||
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/ifcopenshell/tmp",
|
||||
"-DUSERSPACE_PYTHON_PREFIX="
|
||||
+ ["Off", "On"][os.environ.get("PYTHON_USER_SITE", "").lower() in {"1", "on", "true"}],
|
||||
],
|
||||
cmake_dir=CMAKE_DIR,
|
||||
cwd=python_dir,
|
||||
)
|
||||
old_ldflags = os.environ["LDFLAGS"]
|
||||
if wrapper_ldflags:
|
||||
os.environ["LDFLAGS"] = f"{old_ldflags} {wrapper_ldflags}"
|
||||
|
||||
try:
|
||||
run_cmake(
|
||||
"",
|
||||
ifcos_build_args
|
||||
+ [
|
||||
"-DBUILD_IFCPYTHON=ON",
|
||||
]
|
||||
+ cmake_args
|
||||
+ get_cmake_args_prefix_path()
|
||||
+ [
|
||||
*([f"-DPYTHON_EXECUTABLE={python_executable}"] if python_executable else []),
|
||||
# Needed because pyodide is expecting setup.py to be in the root.
|
||||
*([f"-DPYTHON_MODULE_INSTALL_DIR={REPO_PATH}"] * WASM),
|
||||
f"-DPYTHON_INCLUDE_DIR={python_include}",
|
||||
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/ifcopenshell/tmp",
|
||||
"-DUSERSPACE_PYTHON_PREFIX="
|
||||
+ ["Off", "On"][os.environ.get("PYTHON_USER_SITE", "").lower() in {"1", "on", "true"}],
|
||||
],
|
||||
cmake_dir=CMAKE_DIR,
|
||||
cwd=ifcos_build_dir,
|
||||
)
|
||||
finally:
|
||||
os.environ["LDFLAGS"] = old_ldflags
|
||||
|
||||
logger.info(f"\rBuilding python {python_version} wrapper... ")
|
||||
|
||||
run([make, f"-j{IFCOS_NUM_BUILD_PROCS}", "ifcopenshell_wrapper", "VERBOSE=1"], cwd=python_dir)
|
||||
run([make, "install/local"], cwd=os.path.join(python_dir, "ifcwrap"))
|
||||
run([make, f"-j{IFCOS_NUM_BUILD_PROCS}", "ifcopenshell_wrapper", "VERBOSE=1"], cwd=ifcos_build_dir)
|
||||
run([make, "install/local"], cwd=os.path.join(ifcos_build_dir, "ifcwrap"))
|
||||
|
||||
if python_executable:
|
||||
run([python_executable, "-m", "ensurepip"])
|
||||
@@ -1516,12 +1569,14 @@ if "IfcOpenShell-Python" in targets:
|
||||
|
||||
if platform.system() != "Darwin":
|
||||
if BUILD_CFG == "Release":
|
||||
# TODO: This symbol name depends on the Python version?
|
||||
so = glob.glob(os.path.join(module_dir, "_ifcopenshell_wrapper*.so"))[0]
|
||||
if "wasm" in flags:
|
||||
run(["wasm-strip", so, "-k", "dylink.0"])
|
||||
else:
|
||||
run([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", so], cwd=module_dir)
|
||||
for so in glob.glob(os.path.join(module_dir, "*.so")):
|
||||
if "wasm" in flags:
|
||||
run(["wasm-strip", so, "-k", "dylink.0"])
|
||||
elif os.path.basename(so).startswith("_ifcopenshell_wrapper"):
|
||||
# TODO: This symbol name depends on the Python version?
|
||||
run([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", so], cwd=module_dir)
|
||||
else:
|
||||
run([strip, "--strip-unneeded", so], cwd=module_dir)
|
||||
|
||||
return module_dir
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# /// script
|
||||
# ///
|
||||
"""
|
||||
Cache built dependencies for builds.
|
||||
|
||||
@@ -68,7 +66,6 @@ def unpack_dependencies(install_dir: Path) -> None:
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
action = None
|
||||
if len(sys.argv) != 2 or (action := sys.argv[1].lower()) not in ("pack", "unpack"):
|
||||
print(__doc__)
|
||||
sys.exit(1)
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
Fixes configure failing to find a working compiler under GCC 15's default
|
||||
-std=gnu23 (upstream fix: https://gmplib.org/repo/gmp/rev/8e7bb4ae7a18).
|
||||
|
||||
Upstream fix is patching `acinclude.m4`, but since in the release tarball
|
||||
all macros are already expanded to `configure` script, so we're patching
|
||||
all occurrences of that macro.
|
||||
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -6568,7 +6568,7 @@
|
||||
|
||||
#if defined (__GNUC__) && ! defined (__cplusplus)
|
||||
typedef unsigned long long t1;typedef t1*t2;
|
||||
-void g(){}
|
||||
+void g(int,t1 const*,t1,t2,t1 const*,int){}
|
||||
void h(){}
|
||||
static __inline__ t1 e(t2 rp,t2 up,int n,t1 v0)
|
||||
{t1 c,x,r;int i;if(v0){c=1;for(i=1;i<n;i++){x=up[i];r=x+1;rp[i]=r;}}return c;}
|
||||
@@ -8187,7 +8187,7 @@
|
||||
|
||||
#if defined (__GNUC__) && ! defined (__cplusplus)
|
||||
typedef unsigned long long t1;typedef t1*t2;
|
||||
-void g(){}
|
||||
+void g(int,t1 const*,t1,t2,t1 const*,int){}
|
||||
void h(){}
|
||||
static __inline__ t1 e(t2 rp,t2 up,int n,t1 v0)
|
||||
{t1 c,x,r;int i;if(v0){c=1;for(i=1;i<n;i++){x=up[i];r=x+1;rp[i]=r;}}return c;}
|
||||
@@ -0,0 +1,17 @@
|
||||
# This file was generated with the assistance of an AI coding tool.
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 42e403b..764562f 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -249,11 +249,6 @@ set_source_files_properties(
|
||||
PROPERTIES GENERATED TRUE
|
||||
)
|
||||
|
||||
-# If it's an EMSCRIPTEN build, we're done
|
||||
-if(EMSCRIPTEN)
|
||||
- return()
|
||||
-endif()
|
||||
-
|
||||
# CMake exports
|
||||
configure_file(
|
||||
cmake/manifoldConfig.cmake.in
|
||||
@@ -0,0 +1,32 @@
|
||||
http://git.dev.opencascade.org/gitweb/?p=occt.git;a=commitdiff;h=0ab4e621833f4eae945a3762c9a29ee12e2eec53#patch1
|
||||
diff --git a/src/HLRBRep/HLRBRep_InternalAlgo.cxx b/src/HLRBRep/HLRBRep_InternalAlgo.cxx
|
||||
index ca885ca..c13cb06 100644 (file)
|
||||
--- a/src/HLRBRep/HLRBRep_InternalAlgo.cxx
|
||||
+++ b/src/HLRBRep/HLRBRep_InternalAlgo.cxx
|
||||
@@ -165,7 +165,7 @@ void HLRBRep_InternalAlgo::Update ()
|
||||
SB.Bounds(v1,v2,e1,e2,f1,f2);
|
||||
|
||||
for (Standard_Integer e = e1; e <= e2; e++) {
|
||||
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
|
||||
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
|
||||
HLRAlgo::DecodeMinMax(ed.MinMax(), TheMin, TheMax);
|
||||
if (FirstTime) {
|
||||
FirstTime = Standard_False;
|
||||
@@ -307,7 +307,7 @@ void HLRBRep_InternalAlgo::InitEdgeStatus ()
|
||||
Standard_Integer nf = myDS->NbFaces();
|
||||
|
||||
for (Standard_Integer e = 1; e <= ne; e++) {
|
||||
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
|
||||
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
|
||||
if (ed.Selected()) ed.Status().ShowAll();
|
||||
}
|
||||
// for (Standard_Integer f = 1; f <= nf; f++) {
|
||||
@@ -368,7 +368,7 @@ void HLRBRep_InternalAlgo::Select ()
|
||||
Standard_Integer nf = myDS->NbFaces();
|
||||
|
||||
for (Standard_Integer e = 1; e <= ne; e++) {
|
||||
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
|
||||
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
|
||||
ed.Selected(Standard_True);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
From a0deb4ce8b43cf3c8b8c0a4225c6be5296446dbd Mon Sep 17 00:00:00 2001
|
||||
From: Adam Eri <adam.eri@blackmirror.media>
|
||||
Date: Tue, 3 Sep 2019 23:30:20 +0200
|
||||
Subject: [PATCH] Resolves compile error on macOS
|
||||
|
||||
Resolves "no member named 'isnan' in namespace 'std'" on macOS
|
||||
---
|
||||
GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp b/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp
|
||||
index 1f9a3eef..dd6f5c59 100644
|
||||
--- a/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp
|
||||
+++ b/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "GeneratedSaxParserUtils.h"
|
||||
#include <math.h>
|
||||
+#include <cmath>
|
||||
#include <memory>
|
||||
#include <string.h>
|
||||
#include <limits>
|
||||
@@ -34,7 +34,6 @@ environments:
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/gxx-13.3.0-h9576a4e_1.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-13.3.0-hdbfa832_1.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-13.3.0-h6834431_7.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.4-nompi_h2d575fe_105.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/imath-3.1.12-h7955e40_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/jxrlib-1.1-hd590300_3.conda
|
||||
@@ -149,7 +148,6 @@ environments:
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/freeimage-3.18.0-h7cd8ba8_22.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/freetype-2.12.1-h60636b9_2.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/gmp-6.3.0-hf036a51_2.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-1.14.4-nompi_h1607680_105.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/icu-75.1-h120a0e1_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/imath-3.1.12-h2016aa1_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/jxrlib-1.1-h10d778d_3.conda
|
||||
@@ -243,7 +241,6 @@ environments:
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/freeimage-3.18.0-h8310ca0_22.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/freetype-2.12.1-hdaf720e_2.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/gmp-6.3.0-hfeafd45_2.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/hdf5-1.14.4-nompi_hd5d9e70_105.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/imath-3.1.12-hbb528cf_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/intel-openmp-2024.2.1-h57928b3_1083.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/jxrlib-1.1-hcfcfb64_3.conda
|
||||
@@ -349,7 +346,6 @@ environments:
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/gxx-13.3.0-h9576a4e_1.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-13.3.0-hdbfa832_1.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-13.3.0-h6834431_7.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.4-nompi_h2d575fe_105.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/imath-3.1.12-h7955e40_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/jxrlib-1.1-hd590300_3.conda
|
||||
@@ -464,7 +460,6 @@ environments:
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/freeimage-3.18.0-h7cd8ba8_22.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/freetype-2.12.1-h60636b9_2.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/gmp-6.3.0-hf036a51_2.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-1.14.4-nompi_h1607680_105.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/icu-75.1-h120a0e1_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/imath-3.1.12-h2016aa1_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/jxrlib-1.1-h10d778d_3.conda
|
||||
@@ -558,7 +553,6 @@ environments:
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/freeimage-3.18.0-h8310ca0_22.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/freetype-2.12.1-hdaf720e_2.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/gmp-6.3.0-hfeafd45_2.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/hdf5-1.14.4-nompi_hd5d9e70_105.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/imath-3.1.12-hbb528cf_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/intel-openmp-2024.2.1-h57928b3_1083.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/jxrlib-1.1-hcfcfb64_3.conda
|
||||
@@ -743,7 +737,6 @@ environments:
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/gxx-13.3.0-h9576a4e_1.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-13.3.0-hdbfa832_1.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-13.3.0-h6834431_7.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.4-nompi_h2d575fe_105.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/imath-3.1.12-h7955e40_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/jxrlib-1.1-hd590300_3.conda
|
||||
@@ -858,7 +851,6 @@ environments:
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/freeimage-3.18.0-h7cd8ba8_22.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/freetype-2.12.1-h60636b9_2.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/gmp-6.3.0-hf036a51_2.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-1.14.4-nompi_h1607680_105.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/icu-75.1-h120a0e1_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/imath-3.1.12-h2016aa1_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/jxrlib-1.1-h10d778d_3.conda
|
||||
@@ -952,7 +944,6 @@ environments:
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/freeimage-3.18.0-h8310ca0_22.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/freetype-2.12.1-hdaf720e_2.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/gmp-6.3.0-hfeafd45_2.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/hdf5-1.14.4-nompi_hd5d9e70_105.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/imath-3.1.12-hbb528cf_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/intel-openmp-2024.2.1-h57928b3_1083.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/jxrlib-1.1-hcfcfb64_3.conda
|
||||
@@ -1068,7 +1059,6 @@ environments:
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-14.3.0-he663afc_4.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-14.3.0-ha7acb78_11.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h6e4c0c1_103.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda
|
||||
@@ -1239,7 +1229,6 @@ environments:
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/geos-3.13.1-h502464c_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/gmp-6.3.0-hf036a51_2.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-1.14.6-nompi_hc8237f9_103.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/icu-75.1-h120a0e1_0.conda
|
||||
@@ -1380,7 +1369,6 @@ environments:
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/geos-3.13.1-h9ea8674_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/gmp-6.3.0-hfeafd45_2.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/hdf5-1.14.6-nompi_he30205f_103.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
|
||||
- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_1.conda
|
||||
@@ -2990,106 +2978,6 @@ packages:
|
||||
- pkg:pypi/h2?source=compressed-mapping
|
||||
size: 95967
|
||||
timestamp: 1756364871835
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.4-nompi_h2d575fe_105.conda
|
||||
sha256: 93d2bfc672f3ee0988d277ce463330a467f3686d3f7ee37812a3d8ca11776d77
|
||||
md5: d76fff0092b6389a12134ddebc0929bd
|
||||
depends:
|
||||
- __glibc >=2.17,<3.0.a0
|
||||
- libaec >=1.1.3,<2.0a0
|
||||
- libcurl >=8.10.1,<9.0a0
|
||||
- libgcc >=13
|
||||
- libgfortran
|
||||
- libgfortran5 >=13.3.0
|
||||
- libstdcxx >=13
|
||||
- libzlib >=1.3.1,<2.0a0
|
||||
- openssl >=3.4.0,<4.0a0
|
||||
license: BSD-3-Clause
|
||||
license_family: BSD
|
||||
size: 3950601
|
||||
timestamp: 1733003331788
|
||||
- conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h6e4c0c1_103.conda
|
||||
sha256: 4f173af9e2299de7eee1af3d79e851bca28ee71e7426b377e841648b51d48614
|
||||
md5: c74d83614aec66227ae5199d98852aaf
|
||||
depends:
|
||||
- __glibc >=2.17,<3.0.a0
|
||||
- libaec >=1.1.4,<2.0a0
|
||||
- libcurl >=8.14.1,<9.0a0
|
||||
- libgcc >=14
|
||||
- libgfortran
|
||||
- libgfortran5 >=14.3.0
|
||||
- libstdcxx >=14
|
||||
- libzlib >=1.3.1,<2.0a0
|
||||
- openssl >=3.5.1,<4.0a0
|
||||
license: BSD-3-Clause
|
||||
license_family: BSD
|
||||
purls: []
|
||||
size: 3710057
|
||||
timestamp: 1753357500665
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-1.14.4-nompi_h1607680_105.conda
|
||||
sha256: 56500937894b1ca917e1ae1bea64b873a9eec57d581173579189d0b1f590db26
|
||||
md5: 12ebafc40b10d4bf519e4c2074c52aef
|
||||
depends:
|
||||
- __osx >=10.13
|
||||
- libaec >=1.1.3,<2.0a0
|
||||
- libcurl >=8.10.1,<9.0a0
|
||||
- libcxx >=18
|
||||
- libgfortran 5.*
|
||||
- libgfortran5 >=13.2.0
|
||||
- libzlib >=1.3.1,<2.0a0
|
||||
- openssl >=3.4.0,<4.0a0
|
||||
license: BSD-3-Clause
|
||||
license_family: BSD
|
||||
size: 3732340
|
||||
timestamp: 1733003702265
|
||||
- conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-1.14.6-nompi_hc8237f9_103.conda
|
||||
sha256: e41d22f672b1fbe713d22cf69630abffaee68bdb38a500a708fc70e6f639357f
|
||||
md5: 3f1df98f96e0c369d94232712c9b87d0
|
||||
depends:
|
||||
- __osx >=10.13
|
||||
- libaec >=1.1.4,<2.0a0
|
||||
- libcurl >=8.14.1,<9.0a0
|
||||
- libcxx >=19
|
||||
- libgfortran
|
||||
- libgfortran5 >=14.3.0
|
||||
- libgfortran5 >=15.1.0
|
||||
- libzlib >=1.3.1,<2.0a0
|
||||
- openssl >=3.5.1,<4.0a0
|
||||
license: BSD-3-Clause
|
||||
license_family: BSD
|
||||
purls: []
|
||||
size: 3522832
|
||||
timestamp: 1753358062940
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/hdf5-1.14.4-nompi_hd5d9e70_105.conda
|
||||
sha256: e8ced65c604a3b9e4803758a25149d71d8096f186fe876817a0d1d97190550c0
|
||||
md5: 4381be33460283890c34341ecfa42d97
|
||||
depends:
|
||||
- libaec >=1.1.3,<2.0a0
|
||||
- libcurl >=8.10.1,<9.0a0
|
||||
- libzlib >=1.3.1,<2.0a0
|
||||
- openssl >=3.4.0,<4.0a0
|
||||
- ucrt >=10.0.20348.0
|
||||
- vc >=14.2,<15
|
||||
- vc14_runtime >=14.29.30139
|
||||
license: BSD-3-Clause
|
||||
license_family: BSD
|
||||
size: 2048450
|
||||
timestamp: 1733003052575
|
||||
- conda: https://conda.anaconda.org/conda-forge/win-64/hdf5-1.14.6-nompi_he30205f_103.conda
|
||||
sha256: 0a90263b97e9860cec6c2540160ff1a1fff2a609b3d96452f8716ae63489dac5
|
||||
md5: f1f7aaf642cefd2190582550eaca4658
|
||||
depends:
|
||||
- libaec >=1.1.4,<2.0a0
|
||||
- libcurl >=8.14.1,<9.0a0
|
||||
- libzlib >=1.3.1,<2.0a0
|
||||
- openssl >=3.5.1,<4.0a0
|
||||
- ucrt >=10.0.20348.0
|
||||
- vc >=14.3,<15
|
||||
- vc14_runtime >=14.44.35208
|
||||
license: BSD-3-Clause
|
||||
license_family: BSD
|
||||
purls: []
|
||||
size: 2031491
|
||||
timestamp: 1753357255237
|
||||
- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda
|
||||
sha256: 6ad78a180576c706aabeb5b4c8ceb97c0cb25f1e112d76495bff23e3779948ba
|
||||
md5: 0a802cb9888dd14eeefc611f05c40b6e
|
||||
|
||||
@@ -31,7 +31,6 @@ occt = { version = "*", build = "*novtk*" }
|
||||
cgal-cpp = "*"
|
||||
numpy = "*"
|
||||
lark = "*"
|
||||
hdf5 = "*"
|
||||
eigen = "*"
|
||||
mpfr = "*"
|
||||
gmp = "*"
|
||||
|
||||
@@ -35,6 +35,12 @@ sed -i s/0.8.0/$VERSION/g packages/ifcopenshell/meta.yaml
|
||||
# Otherwise pyodide build path typically includes package version, so cached cmake configs might break.
|
||||
export BUILD_DIR=`readlink -f ifcopenshell_build`
|
||||
|
||||
# Sat, 25 Apr 2026 12:11:39 GMT 2026-04-25 12:11:39,173 - DEBUG - running
|
||||
# command `make -j5 ifcopenshell_wrapper VERBOSE=1` in directory
|
||||
# '/home/runner/work/IfcOpenShell/IfcOpenShell/ifcopenshell_build/Linux/wasm/build/ifcopenshell/build'
|
||||
# Sat, 25 Apr 2026 12:18:01 GMT Error: Process completed with exit code 143.
|
||||
export IFCOS_NUM_BUILD_PROCS=1
|
||||
|
||||
# Use build-recipes-no-deps first, so logs would be printed to stdout.
|
||||
pyodide build-recipes-no-deps ifcopenshell
|
||||
pyodide build-recipes ifcopenshell --install
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python3
|
||||
# This file was generated with the assistance of an AI coding tool.
|
||||
"""Order Pyodide wheel shared objects so wasm side modules load safely."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
SCHEMA_ORDER = {
|
||||
"ifc2x3": 0,
|
||||
"ifc4": 1,
|
||||
"ifc4x1": 2,
|
||||
"ifc4x2": 3,
|
||||
"ifc4x3": 4,
|
||||
"ifc4x3_add1": 5,
|
||||
"ifc4x3_add2": 6,
|
||||
}
|
||||
|
||||
MAIN_SHARED_OBJECT_RE = re.compile(r"^_ifcopenshell_wrapper(?:\.|$)")
|
||||
SCHEMA_PLUGIN_RE = re.compile(r"^ifcopenshell\.parse\.schema\.([^.]+)\.so$")
|
||||
MAPPING_PLUGIN_RE = re.compile(r"^ifcopenshell\.geometry\.mapping\.([^.]+)\.so$")
|
||||
DOCUMENT_PLUGIN_RE = re.compile(r"^ifcopenshell\.document\.[^.]+\.([^.]+)\.so$")
|
||||
GEOMETRY_SERIALIZATION_PLUGIN_RE = re.compile(r"^ifcopenshell\.geometry\.serialization\.([^.]+)\.so$")
|
||||
|
||||
|
||||
def schema_key(schema: str) -> tuple[int, str]:
|
||||
schema = schema.lower()
|
||||
return SCHEMA_ORDER.get(schema, len(SCHEMA_ORDER)), schema
|
||||
|
||||
|
||||
def shared_object_sort_key(filename: str, index: int) -> tuple[int, tuple[int, str], str, int]:
|
||||
basename = Path(filename).name
|
||||
if MAIN_SHARED_OBJECT_RE.match(basename):
|
||||
return 0, schema_key(""), basename, index
|
||||
|
||||
if match := SCHEMA_PLUGIN_RE.match(basename):
|
||||
return 1, schema_key(match.group(1)), basename, index
|
||||
|
||||
if match := MAPPING_PLUGIN_RE.match(basename):
|
||||
return 2, schema_key(match.group(1)), basename, index
|
||||
|
||||
if match := DOCUMENT_PLUGIN_RE.match(basename):
|
||||
return 3, schema_key(match.group(1)), basename, index
|
||||
|
||||
if match := GEOMETRY_SERIALIZATION_PLUGIN_RE.match(basename):
|
||||
return 4, schema_key(match.group(1)), basename, index
|
||||
|
||||
return 5, schema_key(""), basename, index
|
||||
|
||||
|
||||
def ordered_infos(infos: list[zipfile.ZipInfo]) -> list[zipfile.ZipInfo]:
|
||||
shared_infos = [(index, info) for index, info in enumerate(infos) if info.filename.endswith(".so")]
|
||||
ordered_shared_infos = [
|
||||
info for index, info in sorted(shared_infos, key=lambda item: shared_object_sort_key(item[1].filename, item[0]))
|
||||
]
|
||||
ordered_shared_iter = iter(ordered_shared_infos)
|
||||
return [next(ordered_shared_iter) if info.filename.endswith(".so") else info for info in infos]
|
||||
|
||||
|
||||
def zip_info_for_write(source: zipfile.ZipInfo) -> zipfile.ZipInfo:
|
||||
info = zipfile.ZipInfo(source.filename)
|
||||
info.date_time = source.date_time
|
||||
info.compress_type = source.compress_type
|
||||
info.comment = source.comment
|
||||
info.create_system = source.create_system
|
||||
info.external_attr = source.external_attr
|
||||
info.extra = source.extra
|
||||
return info
|
||||
|
||||
|
||||
def shared_object_names(infos: list[zipfile.ZipInfo]) -> list[str]:
|
||||
return [info.filename for info in infos if info.filename.endswith(".so")]
|
||||
|
||||
|
||||
def rewrite_wheel(wheel: Path, ordered: list[zipfile.ZipInfo]) -> None:
|
||||
fd, temp_name = tempfile.mkstemp(prefix=f".{wheel.name}.", suffix=".tmp", dir=wheel.parent)
|
||||
os.close(fd)
|
||||
temp_path = Path(temp_name)
|
||||
try:
|
||||
with zipfile.ZipFile(wheel) as zin, zipfile.ZipFile(
|
||||
temp_path, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9
|
||||
) as zout:
|
||||
for info in ordered:
|
||||
zout.writestr(zip_info_for_write(info), zin.read(info))
|
||||
os.replace(temp_path, wheel)
|
||||
finally:
|
||||
if temp_path.exists():
|
||||
temp_path.unlink()
|
||||
|
||||
|
||||
def order_wheel(wheel: Path, check: bool) -> bool:
|
||||
wheel = wheel.resolve()
|
||||
if wheel.suffix != ".whl":
|
||||
raise ValueError(f"not a wheel: {wheel}")
|
||||
|
||||
with zipfile.ZipFile(wheel) as zf:
|
||||
infos = zf.infolist()
|
||||
|
||||
ordered = ordered_infos(infos)
|
||||
changed = shared_object_names(infos) != shared_object_names(ordered)
|
||||
if check:
|
||||
if changed:
|
||||
print(f"{wheel}: shared object order needs updating")
|
||||
return False
|
||||
print(f"{wheel}: shared object order is already valid")
|
||||
return True
|
||||
|
||||
if changed:
|
||||
rewrite_wheel(wheel, ordered)
|
||||
print(f"{wheel}: reordered shared objects")
|
||||
else:
|
||||
print(f"{wheel}: shared object order is already valid")
|
||||
return True
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("wheel", type=Path, help="Wheel to rewrite in place")
|
||||
parser.add_argument("--check", action="store_true", help="Only validate the current shared object order")
|
||||
args = parser.parse_args()
|
||||
|
||||
return 0 if order_wheel(args.wheel, args.check) else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,297 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Split optional IfcOpenShell Pyodide payloads into separate wheels."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import csv
|
||||
import hashlib
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import zipfile
|
||||
from email.parser import Parser
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
MAIN_SHARED_OBJECT_RE = re.compile(r"(^|/)_ifcopenshell_wrapper(?:\.|$)")
|
||||
PURE_PYTHON_PACKAGE_NAME = "ifcopenshell-pure-python"
|
||||
PURE_PYTHON_PREFIXES = (
|
||||
"ifcopenshell/api/",
|
||||
"ifcopenshell/express/",
|
||||
"ifcopenshell/mvd/",
|
||||
"ifcopenshell/simple_spf/",
|
||||
)
|
||||
|
||||
|
||||
def wheel_parts(path: Path) -> tuple[str, str, str, str, str]:
|
||||
if path.suffix != ".whl":
|
||||
raise ValueError(f"not a wheel: {path}")
|
||||
stem = path.name[:-4]
|
||||
left, py_tag, abi_tag, platform_tag = stem.rsplit("-", 3)
|
||||
dist, version = left.rsplit("-", 1)
|
||||
return dist, version, py_tag, abi_tag, platform_tag
|
||||
|
||||
|
||||
def safe_name(name: str) -> str:
|
||||
return re.sub(r"[-_.]+", "-", name).lower().strip("-")
|
||||
|
||||
|
||||
def wheel_escape(value: str) -> str:
|
||||
return re.sub(r"[^\w\d.]+", "_", value, flags=re.UNICODE)
|
||||
|
||||
|
||||
def wheel_version_escape(value: str) -> str:
|
||||
return re.sub(r"[^\w\d.+]+", "_", value, flags=re.UNICODE)
|
||||
|
||||
|
||||
def dist_info_dir(name: str, version: str) -> str:
|
||||
return f"{wheel_escape(name)}-{wheel_version_escape(version)}.dist-info"
|
||||
|
||||
|
||||
def sha256_record_value(data: bytes) -> str:
|
||||
digest = hashlib.sha256(data).digest()
|
||||
return "sha256=" + base64.urlsafe_b64encode(digest).decode("ascii").rstrip("=")
|
||||
|
||||
|
||||
def make_info(name: str, *, source: zipfile.ZipInfo | None = None, mode: int | None = None) -> zipfile.ZipInfo:
|
||||
info = zipfile.ZipInfo(name)
|
||||
if source is not None:
|
||||
info.date_time = source.date_time
|
||||
info.external_attr = source.external_attr
|
||||
info.comment = source.comment
|
||||
info.create_system = source.create_system
|
||||
else:
|
||||
info.date_time = time.localtime(time.time())[:6]
|
||||
info.external_attr = ((mode if mode is not None else 0o644) & 0xFFFF) << 16
|
||||
info.create_system = 3
|
||||
info.compress_type = zipfile.ZIP_DEFLATED
|
||||
return info
|
||||
|
||||
|
||||
def write_record(zf: zipfile.ZipFile, entries: dict[str, bytes | None], record_name: str) -> None:
|
||||
rows: list[list[str]] = []
|
||||
for name in sorted(entries):
|
||||
data = entries[name]
|
||||
if name == record_name:
|
||||
rows.append([name, "", ""])
|
||||
elif data is None:
|
||||
raise ValueError(f"missing bytes for RECORD entry {name}")
|
||||
else:
|
||||
rows.append([name, sha256_record_value(data), str(len(data))])
|
||||
|
||||
buf = io.StringIO(newline="")
|
||||
writer = csv.writer(buf, lineterminator="\n")
|
||||
writer.writerows(rows)
|
||||
zf.writestr(make_info(record_name), buf.getvalue().encode("utf-8"))
|
||||
|
||||
|
||||
def read_original_metadata(zf: zipfile.ZipFile) -> tuple[str, str, str]:
|
||||
metadata_names = [n for n in zf.namelist() if n.endswith(".dist-info/METADATA")]
|
||||
wheel_names = [n for n in zf.namelist() if n.endswith(".dist-info/WHEEL")]
|
||||
record_names = [n for n in zf.namelist() if n.endswith(".dist-info/RECORD")]
|
||||
if len(metadata_names) != 1 or len(wheel_names) != 1 or len(record_names) != 1:
|
||||
raise ValueError("expected exactly one METADATA, WHEEL, and RECORD in the source wheel")
|
||||
return metadata_names[0], wheel_names[0], record_names[0]
|
||||
|
||||
|
||||
def shared_package_name(so_path: str) -> str:
|
||||
stem = Path(so_path).name.removesuffix(".so")
|
||||
stem = re.sub(r"[^A-Za-z0-9]+", "-", stem).strip("-")
|
||||
return safe_name(stem)
|
||||
|
||||
|
||||
def is_pure_python_split_path(path: str) -> bool:
|
||||
return any(path.startswith(prefix) for prefix in PURE_PYTHON_PREFIXES)
|
||||
|
||||
|
||||
def build_wheel(
|
||||
output_dir: Path,
|
||||
package_name: str,
|
||||
version: str,
|
||||
tag: str,
|
||||
root_is_purelib: bool,
|
||||
summary: str,
|
||||
payloads: list[tuple[zipfile.ZipInfo, bytes]],
|
||||
license_files: dict[str, bytes],
|
||||
) -> Path:
|
||||
di = dist_info_dir(package_name, version)
|
||||
wheel_name = f"{wheel_escape(package_name)}-{wheel_version_escape(version)}-{tag}.whl"
|
||||
out = output_dir / wheel_name
|
||||
record_name = f"{di}/RECORD"
|
||||
entries: dict[str, bytes | None] = {}
|
||||
|
||||
metadata = (
|
||||
"Metadata-Version: 2.4\n"
|
||||
f"Name: {package_name}\n"
|
||||
f"Version: {version}\n"
|
||||
f"Summary: {summary}\n"
|
||||
"License-File: COPYING\n"
|
||||
"License-File: COPYING.LESSER\n"
|
||||
"\n"
|
||||
).encode("utf-8")
|
||||
wheel = (
|
||||
"Wheel-Version: 1.0\n"
|
||||
"Generator: split_pyodide_ifcopenshell_wheel.py\n"
|
||||
f"Root-Is-Purelib: {str(root_is_purelib).lower()}\n"
|
||||
f"Tag: {tag}\n"
|
||||
"\n"
|
||||
).encode("utf-8")
|
||||
|
||||
with zipfile.ZipFile(out, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as zf:
|
||||
for info, data in payloads:
|
||||
zf.writestr(make_info(info.filename, source=info), data)
|
||||
entries[info.filename] = data
|
||||
|
||||
metadata_name = f"{di}/METADATA"
|
||||
wheel_meta_name = f"{di}/WHEEL"
|
||||
zf.writestr(make_info(metadata_name), metadata)
|
||||
zf.writestr(make_info(wheel_meta_name), wheel)
|
||||
entries[metadata_name] = metadata
|
||||
entries[wheel_meta_name] = wheel
|
||||
|
||||
for basename, data in license_files.items():
|
||||
name = f"{di}/licenses/{basename}"
|
||||
zf.writestr(make_info(name), data)
|
||||
entries[name] = data
|
||||
|
||||
entries[record_name] = None
|
||||
write_record(zf, entries, record_name)
|
||||
return out
|
||||
|
||||
|
||||
def rewrite_main_wheel(source: Path, target: Path, split_paths: set[str]) -> None:
|
||||
with zipfile.ZipFile(source) as zin, zipfile.ZipFile(
|
||||
target, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9
|
||||
) as zout:
|
||||
_, _, record_name = read_original_metadata(zin)
|
||||
entries: dict[str, bytes | None] = {}
|
||||
for info in zin.infolist():
|
||||
if info.filename in split_paths or info.filename == record_name:
|
||||
continue
|
||||
data = zin.read(info.filename)
|
||||
zout.writestr(make_info(info.filename, source=info), data)
|
||||
entries[info.filename] = data
|
||||
entries[record_name] = None
|
||||
write_record(zout, entries, record_name)
|
||||
|
||||
|
||||
def verify_wheel(path: Path) -> None:
|
||||
with zipfile.ZipFile(path) as zf:
|
||||
zf.testzip()
|
||||
metadata_name, wheel_name, record_name = read_original_metadata(zf)
|
||||
Parser().parsestr(zf.read(metadata_name).decode("utf-8"))
|
||||
wheel_text = zf.read(wheel_name).decode("utf-8")
|
||||
if "Wheel-Version:" not in wheel_text or "Tag:" not in wheel_text:
|
||||
raise ValueError(f"invalid WHEEL metadata in {path}")
|
||||
|
||||
record_rows = list(csv.reader(io.StringIO(zf.read(record_name).decode("utf-8"))))
|
||||
names = {row[0] for row in record_rows}
|
||||
missing = set(zf.namelist()) - names
|
||||
if missing:
|
||||
raise ValueError(f"{path} RECORD is missing entries: {sorted(missing)[:5]}")
|
||||
for name, digest, size in record_rows:
|
||||
if name == record_name:
|
||||
continue
|
||||
data = zf.read(name)
|
||||
if digest != sha256_record_value(data) or size != str(len(data)):
|
||||
raise ValueError(f"{path} RECORD mismatch for {name}")
|
||||
|
||||
|
||||
def split_wheel(wheel_path: Path, output_dir: Path) -> None:
|
||||
wheel_path = wheel_path.expanduser().resolve()
|
||||
if not wheel_path.exists():
|
||||
raise FileNotFoundError(wheel_path)
|
||||
|
||||
output_dir = output_dir.expanduser().resolve()
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
main_wheel_path = output_dir / wheel_path.name
|
||||
if main_wheel_path.resolve(strict=False) == wheel_path:
|
||||
raise ValueError("output directory must not point to the input wheel location")
|
||||
|
||||
_, version, py_tag, abi_tag, platform_tag = wheel_parts(wheel_path)
|
||||
binary_tag = f"{py_tag}-{abi_tag}-{platform_tag}"
|
||||
pure_tag = "py3-none-any"
|
||||
|
||||
with zipfile.ZipFile(wheel_path) as zf:
|
||||
file_infos = [info for info in zf.infolist() if not info.is_dir()]
|
||||
so_infos = [info for info in file_infos if info.filename.endswith(".so")]
|
||||
split_so_infos = [info for info in so_infos if not MAIN_SHARED_OBJECT_RE.search(Path(info.filename).name)]
|
||||
pure_python_infos = [info for info in file_infos if is_pure_python_split_path(info.filename)]
|
||||
if not split_so_infos and not pure_python_infos:
|
||||
raise RuntimeError("no secondary .so files or pure Python subpackages found to split")
|
||||
|
||||
license_files = {
|
||||
Path(info.filename).name: zf.read(info.filename)
|
||||
for info in file_infos
|
||||
if ".dist-info/licenses/" in info.filename
|
||||
}
|
||||
split_so_payloads = [(info, zf.read(info.filename)) for info in split_so_infos]
|
||||
pure_python_payloads = [(info, zf.read(info.filename)) for info in pure_python_infos]
|
||||
|
||||
created_wheels: list[Path] = []
|
||||
for info, data in split_so_payloads:
|
||||
package_name = shared_package_name(info.filename)
|
||||
created_wheels.append(
|
||||
build_wheel(
|
||||
output_dir,
|
||||
package_name,
|
||||
version,
|
||||
binary_tag,
|
||||
False,
|
||||
f"Pyodide shared library split from IfcOpenShell ({Path(info.filename).name}).",
|
||||
[(info, data)],
|
||||
license_files,
|
||||
)
|
||||
)
|
||||
|
||||
if pure_python_payloads:
|
||||
created_wheels.append(
|
||||
build_wheel(
|
||||
output_dir,
|
||||
PURE_PYTHON_PACKAGE_NAME,
|
||||
version,
|
||||
pure_tag,
|
||||
True,
|
||||
"Pure Python subpackages split from IfcOpenShell.",
|
||||
pure_python_payloads,
|
||||
license_files,
|
||||
)
|
||||
)
|
||||
|
||||
temp_main_wheel = output_dir / f".{wheel_path.name}.tmp"
|
||||
try:
|
||||
rewrite_main_wheel(
|
||||
wheel_path,
|
||||
temp_main_wheel,
|
||||
{info.filename for info, _ in split_so_payloads + pure_python_payloads},
|
||||
)
|
||||
verify_wheel(temp_main_wheel)
|
||||
for created in created_wheels:
|
||||
verify_wheel(created)
|
||||
os.replace(temp_main_wheel, main_wheel_path)
|
||||
finally:
|
||||
if temp_main_wheel.exists():
|
||||
temp_main_wheel.unlink()
|
||||
|
||||
|
||||
def parse_args(argv: list[str]) -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Extract optional IfcOpenShell Pyodide payloads into separate wheel artifacts."
|
||||
)
|
||||
parser.add_argument("wheel", help="IfcOpenShell Pyodide wheel to split")
|
||||
parser.add_argument("output_dir", help="Directory for generated wheels")
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
args = parse_args(sys.argv[1:] if argv is None else argv)
|
||||
split_wheel(Path(args.wheel), Path(args.output_dir))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -14,6 +14,8 @@ def test_ifcopenshell_import(selenium):
|
||||
import micropip
|
||||
await micropip.install(f"./{WHEEL_FILENAME}")
|
||||
import ifcopenshell
|
||||
from pathlib import Path
|
||||
ifcopenshell.set_plugin_search_paths([str(Path(ifcopenshell.__file__).parent)])
|
||||
ifc_file = ifcopenshell.file()
|
||||
wall = ifc_file.create_entity("IfcWall")
|
||||
wall1 = ifc_file.by_type("IfcWall")[0]
|
||||
|
||||
+94
-43
@@ -1,8 +1,13 @@
|
||||
[project]
|
||||
name = "IfcOpenShell"
|
||||
version = "0.0.0"
|
||||
# Don't provide requires-python explicitly
|
||||
# allowing pyprojects to set their own (e.g. bonsai and general ifcopenshell version differ).
|
||||
dependencies = [
|
||||
"black==26.3.1",
|
||||
"ruff==0.15.9",
|
||||
"poethepoet",
|
||||
"ty==0.0.29",
|
||||
"gersemi==0.26.1",
|
||||
]
|
||||
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
@@ -38,7 +43,6 @@ exclude = [
|
||||
# then they will be inherited by projects' .toml files.
|
||||
# This allows using assuming different Python version for different projects.
|
||||
[tool.ruff]
|
||||
line-length = 120
|
||||
exclude = [
|
||||
# Submodules.
|
||||
"src/ifcopenshell-python/ifcopenshell/express",
|
||||
@@ -79,36 +83,92 @@ ignore = [
|
||||
]
|
||||
|
||||
[tool.ty.rules]
|
||||
all = "error"
|
||||
all = "ignore"
|
||||
|
||||
# Structural rules (no deep type inference needed, easier to adapt).
|
||||
# Maybe later, requires to specify element types for all generics.
|
||||
missing-type-argument = "ignore"
|
||||
# Conflicts with `bpy` props defined using annotations.
|
||||
invalid-type-form = "ignore"
|
||||
abstract-method-in-final-class = "error"
|
||||
ambiguous-protocol-member = "error"
|
||||
conflicting-declarations = "error"
|
||||
conflicting-metaclass = "error"
|
||||
cyclic-class-definition = "error"
|
||||
cyclic-type-alias-definition = "error"
|
||||
dataclass-field-order = "error"
|
||||
duplicate-base = "error"
|
||||
duplicate-kw-only = "error"
|
||||
empty-body = "error"
|
||||
escape-character-in-forward-annotation = "error"
|
||||
final-on-non-method = "error"
|
||||
final-without-value = "error"
|
||||
ignore-comment-unknown-rule = "error"
|
||||
implicit-concatenated-string-type-annotation = "error"
|
||||
inconsistent-mro = "error"
|
||||
ineffective-final = "error"
|
||||
instance-layout-conflict = "error"
|
||||
invalid-dataclass = "error"
|
||||
invalid-dataclass-override = "error"
|
||||
invalid-enum-member-annotation = "error"
|
||||
invalid-explicit-override = "error"
|
||||
invalid-frozen-dataclass-subclass = "error"
|
||||
invalid-generic-class = "error"
|
||||
invalid-generic-enum = "error"
|
||||
invalid-ignore-comment = "error"
|
||||
invalid-legacy-positional-parameter = "error"
|
||||
invalid-legacy-type-variable = "error"
|
||||
invalid-named-tuple = "error"
|
||||
invalid-newtype = "error"
|
||||
invalid-overload = "error"
|
||||
invalid-paramspec = "error"
|
||||
invalid-protocol = "error"
|
||||
invalid-syntax-in-forward-annotation = "error"
|
||||
invalid-total-ordering = "error"
|
||||
invalid-type-alias-type = "error"
|
||||
invalid-type-checking-constant = "error"
|
||||
invalid-type-guard-definition = "error"
|
||||
invalid-type-variable-bound = "error"
|
||||
invalid-type-variable-constraints = "error"
|
||||
invalid-typed-dict-header = "error"
|
||||
invalid-typed-dict-statement = "error"
|
||||
override-of-final-method = "error"
|
||||
override-of-final-variable = "error"
|
||||
possibly-missing-import = "error"
|
||||
possibly-missing-submodule = "error"
|
||||
# Has false positives due to ty walrus operator bug.
|
||||
# possibly-unresolved-reference = "error"
|
||||
raw-string-type-annotation = "error"
|
||||
redundant-final-classvar = "error"
|
||||
shadowed-type-variable = "error"
|
||||
subclass-of-final-class = "error"
|
||||
super-call-in-named-tuple-method = "error"
|
||||
unavailable-implicit-super-arguments = "error"
|
||||
unbound-type-variable = "error"
|
||||
undefined-reveal = "error"
|
||||
unresolved-global = "error"
|
||||
unresolved-import = "error"
|
||||
unresolved-reference = "error"
|
||||
unused-ignore-comment = "error"
|
||||
unused-type-ignore-comment = "error"
|
||||
useless-overload-body = "error"
|
||||
|
||||
# Non-structural rules:
|
||||
deprecated = "error"
|
||||
zero-stepsize-in-slice = "error"
|
||||
possibly-missing-implicit-call = "error"
|
||||
unused-awaitable = "error"
|
||||
|
||||
# Function argument rules:
|
||||
# Conflicts with `ifcopenshell.api.geometry.add_representation` type of callables we have, confusing them with a module.
|
||||
call-non-callable = "ignore"
|
||||
# bpy is missing some context manager implementations.
|
||||
invalid-context-manager = "ignore"
|
||||
# Doesn't go well with `bpy.ops.xxx.yyy`.
|
||||
unresolved-attribute = "ignore"
|
||||
# call-non-callable = "error"
|
||||
conflicting-argument-forms = "error"
|
||||
# Too many false positives.
|
||||
invalid-argument-type = "ignore"
|
||||
invalid-method-override = "ignore"
|
||||
invalid-assignment = "ignore"
|
||||
invalid-parameter-default = "ignore"
|
||||
missing-override-decorator = "ignore"
|
||||
invalid-yield = "ignore"
|
||||
invalid-return-type = "ignore"
|
||||
non-callable-init-subclass = "ignore"
|
||||
not-iterable = "ignore"
|
||||
possibly-missing-attribute = "ignore"
|
||||
no-matching-overload = "ignore"
|
||||
not-subscriptable = "ignore"
|
||||
unsupported-dynamic-base = "ignore"
|
||||
unsupported-operator = "ignore"
|
||||
# invalid-argument-type = "error"
|
||||
missing-argument = "error"
|
||||
parameter-already-assigned = "error"
|
||||
positional-only-parameter-as-kwarg = "error"
|
||||
too-many-positional-arguments = "error"
|
||||
unknown-argument = "error"
|
||||
# Has a lot of warnings due to current ty walrus operator issues.
|
||||
# index-out-of-bounds = "error"
|
||||
# unresolved-attribute = "error"
|
||||
|
||||
[tool.ty.environment]
|
||||
extra-paths = [
|
||||
@@ -155,20 +215,10 @@ exclude = [
|
||||
|
||||
[tool.poe.tasks]
|
||||
|
||||
dev-setup.sequence = [
|
||||
# 3.13 is chosen because it's the version used in the latest Bonsai.
|
||||
{cmd = "uv sync --python 3.13"},
|
||||
{cmd = "uv pip install -e ./src/bsdd/"},
|
||||
{cmd = "uv pip install -e ./src/ifcopenshell-python/[advanced,dev]"},
|
||||
{cmd = "uv pip install -e ./src/ifcedit/"},
|
||||
{cmd = "uv pip install -e ./src/ifcpatch/"},
|
||||
{cmd = "uv pip install -e ./src/ifcquery/"},
|
||||
{cmd = "uv pip install -e './src/ifcmcp/[mcp]'"},
|
||||
{cmd = "uv pip install -r src/bonsai/requirements-dev.txt"},
|
||||
]
|
||||
dev-setup.help = "Install repo packages in editable mode"
|
||||
|
||||
ruff = "ruff check"
|
||||
ruff-main = "ruff check --extend-exclude nix/build-all.py"
|
||||
# It's actually Python 3.6, but ruff only supports 3.7+, but it should do.
|
||||
ruff-old = "ruff check nix/build-all.py --target-version py37"
|
||||
ruff.sequence = ["ruff-main", "ruff-old"]
|
||||
|
||||
black = "black ."
|
||||
|
||||
@@ -188,14 +238,14 @@ ty-venv-ios.sequence = [
|
||||
{cmd = "uv pip install -r src/ifcopenshell-python/type-check-requirements.txt --python=src/ifcopenshell-python/.venv"},
|
||||
]
|
||||
|
||||
format.sequence = ["black", "ruff"]
|
||||
format.sequence = ["black", "ruff-main", "ruff-old"]
|
||||
|
||||
cmake-format = "gersemi . --in-place"
|
||||
|
||||
[tool.poe.tasks.ty-ios]
|
||||
# --ignore unresolved-reference: walrus operator false positives in ty.
|
||||
cmd = """
|
||||
ty check
|
||||
nix/
|
||||
src/bcf
|
||||
src/bsdd
|
||||
src/ifc2ca
|
||||
@@ -210,6 +260,7 @@ cmd = """
|
||||
src/ifcpatch
|
||||
src/ifctester
|
||||
--python=src/ifcopenshell-python/.venv
|
||||
--ignore unresolved-reference
|
||||
"""
|
||||
|
||||
[tool.poe.tasks.bonsai-deps]
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
black==26.3.1
|
||||
ruff==0.16.0
|
||||
poethepoet
|
||||
ty==0.0.63
|
||||
gersemi==0.28.0
|
||||
@@ -316,7 +316,7 @@ def build_viewpoint(element: entity_instance) -> mdl.VisualizationInfo:
|
||||
Returns:
|
||||
The BCF viewpoint definition.
|
||||
"""
|
||||
ifc_file = element.wrapped_data.file
|
||||
ifc_file = element.file
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||
elem_placement = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)
|
||||
elem_placement[:3, 3] *= unit_scale
|
||||
|
||||
@@ -188,8 +188,6 @@ class BcfClient:
|
||||
response.raise_for_status()
|
||||
return response.status_code, response.text
|
||||
except requests.exceptions.HTTPError as errh:
|
||||
response = errh.response
|
||||
assert response is not None
|
||||
print(f"message: {response.reason}' '{response.status_code}, {errh}")
|
||||
return response.status_code, response.reason
|
||||
|
||||
@@ -208,8 +206,6 @@ class BcfClient:
|
||||
response.raise_for_status()
|
||||
return response.status_code, response.text
|
||||
except requests.exceptions.HTTPError as errh:
|
||||
response = errh.response
|
||||
assert response is not None
|
||||
print(f"message: {response.reason}' '{response.status_code}, {errh}")
|
||||
return response.status_code, response.reason
|
||||
|
||||
@@ -226,8 +222,6 @@ class BcfClient:
|
||||
response.raise_for_status()
|
||||
return response.status_code, response.text
|
||||
except requests.exceptions.HTTPError as errh:
|
||||
response = errh.response
|
||||
assert response is not None
|
||||
print(f"message: {response.reason}' '{response.status_code}, {errh}")
|
||||
return response.status_code, response.reason
|
||||
|
||||
|
||||
@@ -316,7 +316,7 @@ def build_viewpoint(element: entity_instance) -> mdl.VisualizationInfo:
|
||||
Returns:
|
||||
The BCF viewpoint definition.
|
||||
"""
|
||||
ifc_file = element.wrapped_data.file
|
||||
ifc_file = element.file
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||
elem_placement = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)
|
||||
elem_placement[:3, 3] *= unit_scale
|
||||
|
||||
+4
-12
@@ -17,8 +17,8 @@
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
SHELL := sh
|
||||
PYTHON:=python3
|
||||
PIP:=pip3
|
||||
PYTHON:=python3.11
|
||||
PIP:=pip3.11
|
||||
PATCH:=patch
|
||||
SED:=sed -i
|
||||
VENV_ACTIVATE:=bin/activate
|
||||
@@ -106,7 +106,7 @@ endif
|
||||
endif # def PLATFORM
|
||||
|
||||
# Current build commit hash.
|
||||
OLD:=3e7b739
|
||||
OLD:=1c5b825
|
||||
.PHONY: bump
|
||||
bump:
|
||||
ifndef NEW
|
||||
@@ -192,11 +192,7 @@ endif
|
||||
# Provides networkx graph analysis for project dependency calculations
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download networkx --dest=./wheels
|
||||
# Required by IFCDiff
|
||||
# Pinned <9.1: deepdiff 9.1.0 adds cachebox<6,>=5.2 which only ships macOS x86_64
|
||||
# wheels for macosx_10_12+ and is incompatible with our macos py311 --platform
|
||||
# macosx_10_10_x86_64 target. Revisit once the macos py311 platform tag is bumped
|
||||
# to 10_13 (matching py312/py313).
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download "deepdiff<9.1" --dest=./wheels
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download deepdiff --dest=./wheels
|
||||
# Required by IFCCSV and ifcopenshell.util.selector
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download lark --dest=./wheels
|
||||
# Required by IFC4D
|
||||
@@ -360,10 +356,6 @@ else
|
||||
pytest test/tool/test_$(MODULE).py --maxfail=1
|
||||
endif
|
||||
|
||||
.PHONY: test-modal
|
||||
test-modal:
|
||||
blender --enable-event-simulate --python test/modal/test_modal.py --window-maximized
|
||||
|
||||
# Reregistering test is not added to the standard test suite because during unregister
|
||||
# Blender removes all Bonsai dependencies breaking dev-environment symlinks.
|
||||
.PHONY: test-reregister
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This file was modified with the assistance of an AI coding tool.
|
||||
|
||||
import importlib
|
||||
import os
|
||||
@@ -27,7 +25,7 @@ import bpy
|
||||
import bpy.utils.previews
|
||||
from bpy_extras.io_utils import ExportHelper, ImportHelper
|
||||
|
||||
from . import handler, operator, parametric_lifecycle, prop, ui
|
||||
from . import handler, operator, prop, ui
|
||||
|
||||
try:
|
||||
from bonsai.translations import translations_dict
|
||||
@@ -90,7 +88,6 @@ modules = {
|
||||
"web": None,
|
||||
"light": None,
|
||||
"alignment": None,
|
||||
"clip_box": None,
|
||||
# Uncomment this line to enable loading of the demo module. Happy hacking!
|
||||
# The name "demo" must correlate to a folder name in `bim/module/`.
|
||||
# "demo": None,
|
||||
@@ -160,6 +157,9 @@ classes = [
|
||||
ui.BIM_UL_tab_visibilities,
|
||||
ui.BIM_UL_panel_visibilities,
|
||||
ui.DocPreferences,
|
||||
ui.GizmoPreferencesDoor, # Register before GizmoPreferences
|
||||
ui.GizmoPreferencesWindow, # Register before GizmoPreferences
|
||||
ui.GizmoPreferencesStair, # Register before GizmoPreferences
|
||||
ui.GizmoPreferences,
|
||||
# ui.DefaultParameters and ui.BIM_ADDON_preferences are registered separately after modules (see late_classes below)
|
||||
# Tabs panel
|
||||
@@ -268,8 +268,6 @@ def register():
|
||||
bpy.app.handlers.depsgraph_update_post.append(on_register)
|
||||
bpy.app.handlers.undo_post.append(handler.undo_post)
|
||||
bpy.app.handlers.redo_post.append(handler.redo_post)
|
||||
# Must follow the two appends above so regenerators see restored IFC state.
|
||||
parametric_lifecycle.install_parametric_lifecycle_handlers()
|
||||
bpy.app.handlers.load_post.append(handler.load_post)
|
||||
bpy.app.handlers.load_post.append(handler.loadIfcStore)
|
||||
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
|
||||
@@ -327,7 +325,6 @@ def unregister():
|
||||
|
||||
unregister_classes(classes)
|
||||
|
||||
parametric_lifecycle.uninstall_parametric_lifecycle_handlers()
|
||||
bpy.app.handlers.load_post.remove(handler.load_post)
|
||||
bpy.app.handlers.load_post.remove(handler.loadIfcStore)
|
||||
del bpy.types.Scene.BIMProperties
|
||||
|
||||
@@ -24,28 +24,10 @@ a text, a tspan { fill: blue !important; text-decoration: underline;}
|
||||
a:hover { cursor: pointer; }
|
||||
.cut { fill: black; stroke: black; stroke-linecap: 'round'; stroke-width: 0.35; fill-rule: evenodd; }
|
||||
.projection { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; }
|
||||
/* SVG edge classification (issue #3668): see edge-classification.md. These select directly on
|
||||
the <path> element (each classified projection edge carries its own class), so they win over
|
||||
the inherited .projection rule above regardless of specificity. */
|
||||
path.outline { stroke: black; stroke-width: 0.35; stroke-opacity: 1; }
|
||||
path.boundary { stroke: black; stroke-width: 0.3; stroke-opacity: 0.9; }
|
||||
path.crease { stroke: black; stroke-width: 0.25; stroke-opacity: 0.85; }
|
||||
path.sharp { stroke: black; stroke-width: 0.18; stroke-opacity: 0.7; }
|
||||
path.flush { stroke: black; stroke-width: 0.1; stroke-opacity: 0.4; }
|
||||
|
||||
/* Debug CSS for troubleshooting edge classification */
|
||||
/*
|
||||
path.outline { stroke: black; stroke-width: 0.35; stroke-opacity: 1; }
|
||||
path.boundary { stroke: orange; stroke-width: 0.3; stroke-opacity: 0.9; }
|
||||
path.crease { stroke: green; stroke-width: 0.25; stroke-opacity: 0.85; }
|
||||
path.sharp { stroke: red; stroke-width: 0.18; stroke-opacity: 0.7; }
|
||||
path.flush { stroke: blue; stroke-width: 0.1; stroke-opacity: 0.4; }
|
||||
*/
|
||||
|
||||
.surface {fill: white; stroke-width: 0.1;}
|
||||
.annotation { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 0.3; }
|
||||
.IfcAnnotation { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 0.3; }
|
||||
/* .IfcGeographicElement { fill: none; stroke: rgb(150, 150, 150); stroke-linecap: 'round'; stroke-dasharray: 1, 2;} */
|
||||
.surface { stroke: none; fill: #fff; fill-rule: evenodd; }
|
||||
.annotation { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; }
|
||||
.IfcAnnotation { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; }
|
||||
.IfcGeographicElement { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 1; }
|
||||
.PredefinedType-LINEWORK { stroke: black; stroke-width: 0.25; }
|
||||
.PredefinedType-LINEWORK.dashed { stroke-dasharray: 3, 2; }
|
||||
.PredefinedType-LINEWORK.fine { stroke-width: 0.18; stroke: #777777; }
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
This cache folder contains .h5 files. These files cache IFC geometry for performance only. You may safely clear the contents of this cache folder without losing data.
|
||||
@@ -1,96 +0,0 @@
|
||||
Copyright (c) 2011-2012, Nikita Volchenkov (<nikitavolchenkov@gmail.com>),
|
||||
with Reserved Font Name OpenGost Type B.
|
||||
|
||||
Copyright (c) 2012, Valek Filippov (<frob@gnome.org>).
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -5,7 +5,7 @@ FILE_NAME('EPset_Drawing.ifc','2020-01-01T00:00:00',$,$,'EPset_Drawing','EPset_D
|
||||
FILE_SCHEMA(('IFC4'));
|
||||
ENDSEC;
|
||||
DATA;
|
||||
#1=IFCPROPERTYSETTEMPLATE('2JhNIvqZrFnAgxfhK0XVQX',$,'EPset_Drawing','',.PSET_OCCURRENCEDRIVEN.,'IfcAnnotation/DRAWING',(#23,#22,#27,#24,#29,#30,#19,#12,#26,#9,#8,#7,#6,#4,#18,#11,#5,#20,#25,#14,#10,#17,#28,#16,#3,#21,#13,#15,#2,#31,#32,#33,#34,#35,#36,#37));
|
||||
#1=IFCPROPERTYSETTEMPLATE('2JhNIvqZrFnAgxfhK0XVQX',$,'EPset_Drawing','',.PSET_OCCURRENCEDRIVEN.,'IfcAnnotation/DRAWING',(#23,#22,#27,#24,#19,#12,#26,#9,#8,#7,#6,#4,#18,#11,#5,#20,#25,#14,#10,#17,#28,#16,#3,#21,#13,#15,#2));
|
||||
#2=IFCSIMPLEPROPERTYTEMPLATE('23JavTMk98ZxXhrUEnjAcf',$,'TargetView','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#3=IFCSIMPLEPROPERTYTEMPLATE('1yVWUt5H9DAOuu0OaMMLpe',$,'Scale','The scale of this drawing represented as a numerator and denominator, such as 1/100',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#4=IFCSIMPLEPROPERTYTEMPLATE('3gsuPBtU93b8f0gg1pjkq6',$,'HumanScale','The scale of this drawing in human readable format, such as 1:100',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
@@ -33,14 +33,5 @@ DATA;
|
||||
#26=IFCSIMPLEPROPERTYTEMPLATE('2iwERDOW55Pf4hCbuFRe1Q',$,'FillMode','Method to fill areas seen in projection',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#27=IFCSIMPLEPROPERTYTEMPLATE('1YF$qLzBzF19Io8aB2N8cE',$,'CutMode','Method for cutting geometry',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#28=IFCSIMPLEPROPERTYTEMPLATE('1YSnFzurrEyRNtoLdmmddP',$,'BringToFront','The objects with these SVG classes will render in front of all other objects.Ex: IfcBeam, IfcColumn',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
#29=IFCSIMPLEPROPERTYTEMPLATE('0lP6Y8q9v2QhDnR4sT7uVx',$,'PerspectiveShiftX','Horizontal perspective camera shift stored as drawing metadata using Blender camera shift units.',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
|
||||
#30=IFCSIMPLEPROPERTYTEMPLATE('2mR8b1NcW5EoFyG7hJ9kLp',$,'PerspectiveShiftY','Vertical perspective camera shift stored as drawing metadata using Blender camera shift units.',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
|
||||
#31=IFCSIMPLEPROPERTYTEMPLATE('1cFVJnqT13m8ItkMHaI1tp',$,'UseEdgeClassification','Enable the boundary/outline/sharp/crease/flush SVG edge classification scheme (issue #3668). When false, drawings use the original unclassified linework.',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||
#32=IFCSIMPLEPROPERTYTEMPLATE('2kB$mxBgnBUvhjh0Ti0c4P',$,'RenderCreases','Whether to render ''crease'' (concave) edges. Only relevant when UseEdgeClassification is enabled.',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||
#33=IFCSIMPLEPROPERTYTEMPLATE('3MSIJNW$T8r9Hl12kk0BY$',$,'ValleyAngleMinDegrees','Minimum concave dihedral deviation from flat, in degrees, for a projection edge to be classified as ''crease'' rather than ''flush''.',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
|
||||
#34=IFCSIMPLEPROPERTYTEMPLATE('2epSGfC4bFM9gb1X7zBIp4',$,'RenderSharp','Whether to render ''sharp'' (convex) edges. Only relevant when UseEdgeClassification is enabled.',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||
#35=IFCSIMPLEPROPERTYTEMPLATE('3TZwsEjkr5WRDKcgrYzSIA',$,'RidgeAngleMinDegrees','Minimum convex dihedral deviation from flat, in degrees, for a projection edge to be classified as ''sharp'' rather than ''flush''.',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
|
||||
#36=IFCSIMPLEPROPERTYTEMPLATE('2Jua$lO754vgZOkBoHM2gA',$,'RenderFlush','Whether to render ''flush'' edges (dihedral deviation below both ridge/valley thresholds). Only relevant when UseEdgeClassification is enabled.',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||
#37=IFCSIMPLEPROPERTYTEMPLATE('1zM9sia2L8RQDnWZxgUwlZ',$,'JoinClasses','Comma separated list of IFC classes whose cut linework will be joined together when they meet (e.g. mitred at a corner).\X2\000A\X0\Defaults to ''IfcWall,IfcSlab'' if not set. Override to also join other classes, such as ''IfcWall,IfcSlab,IfcCovering''.',.P_SINGLEVALUE.,'IfcText',$,$,$,$,$,.READWRITE.);
|
||||
ENDSEC;
|
||||
END-ISO-10303-21;
|
||||
|
||||
@@ -10,7 +10,6 @@ if bonsai_lib_path:
|
||||
import argparse
|
||||
import base64
|
||||
import json
|
||||
import urllib.parse
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import pystache
|
||||
@@ -19,53 +18,8 @@ from aiohttp import web
|
||||
|
||||
sio_port = 8080 # default port
|
||||
|
||||
|
||||
def get_asset_version() -> str:
|
||||
"""A cache-busting token appended to locally served static asset URLs.
|
||||
|
||||
Browsers otherwise keep serving a stale cached copy of static/js and
|
||||
static/css after Bonsai ships a code change, until the user does a hard
|
||||
refresh. Using the Bonsai version (which includes the build's commit
|
||||
hash) means the token changes on every shipped update.
|
||||
"""
|
||||
if bonsai_version:
|
||||
return urllib.parse.quote(bonsai_version, safe="")
|
||||
# Fallback for standalone runs without BONSAI_VERSION set (e.g. running
|
||||
# sioserver.py directly outside of Blender): derive a token from the
|
||||
# newest mtime among the static assets, so it still changes whenever the
|
||||
# shipped files change.
|
||||
static_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "static")
|
||||
latest_mtime = 0
|
||||
for root, _dirs, files in os.walk(static_dir):
|
||||
for name in files:
|
||||
latest_mtime = max(latest_mtime, int(os.path.getmtime(os.path.join(root, name))))
|
||||
return f"dev-{latest_mtime}"
|
||||
|
||||
|
||||
asset_version = get_asset_version()
|
||||
|
||||
|
||||
@web.middleware
|
||||
async def no_cache_static_middleware(request: web.Request, handler):
|
||||
"""Force revalidation of locally served static assets.
|
||||
|
||||
Query-string version stamping (see `asset_version`) busts the cache for
|
||||
the HTML-referenced entry points, but JS files that statically import
|
||||
other local modules (e.g. cost.js/gantt.js importing utilities/costui.js)
|
||||
reference those modules by an un-stamped relative path. Marking all
|
||||
/static/ and /jsgantt/ responses as no-cache makes browsers always
|
||||
revalidate with the server (a cheap conditional GET / 304 when nothing
|
||||
changed), so nested imports also pick up shipped changes without
|
||||
requiring a hard refresh.
|
||||
"""
|
||||
response = await handler(request)
|
||||
if request.path.startswith("/static/") or request.path.startswith("/jsgantt/"):
|
||||
response.headers["Cache-Control"] = "no-cache, must-revalidate"
|
||||
return response
|
||||
|
||||
|
||||
sio = socketio.AsyncServer(cors_allowed_origins="*", async_mode="aiohttp", max_http_buffer_size=10000000)
|
||||
app = web.Application(middlewares=[no_cache_static_middleware])
|
||||
app = web.Application()
|
||||
sio.attach(app)
|
||||
|
||||
|
||||
@@ -245,28 +199,28 @@ class BlenderNamespace(socketio.AsyncNamespace):
|
||||
async def schedules(request):
|
||||
with open("templates/index.html", "r") as f:
|
||||
template = f.read()
|
||||
html_content = pystache.render(template, {"port": sio_port, "version": bonsai_version, "v": asset_version})
|
||||
html_content = pystache.render(template, {"port": sio_port, "version": bonsai_version})
|
||||
return web.Response(text=html_content, content_type="text/html")
|
||||
|
||||
|
||||
async def costing(request):
|
||||
with open("templates/costing.html", "r") as f:
|
||||
template = f.read()
|
||||
html_content = pystache.render(template, {"port": sio_port, "version": bonsai_version, "v": asset_version})
|
||||
html_content = pystache.render(template, {"port": sio_port, "version": bonsai_version})
|
||||
return web.Response(text=html_content, content_type="text/html")
|
||||
|
||||
|
||||
async def sequencing(request):
|
||||
with open("templates/gantt.html", "r") as f:
|
||||
template = f.read()
|
||||
html_content = pystache.render(template, {"port": sio_port, "version": bonsai_version, "v": asset_version})
|
||||
html_content = pystache.render(template, {"port": sio_port, "version": bonsai_version})
|
||||
return web.Response(text=html_content, content_type="text/html")
|
||||
|
||||
|
||||
async def documentation(request):
|
||||
with open("templates/drawings.html", "r") as f:
|
||||
template = f.read()
|
||||
html_content = pystache.render(template, {"port": sio_port, "version": bonsai_version, "v": asset_version})
|
||||
html_content = pystache.render(template, {"port": sio_port, "version": bonsai_version})
|
||||
return web.Response(text=html_content, content_type="text/html")
|
||||
|
||||
|
||||
@@ -275,7 +229,7 @@ async def documentation(request):
|
||||
async def demo(request):
|
||||
with open("templates/demo.html", "r") as f:
|
||||
template = f.read()
|
||||
html_content = pystache.render(template, {"port": sio_port, "version": bonsai_version, "v": asset_version})
|
||||
html_content = pystache.render(template, {"port": sio_port, "version": bonsai_version})
|
||||
return web.Response(text=html_content, content_type="text/html")
|
||||
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ function addGanttElement(blenderId, tasks, workSched, filename) {
|
||||
vShowTaskInfoLink: 1, // Show link in tool tip (0/1)
|
||||
vShowEndWeekDate: 0, // Show/Hide the date for the last day of the week in header for daily
|
||||
vUseSingleCell: 10000, // Set the threshold cell per table row (Helps performance for large data.
|
||||
vFormatArr: ["Hour", "Day", "Week", "Month", "Quarter"], // vUseSingleCell keeps Hour usable on large charts.
|
||||
vFormatArr: ["Day", "Week", "Month", "Quarter"], // Even with setUseSingleCell using Hour format on such a large chart can cause issues in some browsers,
|
||||
vShowRes: true, // Disable the resource column.
|
||||
vShowComp: false, // Disable the completion column.
|
||||
vShowDur: false, // Disable the duration column, because jsgantt doesn't calculate durations the way we want.
|
||||
|
||||
@@ -250,14 +250,6 @@ export class CostUI {
|
||||
},
|
||||
});
|
||||
|
||||
CostUI.addRibbonButton({
|
||||
text: "Download CSV",
|
||||
icon: "fa-solid fa-file-csv",
|
||||
callback: () => {
|
||||
CostUI.downloadCsv();
|
||||
},
|
||||
});
|
||||
|
||||
CostUI.addRibbonButton({
|
||||
text: "Hide Schedules",
|
||||
icon: "fa-regular fa-eye-slash",
|
||||
@@ -531,81 +523,6 @@ export class CostUI {
|
||||
}
|
||||
}
|
||||
|
||||
static downloadCsv() {
|
||||
const tables = document.querySelectorAll("table[id^='cost-items-']");
|
||||
if (tables.length === 0) {
|
||||
alert("No cost schedule loaded to export!");
|
||||
return;
|
||||
}
|
||||
tables.forEach((table) => {
|
||||
const scheduleId = table.id.split("-").pop();
|
||||
const csv = CostUI.tableToCsv(table);
|
||||
if (csv === null) {
|
||||
return;
|
||||
}
|
||||
const nameEl = document.querySelector(
|
||||
"#cost-schedule-container-" + scheduleId + " .form-header span"
|
||||
);
|
||||
const scheduleName = nameEl
|
||||
? nameEl.textContent
|
||||
: "cost_schedule_" + scheduleId;
|
||||
CostUI.triggerCsvDownload(csv, scheduleName + ".csv");
|
||||
});
|
||||
}
|
||||
|
||||
static tableToCsv(table) {
|
||||
const escapeCsvCell = (value) => {
|
||||
const text = (value === null || value === undefined ? "" : value)
|
||||
.toString()
|
||||
.trim();
|
||||
if (/[",\n]/.test(text)) {
|
||||
return '"' + text.replace(/"/g, '""') + '"';
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
const cellText = (cell) => {
|
||||
const input = cell.querySelector("input");
|
||||
return input ? input.value : cell.innerText;
|
||||
};
|
||||
|
||||
// The Actions column only holds buttons (edit/delete/etc), not data.
|
||||
const isDataColumn = (column) => column && column !== "Actions";
|
||||
|
||||
const headerCells = Array.from(table.querySelectorAll("thead th")).filter(
|
||||
(th) => isDataColumn(th.getAttribute("data-column"))
|
||||
);
|
||||
if (headerCells.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rows = [headerCells.map((th) => escapeCsvCell(th.textContent)).join(",")];
|
||||
|
||||
table.querySelectorAll("tbody tr").forEach((row) => {
|
||||
const cells = Array.from(row.children).filter((cell) =>
|
||||
isDataColumn(cell.getAttribute("data-column"))
|
||||
);
|
||||
if (cells.length === 0) {
|
||||
return; // e.g. the "No cost items found" placeholder row.
|
||||
}
|
||||
rows.push(cells.map((cell) => escapeCsvCell(cellText(cell))).join(","));
|
||||
});
|
||||
|
||||
return rows.join("\n");
|
||||
}
|
||||
|
||||
static triggerCsvDownload(csvContent, filename) {
|
||||
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = filename;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
static createCostTable({ costSchedule, currency, callbacks }) {
|
||||
const preferences = CostUI.getColumnPreferences();
|
||||
const isScheduleOfRates = costSchedule.PredefinedType === "SCHEDULEOFRATES";
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="/static/css/cost.css?v={{v}}"
|
||||
href="/static/css/cost.css"
|
||||
id="index-stylesheet"
|
||||
/>
|
||||
<link
|
||||
@@ -21,7 +21,7 @@
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/static/js/jquery.min.js?v={{v}}"
|
||||
src="/static/js/jquery.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
@@ -34,7 +34,7 @@
|
||||
<script>
|
||||
var SOCKET_PORT = {{port}};
|
||||
</script>
|
||||
<script type="module" defer src="./static/js/cost.js?v={{v}}"></script>
|
||||
<script type="module" defer src="./static/js/cost.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
/>
|
||||
<!-- here we request the CSS file from the server, -->
|
||||
<!-- using registered static path in the server -->
|
||||
<link rel="stylesheet" href="/static/css/demo.css?v={{v}}" id="demo-stylesheet" />
|
||||
<link rel="stylesheet" href="/static/css/demo.css" id="demo-stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css"
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/static/js/jquery.min.js?v={{v}}"
|
||||
src="/static/js/jquery.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
@@ -33,7 +33,7 @@
|
||||
</script>
|
||||
<!-- here we request the JS file from the server-->
|
||||
<!-- using registered static path in the server -->
|
||||
<script defer src="./static/js/demo.js?v={{v}}"></script>
|
||||
<script defer src="./static/js/demo.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- the navigation bar at the top of the page. -->
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="/static/css/drawings.css?v={{v}}"
|
||||
href="/static/css/drawings.css"
|
||||
id="drawings-stylesheet"
|
||||
/>
|
||||
<link
|
||||
@@ -24,7 +24,7 @@
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/static/js/jquery.min.js?v={{v}}"
|
||||
src="/static/js/jquery.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
@@ -45,7 +45,7 @@
|
||||
<script>
|
||||
var SOCKET_PORT = {{port}};
|
||||
</script>
|
||||
<script defer src="./static/js/drawings.js?v={{v}}"></script>
|
||||
<script defer src="./static/js/drawings.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
|
||||
@@ -9,25 +9,25 @@
|
||||
type="image/x-icon"
|
||||
href="https://bonsaibim.org/assets/images/favicon-blender.png"
|
||||
/>
|
||||
<link rel="stylesheet" type="text/css" href="/jsgantt/jsgantt.css?v={{v}}" />
|
||||
<link rel="stylesheet" href="/static/css/gantt.css?v={{v}}" id="gantt-stylesheet" />
|
||||
<link rel="stylesheet" type="text/css" href="/jsgantt/jsgantt.css" />
|
||||
<link rel="stylesheet" href="/static/css/gantt.css" id="gantt-stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css"
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/static/js/jquery.min.js?v={{v}}"
|
||||
src="/static/js/jquery.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.socket.io/4.0.0/socket.io.min.js"
|
||||
></script>
|
||||
<script type="text/javascript" src="./jsgantt/jsgantt.js?v={{v}}"></script>
|
||||
<script type="text/javascript" src="./jsgantt/jsgantt.js"></script>
|
||||
<script>
|
||||
var SOCKET_PORT = {{port}};
|
||||
</script>
|
||||
<script type="module" defer src="./static/js/gantt.js?v={{v}}"></script>
|
||||
<script type="module" defer src="./static/js/gantt.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="no-print">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user