Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 60 additions & 58 deletions compile_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
name.lower()
for name in (
# Direct C/C++/Fortran/Rust extensions with no pure-Python distribution.
"av",
"cmake",
"cog",
"ifcopenshell",
Expand Down Expand Up @@ -75,6 +76,9 @@
"pydantic_core",
"watchfiles",
"lxml",
# Force pure-Python mypy (its wheels are mypyc-compiled, won't load under python_d).
# Keep the pin at 1.18.2; newer mypy needs the compiled-only librt.Let's w
"mypy",
)

# Sitecustomize shim installed at <libpack>/bin/Lib/site-packages/sitecustomize.py for
Expand Down Expand Up @@ -297,10 +301,9 @@ def __init__(
self.mode = mode
self.strict_mode = True

# Right now there are two packages where the version number gets coded into the path when: Boost and Coin:
# store those two separately from all the other paths we have to track
# Boost is the one package where the version number gets coded into the path, so store
# that path separately from all the other paths we have to track
self.boost_include_path = None
self.coin_cmake_path = None

def get_cmake_options(self) -> List[str]:
"""Get a comprehensive list of cMake options that can be used in any cMake build. Not all options apply
Expand Down Expand Up @@ -337,7 +340,6 @@ def get_cmake_options(self) -> List[str]:
f"-D HDF5_DIFF_EXECUTABLE={self.install_dir}/bin/hdf5diff" + to_exe(),
f"-D INSTALL_DIR={self.install_dir}",
f"-D PCRE2_LIBRARY={pcre_lib}",
"-D PIVY_USE_QT6=Yes",
f"-D pybind11_DIR={self.install_dir}/share/cmake/pybind11",
f"-D Python_ROOT_DIR={self.install_dir}/bin",
f"-D Python_DIR={self.install_dir}/bin",
Expand All @@ -350,8 +352,6 @@ def get_cmake_options(self) -> List[str]:
f"-D Qt6_DIR={self.install_dir}/lib/cmake/Qt6",
f"-D SWIG_EXECUTABLE={self.install_dir}/bin/swig" + to_exe(),
f"-D ZLIB_DIR={self.install_dir}/lib/cmake/",
"-D CMAKE_DISABLE_FIND_PACKAGE_SoQt=True",
# Absolutely never find SoQt (it's deprecated and we don't want it!)
]
if self.mode == BuildMode.DEBUG:
python_lib = self._python_lib_path()
Expand All @@ -372,8 +372,6 @@ def get_cmake_options(self) -> List[str]:
)
if self.boost_include_path:
base.append(f"-D Boost_INCLUDE_DIR={self.boost_include_path}")
if self.coin_cmake_path:
base.append(f"-D Coin_DIR={self.coin_cmake_path}")
if sys.platform.startswith("win32"):
inc_path = self.install_dir.replace("\\", "/")
cxx_flags = (
Expand Down Expand Up @@ -711,6 +709,14 @@ def build_python(self, args=None):
"."
)

# We ship the full stdlib in Lib/, but Windows Python auto-adds
# <bin>/python<major><minor>.zip to sys.path ahead of Lib/ whenever that file
# exists. A stale or partial such zip (for example one left in an incremental
# build tree) would shadow Lib/ and break stdlib imports, so remove it.
stdlib_zip = os.path.join(bin_dir, f"python{major}{minor}.zip")
if os.path.exists(stdlib_zip):
os.remove(stdlib_zip)

# Construct the list of files we expect to exist that need to be placed in the toplevel directory, or in
# libs:
move_to_bin = ["vcruntime"]
Expand Down Expand Up @@ -1168,13 +1174,22 @@ def build_qt(self, options: dict):
"-submodules",
",".join(submodules),
"-feature-opengl",
"-feature-zstd",
"-prefix",
self.install_dir,
"-opengl",
"desktop",
]
if self.mode == BuildMode.DEBUG:
init_command.append("-debug")
# Qt 6.11 has no bundled zstd, so WrapZSTD must locate the LibPack's own copy via its
# installed CMake config package. Point find_package(zstd CONFIG) directly at it.
# Requesting -feature-zstd above turns a missing zstd into a hard configure error rather
# than a silently disabled feature that would leave rcc unable to handle zstd resources.
init_command += [
"--",
f"-Dzstd_DIR={self.install_dir}/lib/cmake/zstd".replace("\\", "/"),
]
try:
self._run_streaming(init_command, "configure_log.txt")
except subprocess.CalledProcessError as e:
Expand Down Expand Up @@ -1401,41 +1416,6 @@ def _build_with_pip(self, options: dict):
exit(1)
self._pip_install(options["pip-install"])

def build_coin(self, _=None):
"""Builds and installs Coin using standard CMake settings"""
if self.skip_existing:
self._configure_coin_cmake_path()
if self.coin_cmake_path is not None:
print(" Not rebuilding Coin, it is already in the LibPack")
return
extra_args = ["-D COIN_BUILD_TESTS=Off"]
self._build_standard_cmake(extra_args)
self._configure_coin_cmake_path()

def _configure_coin_cmake_path(self):
"""Coin installs its cMake file into a directory named with the full version, so figure out what that is"""
start_crawl_at = os.path.join(self.install_dir, "lib", "cmake")
contents = [
f for f in os.listdir(start_crawl_at) if os.path.isdir(os.path.join(start_crawl_at, f))
]
for item in contents:
if item.startswith("Coin"):
self.coin_cmake_path = os.path.join(start_crawl_at, item)
break

def build_quarter(self, _=None):
"""Builds and installs Quarter using standard CMake settings"""
if self.skip_existing:
if os.path.exists(os.path.join(self.install_dir, "include", "Quarter")):
print(" Not rebuilding Quarter, it is already in the LibPack")
return
extra_args = [
"-D QUARTER_BUILD_EXAMPLES=Off",
"-D QUARTER_USE_QT5=Off",
"-D QUARTER_USE_QT6=On",
]
self._build_standard_cmake(extra_args=extra_args)

def build_zlib(self, _=None):
if self.skip_existing:
if os.path.exists(os.path.join(self.install_dir, "include", "zlib.h")):
Expand Down Expand Up @@ -1480,6 +1460,23 @@ def build_bzip2(self, _=None):
else:
raise NotImplemented("Non-Windows compilation of bzip2 is not implemented yet")

def build_expat(self, _=None):
if self.skip_existing:
if os.path.exists(os.path.join(self.install_dir, "include", "expat.h")):
print(" Not rebuilding expat, it is already in the LibPack")
return
# libexpat's CMake project lives in the expat/ subdirectory of the repository rather
# than at its root, so descend into it before running the standard CMake build.
os.chdir("expat")
extra_args = [
"-D EXPAT_BUILD_TOOLS=OFF",
"-D EXPAT_BUILD_EXAMPLES=OFF",
"-D EXPAT_BUILD_TESTS=OFF",
"-D EXPAT_BUILD_DOCS=OFF",
"-D EXPAT_SHARED_LIBS=ON",
]
self._build_standard_cmake(extra_args)

def build_pcre2(self, _=None):
if self.skip_existing:
if os.path.exists(os.path.join(self.install_dir, "include", "pcre2.h")):
Expand All @@ -1494,19 +1491,6 @@ def build_swig(self, _=None):
return
self._build_standard_cmake()

def build_pivy(self, _=None):
if self.skip_existing:
if os.path.exists(
os.path.join(self.install_dir, "bin", "Lib", "site-packages", "pivy")
):
print(" Not rebuilding pivy, it is already in the LibPack")
return
extra_args = []
self._build_standard_cmake(extra_args)
if self.mode == BuildMode.DEBUG:
base = os.path.join(self.install_dir, "bin", "Lib", "site-packages", "pivy")
os.rename(os.path.join(base, "_coin.pyd"), os.path.join(base, "_coin_d.pyd"))

def build_libclang(self, _=None):
"""libclang is provided as a platform-specific download by Qt."""
if self.skip_existing:
Expand Down Expand Up @@ -1611,6 +1595,22 @@ def build_libpng(self, _=None):
return
self._build_standard_cmake()

def build_zstd(self, _=None):
if self.skip_existing:
if os.path.exists(os.path.join(self.install_dir, "include", "zstd.h")):
print(" Not rebuilding zstd, it is already in the LibPack")
return
# Zstandard's CMake project lives in the build/cmake subdirectory of the repository
# rather than at its root, so descend into it before running the standard CMake build.
os.chdir(os.path.join("build", "cmake"))
extra_args = [
"-D ZSTD_BUILD_SHARED=ON",
"-D ZSTD_BUILD_STATIC=ON",
"-D ZSTD_BUILD_PROGRAMS=OFF",
"-D ZSTD_BUILD_TESTS=OFF",
]
self._build_standard_cmake(extra_args)

def build_pybind11(self, _=None):
if self.skip_existing:
if os.path.exists(os.path.join(self.install_dir, "include", "pybind11")):
Expand Down Expand Up @@ -2035,7 +2035,9 @@ def build_libfmt(self, _: None):
if os.path.exists(os.path.join(self.install_dir, "include", "fmt")):
print(" Not rebuilding libfmt, it is already in the LibPack")
return
extra_args = ["-D FMT_TEST=OFF", "-D FMT_DOC=OFF"]
# fmt 12.2.0 auto-enables FMT_MODULE under C++20/MSVC, exporting a broken fmt::fmt-module
# target that breaks find_package(fmt). FreeCAD uses fmt as a plain library, so disable it.
extra_args = ["-D FMT_TEST=OFF", "-D FMT_DOC=OFF", "-D FMT_MODULE=OFF"]
self._build_standard_cmake(extra_args)

def build_eigen3(self, _: None):
Expand Down Expand Up @@ -2076,7 +2078,7 @@ def build_opencamlib(self, _: None):
# ("opencamlib") under CMAKE_INSTALL_PREFIX, expecting either scikit-build to
# supply a wheel root or the build driver to point CMAKE_INSTALL_PREFIX at a
# site-packages directory (see src/pythonlib/pythonlib.cmake). Other Python
# C-extensions in this LibPack (for example pivy) detect Python_SITEARCH from
# C-extensions in this LibPack detect Python_SITEARCH from
# CMake's FindPython and install themselves into site-packages directly;
# opencamlib does not. To ensure it ends up in the right place we override the prefix
# for this one package so its "opencamlib" destination resolves under the
Expand Down
66 changes: 31 additions & 35 deletions config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"FreeCAD-version":"26.3.0",
"LibPack-version":"3.5.2",
"LibPack-version":"3.5.3",
"content": [
{
"name":"libiconv",
Expand Down Expand Up @@ -45,18 +45,25 @@
"git-repo":"https://github.com/glennrp/libpng",
"git-ref":"v1.6.58"
},
{
"name":"zstd",
"git-repo":"https://github.com/facebook/zstd",
"git-ref":"v1.5.7",
"note":"Zstandard. Qt 6.11 ships no bundled zstd; WrapZSTD requires an external one. Without it Qt configures with the zstd feature off, so the resource compiler (rcc) cannot produce or read zstd-compressed .qrc/.rcc resources, which breaks FreeCAD builds that use zstd resource compression. Built before Qt so build_qt can require FEATURE_zstd and fail loudly if it is ever missing again."
},
{
"name":"python",
"git-repo":"https://github.com/python/cpython.git",
"git-ref":"v3.14.5",
"git-ref":"v3.14.6",
"requirements": [
"annotated-types==0.7.0",
"anyio==4.13.0",
"anyio==4.14.1",
"attrs==23.2.0",
"certifi==2026.5.20",
"av==18.0.0",
"certifi==2026.6.17",
"charset-normalizer==3.4.7",
"click==8.4.1",
"cmake==4.3.2",
"click==8.4.2",
"cmake==4.3.4",
"cog==0.16.12",
"colorama==0.4.6",
"configparser==7.2.0",
Expand All @@ -65,7 +72,7 @@
"debugpy==1.8.21",
"definitions==0.2.0",
"defusedxml==0.7.1",
"elementpath==5.1.2",
"elementpath==5.1.3",
"fastapi==0.118.3",
"fonttools==4.63.0",
"h11==0.16.0",
Expand All @@ -78,41 +85,42 @@
"lark==1.3.1",
"lxml==6.1.1",
"matplotlib==3.11.0",
"mypy==1.18.2",
"nltk==3.9.4",
"numpy==2.4.6",
"numpy==2.5.0",
"packaging==26.2",
"pillow==12.2.0",
"pillow==12.3.0",
"ply==3.11",
"pycollada==0.9.3",
"pydantic==2.13.4",
"pydantic_core==2.46.4",
"pyparsing==3.3.2",
"pyshp==3.0.12",
"pyshp==3.1.4",
"pysolar==0.13",
"python-dateutil==2.9.0.post0",
"python-dotenv==1.2.2",
"PyYAML==6.0.3",
"regex==2026.5.9",
"regex==2026.6.28",
"requests==2.34.2",
"rpdb2==2.0.0.1.2",
"scipy==1.17.1",
"scipy==1.18.0",
"sets==0.3.2",
"setuptools==82.0.1",
"shapely==2.1.2; platform_machine != \"ARM64\"",
"six==1.17.0",
"sniffio==1.3.1",
"starlette==0.48.0",
"structlog==24.4.0",
"tqdm==4.68.2",
"tqdm==4.68.3",
"typing-inspection==0.4.2",
"typing_extensions==4.15.0",
"typing_extensions==4.16.0",
"urllib3==2.7.0",
"uvicorn==0.49.0",
"vermin==1.8.0",
"watchfiles==1.2.0",
"websockets==16.0",
"wheel==0.47.0",
"xmlschema==4.3.1"
"xmlschema==4.3.2"
]
},
{
Expand Down Expand Up @@ -142,17 +150,10 @@
"git-ref": "boost-1.91.0"
},
{
"name":"coin",
"git-repo":"https://github.com/coin3d/coin",
"git-ref": "v4.0.8",
"patches": ["patches/coin-01-cxx20-shared-ptr-unique.patch"],
"note": "That patch will not be needed in the next release of Coin, it's fixed upstream already"
},
{
"name":"quarter",
"git-repo":"https://github.com/coin3d/quarter",
"git-ref":"v1.2.3",
"patches":["patches/quarter-01-add-QOpenGLContext-to-QuarterWidgetP.patch"]
"name": "expat",
"git-repo": "https://github.com/libexpat/libexpat",
"git-ref": "R_2_8_2",
"note": "Required by FreeCAD's bundled Coin, which is forced to USE_EXTERNAL_EXPAT (see cMake/FreeCAD_Helpers/SetupCoin3D.cmake)"
},
{
"name":"pcre2",
Expand All @@ -164,16 +165,11 @@
"git-repo":"https://github.com/swig/swig.git",
"git-tag":"v4.4.1"
},
{
"name":"pivy",
"git-repo":"https://github.com/coin3d/pivy",
"git-ref":"0.6.11"
},
{
"name":"libclang",
"url-x64":"https://download.qt.io/development_releases/prebuilt/libclang/libclang-release_21.1.2-based-windows-vs2022_64.7z",
"url-ARM64":"https://download.qt.io/development_releases/prebuilt/libclang/libclang-release_21.1.2-based-windows-vs2022_arm64.7z",
"note":"Pinned at 21.1.2; 22.x triggers shiboken parser bugs that confuse same-named enums across sibling Qt classes (QLocalSocket vs QLocalServer SocketOption, QStringConverter::Default, etc.). Revisit after PySide 6.11.1 or later."
"url-x64":"https://download.qt.io/development_releases/prebuilt/libclang/libclang-release_22.1.8-based-windows-vs2022_64.7z",
"url-ARM64":"https://download.qt.io/development_releases/prebuilt/libclang/libclang-release_22.1.8-based-windows-vs2022_arm64.7z",
"note":"Bumped to 22.1.8 for LibPack 3.5.3. Previously held at 21.1.2 because 22.x triggered shiboken parser bugs that confused same-named enums across sibling Qt classes (QLocalSocket vs QLocalServer SocketOption, QStringConverter::Default, etc.). PySide 6.11 supports libclang 16-22 and Qt now ships the 22.1.8 prebuilt, so the revisit condition was met. Confirm the PySide/shiboken build is clean when validating this bump."
},
{
"name":"pyside",
Expand Down Expand Up @@ -271,7 +267,7 @@
{
"name":"libfmt",
"git-repo":"https://github.com/fmtlib/fmt",
"git-ref":"12.1.0"
"git-ref":"12.2.0"
},
{
"name": "yamlcpp",
Expand Down
4 changes: 4 additions & 0 deletions create_libpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,10 @@ def prevent_sleep_mode():
exit(1)
else:
compiler.init_script = [init_bat]
# Ignore the per-user site-packages, which the LibPack's Python shares with any
# same-version system Python; a user-installed setuptools there shadows our pinned
# copy and breaks setup.py-based steps (PySide/Shiboken).
os.environ["PYTHONNOUSERSITE"] = "1"
compiler.compile_all()

# Final cleanup: delete extraneous files and remove local path references from the cMake files
Expand Down
10 changes: 0 additions & 10 deletions patches/coin-01-cxx20-shared-ptr-unique.patch

This file was deleted.

Loading
Loading