mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 12:13:43 +00:00
bfce5b9415
Moving to Python to make Windows build scripts more maintainable. It's intended to be a drop-in replacement, so it should be possible to just switch `.\build-deps.cmd` to `python build-deps.py`, keeping exactly the same arguments and behaviour will be the same. `build-deps.cmd` is deprecated, but not yet removed, but will be shortly after more testing. Other batch files will be migrated to Python shortly after too.
1251 lines
44 KiB
Python
1251 lines
44 KiB
Python
# /// script
|
|
# [tool.ty.environment]
|
|
# root = ["."]
|
|
# ///
|
|
###############################################################################
|
|
# #
|
|
# 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/>. #
|
|
# #
|
|
###############################################################################
|
|
#
|
|
import os
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
from urllib.request import urlretrieve
|
|
|
|
from common import (
|
|
REPO_ROOT,
|
|
SCRIPT_DIR,
|
|
BuildCfg,
|
|
BuildDepsCache,
|
|
BuildType,
|
|
debug_or_release,
|
|
logger,
|
|
require_command,
|
|
run,
|
|
run_streamed,
|
|
)
|
|
from vs_cfg import CMAKE_GENERATORS, VS_TOOLSET_TO_VS_VER, VsCfgResult, get_vs_var
|
|
|
|
|
|
def build_cfg_marker_filepath(dependency_install_dir: Path, build_cfg: BuildCfg) -> Path:
|
|
return dependency_install_dir / f".{debug_or_release(build_cfg).lower()}_installation"
|
|
|
|
|
|
def is_already_installed(dependency_install_dir: Path, *, expected_build_cfg: BuildCfg | None = None) -> bool:
|
|
if not dependency_install_dir.exists():
|
|
return False
|
|
|
|
if expected_build_cfg is not None:
|
|
marker_filepath = build_cfg_marker_filepath(dependency_install_dir, expected_build_cfg)
|
|
if not marker_filepath.exists():
|
|
return False
|
|
|
|
logger.info(f"Found existing '{dependency_install_dir}', skipping")
|
|
return True
|
|
|
|
|
|
def mark_installation(installation_dir: Path, build_cfg: BuildCfg) -> None:
|
|
if not installation_dir.exists():
|
|
logger.error(f"Directory '{installation_dir}' does not exist.")
|
|
sys.exit(1)
|
|
|
|
marker_filepath = build_cfg_marker_filepath(installation_dir, build_cfg)
|
|
if marker_filepath.exists():
|
|
return
|
|
|
|
logger.info(f"Marking installation in '{installation_dir}' with '{marker_filepath.name}'.")
|
|
marker_filepath.touch()
|
|
|
|
|
|
def download_file(log_dependency_name: str, url: str, destination: Path) -> None:
|
|
destination = Path(destination)
|
|
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
if destination.exists():
|
|
logger.info(f"{log_dependency_name} already downloaded. Skipping.")
|
|
return
|
|
|
|
logger.info(f"Downloading {log_dependency_name} into '{destination.parent}'")
|
|
urlretrieve(url, destination)
|
|
|
|
|
|
def extract_file(log_dependency_name: str, filename: Path, destination_dir: Path, dir_after_extraction: Path) -> None:
|
|
if dir_after_extraction.exists():
|
|
logger.info(f"{log_dependency_name} already extracted into '{dir_after_extraction}'. Skipping.")
|
|
return
|
|
|
|
logger.info(f"Extracting {log_dependency_name} into '{destination_dir}' from '{filename}'.")
|
|
sevenzip = require_command("7z")
|
|
subprocess.check_call([sevenzip, "x", "-bso0", "-bsp0", str(filename), f"-o{destination_dir}"])
|
|
# TODO: assert that dir_after_extraction exists
|
|
|
|
|
|
def git_clone_and_checkout_revision(
|
|
log_dependency_name: str,
|
|
git_url: str,
|
|
dest_dir: Path,
|
|
revision: str | None = None,
|
|
) -> None:
|
|
if dest_dir.exists():
|
|
logger.info(f"Cloning {log_dependency_name} is already cloned.")
|
|
return
|
|
|
|
logger.info(f"Cloning {log_dependency_name} into '{dest_dir}'.")
|
|
run_streamed("git", "clone", git_url, str(dest_dir))
|
|
|
|
if revision:
|
|
run_streamed("git", "fetch", cwd=dest_dir)
|
|
logger.info(f"Checking out {log_dependency_name} revision {revision}.")
|
|
run_streamed("git", "reset", "--hard", cwd=dest_dir)
|
|
run_streamed("git", "checkout", revision, cwd=dest_dir)
|
|
|
|
|
|
def run_cmake(
|
|
log_dependency_name: str,
|
|
dependency_dir: Path,
|
|
vs_cfg_vars: VsCfgResult,
|
|
build_type: BuildType,
|
|
*extra_args: str,
|
|
env: dict[str, str] | None = None,
|
|
) -> None:
|
|
logger.info(f"Running CMake for {log_dependency_name}.")
|
|
|
|
build_path = dependency_dir / vs_cfg_vars.build_dir
|
|
build_path.mkdir(parents=True, exist_ok=True)
|
|
|
|
# TODO make deleting cache a parameter for this subroutine? We probably want to delete the
|
|
# cache always e.g. when we've had new changes in the repository.
|
|
cmake_cache_path = build_path / "CMakeCache.txt"
|
|
if build_type == "Rebuild" and cmake_cache_path.exists():
|
|
cmake_cache_path.unlink()
|
|
|
|
run_streamed(
|
|
"cmake",
|
|
"..",
|
|
"-G",
|
|
vs_cfg_vars.generator.name,
|
|
"-A",
|
|
vs_cfg_vars.vs_platform,
|
|
*extra_args,
|
|
cwd=build_path,
|
|
env=env,
|
|
)
|
|
|
|
|
|
def build_cmake_project(
|
|
log_dependency_name: str,
|
|
build_dir: Path,
|
|
build_cfg: BuildCfg,
|
|
msbuild_multiproc: tuple[str, ...],
|
|
) -> None:
|
|
logger.info(f"Building {log_dependency_name}. Please be patient, this will take a while.")
|
|
|
|
run_streamed("cmake", "--build", ".", "--config", build_cfg, "--", *msbuild_multiproc, cwd=build_dir)
|
|
|
|
|
|
def install_cmake_project(log_dependency_name: str, build_dir: Path, build_cfg: BuildCfg) -> None:
|
|
logger.info(f"Installing {log_dependency_name} ({build_cfg}). Please be patient, this may take a while.")
|
|
|
|
run_streamed("cmake", "--install", ".", "--config", build_cfg, cwd=build_dir)
|
|
|
|
|
|
def build_solution(
|
|
log_dependency_name: str,
|
|
msbuild_cmd: tuple[str, ...],
|
|
solution_path: Path,
|
|
build_cfg: BuildCfg,
|
|
vs_platform: str,
|
|
build_type: BuildType,
|
|
target: str | None = None,
|
|
compile_with_wpo: bool = False,
|
|
) -> None:
|
|
if target is None:
|
|
msbuild_target = build_type
|
|
elif build_type == "Build":
|
|
msbuild_target = target
|
|
else:
|
|
msbuild_target = f"{target}:{build_type}"
|
|
|
|
logger.info(f"Building {msbuild_target} of {log_dependency_name}. Please be patient, this will take a while.")
|
|
|
|
# Whole program optimization avoids Visual C++ hanging when compiling 32-bit release OCCT up to version 7.4.0.
|
|
properties = f"configuration={build_cfg};platform={vs_platform}"
|
|
if compile_with_wpo:
|
|
properties += ";WholeProgramOptimization=TRUE"
|
|
|
|
run_streamed(*msbuild_cmd, str(solution_path), f"/p:{properties}", f"/t:{msbuild_target}")
|
|
|
|
|
|
def install_json(install_dir: Path) -> None:
|
|
# TODO: sync it with build-all
|
|
JSON_VERSION = "3.6.1"
|
|
DEPENDENCY_NAME = f"json-{JSON_VERSION}"
|
|
download_file(
|
|
DEPENDENCY_NAME,
|
|
f"https://github.com/nlohmann/json/releases/download/v{JSON_VERSION}/json.hpp",
|
|
install_dir / "json" / "nlohmann" / "json.hpp",
|
|
)
|
|
|
|
|
|
def install_nuget(deps_dir: Path) -> Path:
|
|
NUGET_VERSION = "6.14.0"
|
|
DEPENDENCY_NAME = "nuget"
|
|
|
|
nuget_in_path = shutil.which("nuget")
|
|
if nuget_in_path:
|
|
logger.info("Found existing nuget in PATH. Skipping.")
|
|
return Path(nuget_in_path)
|
|
|
|
nuget_exe = deps_dir / f"nuget-{NUGET_VERSION}" / "nuget.exe"
|
|
download_file(
|
|
DEPENDENCY_NAME,
|
|
f"https://dist.nuget.org/win-x86-commandline/v{NUGET_VERSION}/nuget.exe",
|
|
nuget_exe,
|
|
)
|
|
return nuget_exe
|
|
|
|
|
|
def install_ccache(deps_dir: Path, nuget_exe: Path, build_deps_cache: BuildDepsCache) -> Path:
|
|
CCACHE_VERSION = "4.12.1"
|
|
DEPENDENCY_NAME = "ccache"
|
|
ccache_install_dir = deps_dir / f"{DEPENDENCY_NAME}.{CCACHE_VERSION}" / "tools"
|
|
|
|
if shutil.which("ccache"):
|
|
logger.info("Found existing ccache in PATH. Skipping.")
|
|
return ccache_install_dir
|
|
|
|
build_deps_cache.add_entry("CCACHE_INSTALL_DIR", str(ccache_install_dir))
|
|
|
|
if ccache_install_dir.exists():
|
|
logger.info(f"Found existing '{ccache_install_dir}', skipping")
|
|
return ccache_install_dir
|
|
|
|
run(str(nuget_exe), "install", "ccache", "-Version", CCACHE_VERSION, "-OutputDirectory", str(deps_dir))
|
|
return ccache_install_dir
|
|
|
|
|
|
def install_boost(
|
|
vs_cfg_vars: VsCfgResult,
|
|
build_deps_cache: BuildDepsCache,
|
|
build_cfg: BuildCfg,
|
|
ifcos_num_build_procs: int,
|
|
reuse_boost: bool,
|
|
) -> None:
|
|
# NOTE Boost < 1.64 doesn't work without tricks if the user has only VS 2017 installed and no earlier versions.
|
|
BOOST_VERSION = "1.92.0"
|
|
DEPENDENCY_NAME = f"Boost {BOOST_VERSION}"
|
|
|
|
dependency_dir = vs_cfg_vars.deps_dir / f"boost-{BOOST_VERSION}"
|
|
dependency_install_dir = dependency_dir / "stage" / vs_cfg_vars.gen_shorthand
|
|
|
|
# Remove leftover dir from before the switch to the archive's actual top-level folder naming.
|
|
# TODO: remove it a bit later.
|
|
old_dependency_dir = vs_cfg_vars.deps_dir / f"boost_{BOOST_VERSION.replace('.', '_')}"
|
|
if old_dependency_dir.exists():
|
|
logger.info(f"Removing outdated '{old_dependency_dir}'.")
|
|
shutil.rmtree(old_dependency_dir)
|
|
|
|
build_deps_cache.add_entry("BOOST_INSTALL_DIR", str(dependency_install_dir))
|
|
|
|
# NOTE Boost is fast to build with a limited set of libraries, so it's rebuilt by default.
|
|
# TODO: consider reuse_boost and release/debug installations.
|
|
if reuse_boost and is_already_installed(dependency_install_dir):
|
|
return
|
|
|
|
BOOST_ZIP = f"boost-{BOOST_VERSION}-b2-nodocs.7z"
|
|
|
|
download_file(
|
|
DEPENDENCY_NAME,
|
|
f"https://github.com/boostorg/boost/releases/download/boost-{BOOST_VERSION}/{BOOST_ZIP}",
|
|
vs_cfg_vars.deps_dir / BOOST_ZIP,
|
|
)
|
|
|
|
extract_file(
|
|
DEPENDENCY_NAME,
|
|
vs_cfg_vars.deps_dir / BOOST_ZIP,
|
|
vs_cfg_vars.deps_dir,
|
|
dependency_dir,
|
|
)
|
|
|
|
# Build Boost build script
|
|
if not (dependency_dir / "project-config.jam").exists():
|
|
boost_css = dependency_dir / "boost.css"
|
|
if not boost_css.exists():
|
|
logger.error(f"'{boost_css}' not found.")
|
|
sys.exit(1)
|
|
logger.info("Building Boost build script.")
|
|
run_streamed(
|
|
str(dependency_dir / "bootstrap.bat"), vs_cfg_vars.generator.boost_bootstrap_ver, cwd=dependency_dir
|
|
)
|
|
|
|
# TODO: this means that 'arm' and 'win32' platforms are not actually supported
|
|
# and can be dropped.
|
|
if vs_cfg_vars.is_vs_platform("x64"):
|
|
B2_ARCH_FEATURE = "x86"
|
|
elif vs_cfg_vars.is_vs_platform("ARM64"):
|
|
B2_ARCH_FEATURE = "arm"
|
|
else:
|
|
logger.error("Failed to identify architecture")
|
|
sys.exit(1)
|
|
|
|
BOOST_LIBS = (
|
|
"--with-system",
|
|
"--with-program_options",
|
|
"--with-regex",
|
|
"--with-thread",
|
|
"--with-date_time",
|
|
"--with-iostreams",
|
|
"--with-filesystem",
|
|
)
|
|
|
|
logger.info(f"Building {DEPENDENCY_NAME} {' '.join(BOOST_LIBS)}. Please be patient, this will take a while.")
|
|
|
|
project_cache_jam = dependency_dir / "bin.v2" / "project-cache.jam"
|
|
if project_cache_jam.exists():
|
|
project_cache_jam.unlink()
|
|
|
|
run_streamed(
|
|
str(dependency_dir / "b2.exe"),
|
|
f"toolset={vs_cfg_vars.boost_toolset}",
|
|
f"architecture={B2_ARCH_FEATURE}",
|
|
f"address-model={vs_cfg_vars.arch_bits}",
|
|
"--abbreviate-paths",
|
|
f"-j{ifcos_num_build_procs}",
|
|
f"variant={debug_or_release(build_cfg).lower()}",
|
|
*BOOST_LIBS,
|
|
"stage",
|
|
f"--stagedir={dependency_install_dir}",
|
|
cwd=dependency_dir,
|
|
)
|
|
|
|
|
|
def install_opencollada(
|
|
vs_cfg_vars: VsCfgResult,
|
|
build_type: BuildType,
|
|
build_cfg: BuildCfg,
|
|
msbuild_multiproc: tuple[str, ...],
|
|
) -> None:
|
|
deps_dir = vs_cfg_vars.deps_dir
|
|
install_dir = vs_cfg_vars.install_dir
|
|
|
|
DEPENDENCY_NAME = "OpenCOLLADA"
|
|
dependency_dir = deps_dir / "OpenCOLLADA"
|
|
|
|
# TODO: we probably can install
|
|
# Always clone it, even if it's installed, because it contains xml headers we need.
|
|
# Use a fixed revision in order to prevent introducing breaking changes
|
|
# TODO: commit is almost 3 years behind the latest version used in nix/build-all.py, need to test and bump.
|
|
git_clone_and_checkout_revision(
|
|
DEPENDENCY_NAME,
|
|
"https://github.com/KhronosGroup/OpenCOLLADA.git",
|
|
dependency_dir,
|
|
"064a60b65c2c31b94f013820856bc84fb1937cc6",
|
|
)
|
|
|
|
if is_already_installed(install_dir / DEPENDENCY_NAME, expected_build_cfg=build_cfg):
|
|
return
|
|
|
|
# TODO: add git reset and apply patches more cleanly.
|
|
|
|
# Debug build of OpenCOLLADAValidator fails (https://github.com/KhronosGroup/OpenCOLLADA/issues/377) so
|
|
# disable it from the build altogether as we have no use for it.
|
|
if "#add_subdirectory(COLLADAValidator)" not in (dependency_dir / "CMakeLists.txt").read_text():
|
|
run_streamed(
|
|
"git",
|
|
"apply",
|
|
"--reject",
|
|
"--whitespace=fix",
|
|
str(SCRIPT_DIR / "patches" / "OpenCOLLADA_CMakeLists.txt.patch"),
|
|
"--ignore-whitespace",
|
|
cwd=dependency_dir,
|
|
)
|
|
|
|
# std::tr1::unordered_map was a legacy MSVC compatibility shim kept around through VS2022's STL, but newer
|
|
# toolsets (e.g. VS2026/v145) no longer provide it, breaking the build with error C2039: 'tr1' is not a member of 'std'.
|
|
common_f_write_buffer_flusher = dependency_dir / "common" / "libBuffer" / "include" / "CommonFWriteBufferFlusher.h"
|
|
if (
|
|
"typedef std::unordered_map<MarkId, FilePosType > MarkIdToFilePos;"
|
|
not in common_f_write_buffer_flusher.read_text()
|
|
):
|
|
run_streamed(
|
|
"git",
|
|
"apply",
|
|
"--reject",
|
|
"--whitespace=fix",
|
|
str(REPO_ROOT / "nix" / "patches" / "opencollada" / "remove_tr1.patch"),
|
|
"--ignore-whitespace",
|
|
cwd=dependency_dir,
|
|
)
|
|
|
|
dependency_install_dir = install_dir / DEPENDENCY_NAME
|
|
|
|
# TODO: inconsistency with nix/build-all - there we prepare pcre and libxml2 separately,
|
|
# while here we rely on the versions bundled with the OpenCOLLADA repo (Externals/pcre,
|
|
# Externals/LibXML). Worth reconciling at some point.
|
|
#
|
|
# NOTE Enforce that the embedded LibXml2 and PCRE are used as there might be problems with
|
|
# arbitrary versions of the libraries.
|
|
run_cmake(
|
|
DEPENDENCY_NAME,
|
|
dependency_dir,
|
|
vs_cfg_vars,
|
|
build_type,
|
|
f"-DCMAKE_INSTALL_PREFIX={dependency_install_dir}",
|
|
"-DUSE_STATIC_MSVC_RUNTIME=0",
|
|
"-DCMAKE_DEBUG_POSTFIX=d",
|
|
"-DLIBXML2_LIBRARIES=",
|
|
"-DLIBXML2_INCLUDE_DIR=",
|
|
"-DPCRE_INCLUDE_DIR=",
|
|
"-DPCRE_LIBRARIES=",
|
|
# OpenCOLLADA is ancient at this point and allows cmake 2.6+, which results in an error
|
|
# in cmake 4, so we override the minimum cmake version.
|
|
"-DCMAKE_POLICY_VERSION_MINIMUM=3.5",
|
|
)
|
|
|
|
# OpenCOLLADA's vcxproj files only define Debug/Release configurations (no RelWithDebInfo/MinSizeRel).
|
|
debug_or_release_cfg = debug_or_release(build_cfg)
|
|
build_path = dependency_dir / vs_cfg_vars.build_dir
|
|
build_cmake_project(DEPENDENCY_NAME, build_path, debug_or_release_cfg, msbuild_multiproc)
|
|
install_cmake_project(DEPENDENCY_NAME, build_path, debug_or_release_cfg)
|
|
|
|
mark_installation(dependency_install_dir, build_cfg)
|
|
|
|
|
|
def install_occt(
|
|
vs_cfg_vars: VsCfgResult,
|
|
build_type: BuildType,
|
|
build_deps_cache: BuildDepsCache,
|
|
build_cfg: BuildCfg,
|
|
msbuild_multiproc: tuple[str, ...],
|
|
) -> None:
|
|
deps_dir = vs_cfg_vars.deps_dir
|
|
install_dir = vs_cfg_vars.install_dir
|
|
|
|
OCCT_VERSION = "7.8.1"
|
|
OCCT_VER = f"V{OCCT_VERSION.replace('.', '_')}"
|
|
|
|
DEPENDENCY_NAME = f"Open CASCADE {OCCT_VERSION}"
|
|
# TODO: `new-layout` suffix can be dropped on the next OCCT version update, it's only needed
|
|
# to separate the legacy layout installation (used by version 7.8.1) from the new one.
|
|
new_layout_suffix = "-new-layout" if OCCT_VERSION == "7.8.1" else ""
|
|
OCCT_DEPENDENCY_INSTALL_NAME = f"opencascade-{OCCT_VERSION}{new_layout_suffix}"
|
|
dependency_install_dir = install_dir / OCCT_DEPENDENCY_INSTALL_NAME
|
|
|
|
build_deps_cache.add_entry("OCC_INSTALL_DIR", str(dependency_install_dir))
|
|
|
|
if is_already_installed(dependency_install_dir, expected_build_cfg=build_cfg):
|
|
return
|
|
|
|
dependency_dir = deps_dir / "occt_git"
|
|
git_clone_and_checkout_revision(
|
|
DEPENDENCY_NAME,
|
|
"https://github.com/Open-Cascade-SAS/OCCT",
|
|
dependency_dir,
|
|
OCCT_VER,
|
|
)
|
|
|
|
# Patching always blindly would trigger a rebuild each time.
|
|
cmake_lists_path = dependency_dir / "CMakeLists.txt"
|
|
# TODO: probably can use `git apply --reverse --check` for better validation.
|
|
if "IfcOpenShell" not in cmake_lists_path.read_text():
|
|
run_streamed(
|
|
"git",
|
|
"apply",
|
|
"--ignore-whitespace",
|
|
str(SCRIPT_DIR / "patches" / f"{OCCT_VER}.patch"),
|
|
cwd=dependency_dir,
|
|
)
|
|
assert "IfcOpenShell" in cmake_lists_path.read_text()
|
|
|
|
# TODO: remove CMAKE_DEBUG_POSTFIX setting later.
|
|
# Temporarily explicitly set `CMAKE_DEBUG_POSTFIX` to empty to override it's previously being set to `d`.
|
|
# OCCT don't need it, since it's layout is separating debug and release build by different folders.
|
|
#
|
|
# OCCT 7.8.1 we're using is becoming old and it was targeting cmake 3.1+.
|
|
# To make it buildable on cmake 4, we override policy version, but it may have some quirks in the future
|
|
# and we may consider version bump.
|
|
run_cmake(
|
|
DEPENDENCY_NAME,
|
|
dependency_dir,
|
|
vs_cfg_vars,
|
|
build_type,
|
|
f"-DCMAKE_INSTALL_PREFIX={dependency_install_dir}",
|
|
"-DBUILD_LIBRARY_TYPE=Static",
|
|
"-DCMAKE_DEBUG_POSTFIX=",
|
|
"-DBUILD_MODULE_Draw=0",
|
|
"-DBUILD_RELEASE_DISABLE_EXCEPTIONS=OFF",
|
|
"-DUSE_XLIB=OFF",
|
|
"-DUSE_FREETYPE=OFF",
|
|
"-DUSE_OPENGL=OFF",
|
|
"-DUSE_GLES2=OFF",
|
|
"-DBUILD_USE_PCH=ON",
|
|
"-DCMAKE_POLICY_VERSION_MINIMUM=3.5",
|
|
)
|
|
|
|
build_path = dependency_dir / vs_cfg_vars.build_dir
|
|
build_cmake_project(DEPENDENCY_NAME, build_path, build_cfg, msbuild_multiproc)
|
|
install_cmake_project(DEPENDENCY_NAME, build_path, build_cfg)
|
|
|
|
# Fix upstream bug in cmake config file with unescaped quotes preventing configuration.
|
|
# The issue is fixed in 7.9.0+.
|
|
# See https://github.com/Open-Cascade-SAS/OCCT/pull/373
|
|
occt_config_cmake = dependency_install_dir / "cmake" / "OpenCASCADEConfig.cmake"
|
|
occt_config_cmake.write_text(re.sub(r'/wd"(\d+)"', r"/wd\1", occt_config_cmake.read_text()))
|
|
|
|
mark_installation(dependency_install_dir, build_cfg)
|
|
|
|
|
|
def install_proj(
|
|
vs_cfg_vars: VsCfgResult,
|
|
build_type: BuildType,
|
|
build_cfg: BuildCfg,
|
|
msbuild_multiproc: tuple[str, ...],
|
|
) -> None:
|
|
deps_dir = vs_cfg_vars.deps_dir
|
|
install_dir = vs_cfg_vars.install_dir
|
|
|
|
PROJ_VERSION = "9.4.1"
|
|
|
|
if is_already_installed(install_dir / f"proj-{PROJ_VERSION}"):
|
|
return
|
|
|
|
def install_sqlite3() -> None:
|
|
DEPENDENCY_NAME = "sqlite3"
|
|
SQLITE_VERSION = "3430100"
|
|
|
|
(install_dir / "sqlite3" / "lib").mkdir(parents=True, exist_ok=True)
|
|
(install_dir / "sqlite3" / "bin").mkdir(parents=True, exist_ok=True)
|
|
(install_dir / "sqlite3" / "include").mkdir(parents=True, exist_ok=True)
|
|
|
|
download_file(
|
|
DEPENDENCY_NAME,
|
|
f"https://www.sqlite.org/2023/sqlite-amalgamation-{SQLITE_VERSION}.zip",
|
|
deps_dir / f"sqlite-amalgamation-{SQLITE_VERSION}.zip",
|
|
)
|
|
|
|
extract_file(
|
|
DEPENDENCY_NAME,
|
|
deps_dir / f"sqlite-amalgamation-{SQLITE_VERSION}.zip",
|
|
deps_dir,
|
|
deps_dir / f"sqlite-amalgamation-{SQLITE_VERSION}",
|
|
)
|
|
|
|
sqlite_dir = deps_dir / f"sqlite-amalgamation-{SQLITE_VERSION}"
|
|
run("cl", "/c", "sqlite3.c", cwd=sqlite_dir)
|
|
run("lib", f"/OUT:{install_dir / 'sqlite3' / 'lib' / 'sqlite3.lib'}", "sqlite3.obj", cwd=sqlite_dir)
|
|
run(
|
|
"cl",
|
|
"sqlite3.c",
|
|
"shell.c",
|
|
"/link",
|
|
f"/out:{install_dir / 'sqlite3' / 'bin' / 'sqlite3.exe'}",
|
|
cwd=sqlite_dir,
|
|
)
|
|
os.environ["PATH"] += os.pathsep + str(install_dir / "sqlite3" / "bin")
|
|
shutil.copy(sqlite_dir / "sqlite3.h", install_dir / "sqlite3" / "include")
|
|
|
|
def _install_proj() -> None:
|
|
DEPENDENCY_NAME = "proj"
|
|
dependency_dir = deps_dir / f"proj-{PROJ_VERSION}"
|
|
|
|
download_file(
|
|
DEPENDENCY_NAME,
|
|
f"https://download.osgeo.org/proj/proj-{PROJ_VERSION}.zip",
|
|
deps_dir / f"proj-{PROJ_VERSION}.zip",
|
|
)
|
|
|
|
extract_file(
|
|
DEPENDENCY_NAME,
|
|
deps_dir / f"proj-{PROJ_VERSION}.zip",
|
|
deps_dir,
|
|
dependency_dir,
|
|
)
|
|
|
|
run_cmake(
|
|
DEPENDENCY_NAME,
|
|
dependency_dir,
|
|
vs_cfg_vars,
|
|
build_type,
|
|
f'-DCMAKE_INSTALL_PREFIX={install_dir / f"proj-{PROJ_VERSION}"}',
|
|
f'-DCMAKE_PREFIX_PATH={install_dir / "sqlite3"}',
|
|
f'-DSQLite3_INCLUDE_DIR={install_dir / "sqlite3" / "include"}',
|
|
f'-DSQLite3_LIBRARY={install_dir / "sqlite3" / "lib" / "sqlite3.lib"}',
|
|
"-DENABLE_TIFF=OFF",
|
|
"-DENABLE_CURL=OFF",
|
|
"-DBUILD_PROJSYNC=OFF",
|
|
"-DBUILD_SHARED_LIBS=OFF",
|
|
"-DBUILD_TESTING=OFF",
|
|
)
|
|
|
|
build_path = dependency_dir / vs_cfg_vars.build_dir
|
|
build_cmake_project(DEPENDENCY_NAME, build_path, build_cfg, msbuild_multiproc)
|
|
install_cmake_project(DEPENDENCY_NAME, build_path, build_cfg)
|
|
|
|
install_sqlite3()
|
|
_install_proj()
|
|
|
|
|
|
def install_mpir(vs_cfg_vars: VsCfgResult, deps_dir: Path, install_dir: Path, build_cfg: BuildCfg) -> None:
|
|
DEPENDENCY_NAME = "mpir"
|
|
# `mpfr` depends on relative path `..\mpir\config.h`, so dependency name should match exactly.
|
|
dependency_dir = deps_dir / "mpir"
|
|
|
|
if is_already_installed(install_dir / "mpir"):
|
|
return
|
|
|
|
git_clone_and_checkout_revision(DEPENDENCY_NAME, "https://github.com/Andrej730/mpir-vs2026.git", dependency_dir)
|
|
run_streamed("git", "reset", "--hard", cwd=dependency_dir)
|
|
run_streamed("git", "clean", "-fdx", cwd=dependency_dir)
|
|
|
|
ucrt_version = get_vs_var("UCRTVersion")
|
|
mpir_patch = (SCRIPT_DIR / "patches" / "mpir.patch").read_text()
|
|
for project_name in ("lib_mpir_cxx", "lib_mpir_gc"):
|
|
patch = mpir_patch.replace("sdk", ucrt_version).replace("fn", project_name)
|
|
logger.info(f"Applying mpir patch for {project_name}.")
|
|
subprocess.run(
|
|
["git", "apply", "--unidiff-zero", "--ignore-whitespace"],
|
|
input=patch,
|
|
text=True,
|
|
cwd=dependency_dir,
|
|
check=True,
|
|
)
|
|
|
|
run_streamed(
|
|
"git",
|
|
"apply",
|
|
str(SCRIPT_DIR / "patches" / "mpir_runtime.patch"),
|
|
"--unidiff-zero",
|
|
"--ignore-whitespace",
|
|
cwd=dependency_dir,
|
|
)
|
|
|
|
if vs_cfg_vars.is_vs_platform("ARM64"):
|
|
logger.info("Applying ARM64 patches for mpir.")
|
|
run_streamed(
|
|
"git",
|
|
"apply",
|
|
str(SCRIPT_DIR / "patches" / "mpir-arm64-changes.patch"),
|
|
"--unidiff-zero",
|
|
"--ignore-whitespace",
|
|
cwd=dependency_dir,
|
|
)
|
|
|
|
vs_ver_short = str(vs_cfg_vars.generator.vs_ver)[2:]
|
|
msvc_dir = dependency_dir / "msvc" / f"vs{vs_ver_short}"
|
|
# mpir's vcxproj files only define Debug/Release configurations (no RelWithDebInfo/MinSizeRel).
|
|
debug_or_release_cfg = debug_or_release(build_cfg)
|
|
run_streamed(
|
|
str(msvc_dir / "msbuild.bat"), "gc", "LIB", vs_cfg_vars.vs_platform, debug_or_release_cfg, cwd=msvc_dir
|
|
)
|
|
|
|
lib_dir = dependency_dir / "lib" / vs_cfg_vars.vs_platform / debug_or_release_cfg
|
|
shutil.copytree(lib_dir, install_dir / "mpir", dirs_exist_ok=True)
|
|
|
|
|
|
def install_mpfr(
|
|
vs_cfg_vars: VsCfgResult,
|
|
deps_dir: Path,
|
|
install_dir: Path,
|
|
build_cfg: BuildCfg,
|
|
build_type: BuildType,
|
|
msbuild_cmd: tuple[str, ...],
|
|
) -> None:
|
|
DEPENDENCY_NAME = "mpfr"
|
|
dependency_dir = deps_dir / "mpfr"
|
|
|
|
if is_already_installed(install_dir / "mpfr"):
|
|
return
|
|
|
|
git_clone_and_checkout_revision(
|
|
DEPENDENCY_NAME,
|
|
"https://github.com/aothms/mpfr.git",
|
|
dependency_dir,
|
|
"2ebbe10fd029a480cf6e8a64c493afa9f3654251",
|
|
)
|
|
run_streamed("git", "reset", "--hard", cwd=dependency_dir)
|
|
run_streamed("git", "clean", "-fdx", cwd=dependency_dir)
|
|
|
|
ucrt_version = get_vs_var("UCRTVersion")
|
|
mpfr_patch = (SCRIPT_DIR / "patches" / "mpfr.patch").read_text()
|
|
patch = mpfr_patch.replace("sdk", ucrt_version).replace("fn", "lib_mpfr")
|
|
logger.info("Applying mpfr patch.")
|
|
subprocess.run(
|
|
["git", "apply", "--unidiff-zero", "--ignore-whitespace"],
|
|
input=patch,
|
|
text=True,
|
|
cwd=dependency_dir,
|
|
check=True,
|
|
)
|
|
|
|
run_streamed(
|
|
"git",
|
|
"apply",
|
|
str(SCRIPT_DIR / "patches" / "mpfr_runtime.patch"),
|
|
"--unidiff-zero",
|
|
"--ignore-whitespace",
|
|
cwd=dependency_dir,
|
|
)
|
|
|
|
if vs_cfg_vars.is_vs_platform("ARM64"):
|
|
logger.info("Applying ARM64 patches for mpfr.")
|
|
run_streamed(
|
|
"git",
|
|
"apply",
|
|
str(SCRIPT_DIR / "patches" / "mpfr-arm64-changes.patch"),
|
|
"--unidiff-zero",
|
|
"--ignore-whitespace",
|
|
cwd=dependency_dir,
|
|
)
|
|
|
|
# mpfr's repo only ships these two prebaked solution folders, regardless of the actual VS version in use.
|
|
if vs_cfg_vars.generator.vs_ver == 2017:
|
|
mpfr_sln_dir = "build.vc15"
|
|
orig_generator = CMAKE_GENERATORS["Visual Studio 15 2017"]
|
|
else:
|
|
mpfr_sln_dir = "build.vs19"
|
|
orig_generator = CMAKE_GENERATORS["Visual Studio 16 2019"]
|
|
orig_platform_toolset = orig_generator.vs_toolset
|
|
|
|
target_toolset = vs_cfg_vars.vs_toolset_override or vs_cfg_vars.generator.vs_toolset
|
|
for vcxproj in (dependency_dir / mpfr_sln_dir).rglob("*.vcxproj"):
|
|
vcxproj.write_text(vcxproj.read_text().replace(orig_platform_toolset, target_toolset))
|
|
|
|
# mpfr's vcxproj files only define Debug/Release configurations (no RelWithDebInfo/MinSizeRel).
|
|
debug_or_release_cfg = debug_or_release(build_cfg)
|
|
build_solution(
|
|
DEPENDENCY_NAME,
|
|
msbuild_cmd,
|
|
dependency_dir / mpfr_sln_dir / "lib_mpfr.sln",
|
|
debug_or_release_cfg,
|
|
vs_cfg_vars.vs_platform,
|
|
build_type,
|
|
target="lib_mpfr",
|
|
)
|
|
|
|
# Not all msvc projects in the solution are patched with the right sdk version, so the build
|
|
# can report success even when mpfr.lib itself failed to build.
|
|
lib_dir = dependency_dir / "lib" / vs_cfg_vars.vs_platform / debug_or_release_cfg
|
|
if not (lib_dir / "mpfr.lib").exists():
|
|
logger.error(f"{lib_dir / 'mpfr.lib'} was not built.")
|
|
sys.exit(1)
|
|
|
|
shutil.copytree(lib_dir, install_dir / "mpfr", dirs_exist_ok=True)
|
|
|
|
|
|
def install_qt6(
|
|
vs_cfg_vars: VsCfgResult,
|
|
build_deps_cache: BuildDepsCache,
|
|
build_cfg: BuildCfg,
|
|
ifcos_install_qt6: bool,
|
|
pythonhome: Path | None,
|
|
) -> None:
|
|
DEPENDENCY_NAME = "qt6"
|
|
QT6_VERSION = os.getenv("QT6_VERSION")
|
|
if QT6_VERSION:
|
|
logger.info(f"Using overridden QT6_VERSION: '{QT6_VERSION}'")
|
|
else:
|
|
QT6_VERSION = "6.8.3"
|
|
|
|
build_deps_cache.add_entry("QT6_VERSION", QT6_VERSION)
|
|
|
|
vs_toolset = vs_cfg_vars.vs_toolset_override or vs_cfg_vars.generator.vs_toolset
|
|
QT6_MSVC_YEAR = VS_TOOLSET_TO_VS_VER[vs_toolset]
|
|
# Qt has not published prebuilt msvc2026 binaries yet (aqt only lists win64_msvc2022_64 as of
|
|
# Qt 6.7-6.10). The v14x MSVC toolsets share a stable ABI/CRT, so fall back to the msvc2022
|
|
# binaries until Qt ships msvc2026 ones. Revisit once `aqt list-qt windows desktop --arch <ver>`
|
|
# shows a msvc2026 entry.
|
|
if QT6_MSVC_YEAR == 2026:
|
|
QT6_MSVC_YEAR = 2022
|
|
|
|
QT6_CROSS_COMPILING = False
|
|
QT6_HOST_ARCH = None
|
|
QT6_HOST_INSTALL_SUFFIX = None
|
|
if vs_cfg_vars.is_vs_platform("x64"):
|
|
QT6_ARCH = f"win64_msvc{QT6_MSVC_YEAR}_64"
|
|
QT6_INSTALL_SUFFIX = f"msvc{QT6_MSVC_YEAR}_64"
|
|
elif vs_cfg_vars.is_vs_platform("ARM64"):
|
|
QT6_CROSS_COMPILING = True
|
|
QT6_ARCH = f"win64_msvc{QT6_MSVC_YEAR}_arm64_cross_compiled"
|
|
QT6_INSTALL_SUFFIX = f"msvc{QT6_MSVC_YEAR}_arm64"
|
|
# Qt publishes Windows ARM64 packages as cross-compiled Qt. Even on the
|
|
# windows-11-arm runner, Qt CMake requires host tools such as moc/rcc.
|
|
# Use the x64 host tools; Windows 11 on Arm runs them through x64
|
|
# emulation while cl.exe still builds ARM64 binaries against target Qt.
|
|
QT6_HOST_ARCH = f"win64_msvc{QT6_MSVC_YEAR}_64"
|
|
QT6_HOST_INSTALL_SUFFIX = f"msvc{QT6_MSVC_YEAR}_64"
|
|
else:
|
|
logger.error(
|
|
f"Automatic Qt6 installation is only supported for x64 and arm64 builds, "
|
|
f"got '{vs_cfg_vars.vs_platform}'."
|
|
)
|
|
sys.exit(1)
|
|
|
|
DEPENDENCY_INSTALL_NAME = f"qt6-{QT6_VERSION}-{QT6_INSTALL_SUFFIX}"
|
|
QT6_AQT_OUTPUT_DIR = vs_cfg_vars.install_dir / DEPENDENCY_INSTALL_NAME
|
|
QT6_INSTALL_DIR = QT6_AQT_OUTPUT_DIR / QT6_VERSION / QT6_INSTALL_SUFFIX
|
|
QT_DIR = QT6_INSTALL_DIR
|
|
|
|
QT6_HOST_AQT_OUTPUT_DIR = None
|
|
QT6_HOST_INSTALL_DIR = None
|
|
QT_HOST_PATH = None
|
|
if QT6_CROSS_COMPILING:
|
|
assert QT6_HOST_INSTALL_SUFFIX is not None
|
|
QT6_HOST_AQT_OUTPUT_DIR = vs_cfg_vars.install_dir / f"qt6-{QT6_VERSION}-{QT6_HOST_INSTALL_SUFFIX}"
|
|
QT6_HOST_INSTALL_DIR = QT6_HOST_AQT_OUTPUT_DIR / QT6_VERSION / QT6_HOST_INSTALL_SUFFIX
|
|
QT_HOST_PATH = QT6_HOST_INSTALL_DIR
|
|
|
|
QT6_CONFIG_DLL = "Qt6Cored.dll" if debug_or_release(build_cfg) == "Debug" else "Qt6Core.dll"
|
|
|
|
if not ifcos_install_qt6:
|
|
logger.info("IFCOS_INSTALL_QT6 not 'TRUE', skipping installation of Qt6.")
|
|
return
|
|
|
|
build_deps_cache.add_entry("QT6_INSTALL_DIR", str(QT6_INSTALL_DIR))
|
|
build_deps_cache.add_entry("QT_DIR", str(QT_DIR))
|
|
if QT6_CROSS_COMPILING:
|
|
assert QT6_HOST_INSTALL_DIR is not None
|
|
assert QT_HOST_PATH is not None
|
|
build_deps_cache.add_entry("QT6_HOST_INSTALL_DIR", str(QT6_HOST_INSTALL_DIR))
|
|
build_deps_cache.add_entry("QT_HOST_PATH", str(QT_HOST_PATH))
|
|
|
|
QT6_TARGET_EXPECTED_FILES = [
|
|
QT6_INSTALL_DIR / "lib" / "cmake" / "Qt6" / "Qt6Config.cmake",
|
|
QT6_INSTALL_DIR / "bin" / QT6_CONFIG_DLL,
|
|
QT6_INSTALL_DIR / "lib" / "cmake" / "Qt6Svg" / "Qt6SvgConfig.cmake",
|
|
]
|
|
QT6_TARGET_INSTALLED = all(path.exists() for path in QT6_TARGET_EXPECTED_FILES)
|
|
|
|
QT6_HOST_EXPECTED_FILES = None
|
|
QT6_HOST_INSTALLED = True
|
|
if QT6_CROSS_COMPILING:
|
|
assert QT6_HOST_INSTALL_DIR is not None
|
|
QT6_HOST_EXPECTED_FILES = [
|
|
QT6_HOST_INSTALL_DIR / "lib" / "cmake" / "Qt6" / "Qt6Config.cmake",
|
|
QT6_HOST_INSTALL_DIR / "bin" / "moc.exe",
|
|
QT6_HOST_INSTALL_DIR / "bin" / "rcc.exe",
|
|
QT6_HOST_INSTALL_DIR / "lib" / "cmake" / "Qt6Svg" / "Qt6SvgConfig.cmake",
|
|
]
|
|
QT6_HOST_INSTALLED = all(path.exists() for path in QT6_HOST_EXPECTED_FILES)
|
|
|
|
if QT6_TARGET_INSTALLED and QT6_HOST_INSTALLED:
|
|
logger.info(f"Found existing '{QT6_INSTALL_DIR}' for {build_cfg}, skipping")
|
|
if QT6_CROSS_COMPILING:
|
|
logger.info(f"Found existing Qt host tools at '{QT6_HOST_INSTALL_DIR}', skipping")
|
|
mark_installation(QT6_INSTALL_DIR, build_cfg)
|
|
return
|
|
|
|
if pythonhome is not None and (pythonhome / "python.exe").exists():
|
|
AQT_PYTHON = str(pythonhome / "python.exe")
|
|
else:
|
|
AQT_PYTHON = require_command("python")
|
|
|
|
run_streamed(AQT_PYTHON, "-m", "pip", "install", "--upgrade", "aqtinstall")
|
|
|
|
def aqt_install_qt(arch: str, output_dir: Path) -> None:
|
|
run_streamed(
|
|
AQT_PYTHON,
|
|
"-m",
|
|
"aqt",
|
|
"install-qt",
|
|
"windows",
|
|
"desktop",
|
|
QT6_VERSION,
|
|
arch,
|
|
"-O",
|
|
str(output_dir),
|
|
"--archives",
|
|
"qtbase",
|
|
"qtsvg",
|
|
)
|
|
|
|
if not QT6_TARGET_INSTALLED:
|
|
# 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.
|
|
aqt_install_qt(QT6_ARCH, QT6_AQT_OUTPUT_DIR)
|
|
|
|
if QT6_CROSS_COMPILING and not QT6_HOST_INSTALLED:
|
|
assert QT6_HOST_ARCH is not None
|
|
assert QT6_HOST_AQT_OUTPUT_DIR is not None
|
|
# windeployqt runs from the host Qt when cross-compiling ARM64, so the
|
|
# host Qt needs qtsvg too to deploy the Bonsai Viewer's Qt6Svg dependency.
|
|
aqt_install_qt(QT6_HOST_ARCH, QT6_HOST_AQT_OUTPUT_DIR)
|
|
|
|
def require_exists(label: str, path: Path) -> None:
|
|
if not path.exists():
|
|
logger.error(f"{label} did not produce '{path.name}' at '{path.parent}'.")
|
|
sys.exit(1)
|
|
|
|
for path in QT6_TARGET_EXPECTED_FILES:
|
|
require_exists("Qt6 installation", path)
|
|
|
|
if QT6_CROSS_COMPILING:
|
|
assert QT6_HOST_EXPECTED_FILES is not None
|
|
for path in QT6_HOST_EXPECTED_FILES:
|
|
require_exists("Qt6 host installation", path)
|
|
|
|
# TODO: check if it's actually needed, since we don't use check it.
|
|
mark_installation(QT6_INSTALL_DIR, build_cfg)
|
|
|
|
|
|
def install_python(
|
|
vs_cfg_vars: VsCfgResult, ifcos_install_python: bool, build_deps_cache: BuildDepsCache, nuget_exe: Path
|
|
) -> Path | None:
|
|
"""Returns PYTHONHOME, or None if IFCOS_INSTALL_PYTHON is not set."""
|
|
PYTHON_VERSION = os.getenv("PYTHON_VERSION")
|
|
if PYTHON_VERSION:
|
|
logger.info(f"Using overridden PYTHON_VERSION: '{PYTHON_VERSION}'")
|
|
else:
|
|
PYTHON_VERSION = "3.11.7"
|
|
|
|
if not ifcos_install_python:
|
|
logger.info("IFCOS_INSTALL_PYTHON not 'TRUE', skipping installation of Python.")
|
|
return None
|
|
|
|
if not vs_cfg_vars.is_vs_platform("ARM64") and not vs_cfg_vars.is_vs_platform("x64"):
|
|
# nuget doesn't support providing architecture for packages.
|
|
logger.error("Automatic installation of Python for x86 builds is not supported,")
|
|
logger.error(f"please install Python {PYTHON_VERSION} manually and ensure that it is available in PATH.")
|
|
logger.error(f"https://www.python.org/ftp/python/{PYTHON_VERSION}/python-{PYTHON_VERSION}.exe")
|
|
sys.exit(1)
|
|
|
|
if vs_cfg_vars.is_vs_platform("ARM64"):
|
|
PYTHONHOME = vs_cfg_vars.deps_dir / f"pythonarm64.{PYTHON_VERSION}" / "tools"
|
|
else:
|
|
PYTHONHOME = vs_cfg_vars.deps_dir / f"python.{PYTHON_VERSION}" / "tools"
|
|
|
|
build_deps_cache.add_entry("PYTHONHOME", str(PYTHONHOME))
|
|
|
|
if PYTHONHOME.exists():
|
|
logger.info(f"Found existing '{PYTHONHOME}', skipping installation.")
|
|
return PYTHONHOME
|
|
|
|
nuget_package = "pythonarm64" if vs_cfg_vars.is_vs_platform("ARM64") else "Python"
|
|
run(
|
|
str(nuget_exe),
|
|
"install",
|
|
nuget_package,
|
|
"-Version",
|
|
PYTHON_VERSION,
|
|
"-OutputDirectory",
|
|
str(vs_cfg_vars.deps_dir),
|
|
)
|
|
|
|
return PYTHONHOME
|
|
|
|
|
|
def install_swig(
|
|
vs_cfg_vars: VsCfgResult,
|
|
build_type: BuildType,
|
|
build_deps_cache: BuildDepsCache,
|
|
msbuild_multiproc: tuple[str, ...],
|
|
) -> None:
|
|
SWIG_VERSION = "4.4.1"
|
|
DEPENDENCY_NAME = "SWIG"
|
|
dependency_dir = vs_cfg_vars.deps_dir / f"swig-{SWIG_VERSION}"
|
|
dependency_install_dir = vs_cfg_vars.install_dir / f"swig-{SWIG_VERSION}"
|
|
|
|
build_deps_cache.add_entry("SWIG_INSTALL_DIR", str(dependency_install_dir))
|
|
|
|
if is_already_installed(dependency_install_dir):
|
|
return
|
|
|
|
WIN_FLEX_BISON = "win_flex_bison-2.5.25"
|
|
|
|
def install_bison() -> None:
|
|
DEPENDENCY_NAME = "win_flex_bison"
|
|
WIN_FLEX_BISON_ZIP = f"{WIN_FLEX_BISON}.zip"
|
|
|
|
download_file(
|
|
DEPENDENCY_NAME,
|
|
f"https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/{WIN_FLEX_BISON_ZIP}",
|
|
vs_cfg_vars.deps_dir / WIN_FLEX_BISON_ZIP,
|
|
)
|
|
|
|
extract_file(
|
|
DEPENDENCY_NAME,
|
|
vs_cfg_vars.deps_dir / WIN_FLEX_BISON_ZIP,
|
|
vs_cfg_vars.deps_dir / WIN_FLEX_BISON,
|
|
vs_cfg_vars.deps_dir / WIN_FLEX_BISON,
|
|
)
|
|
|
|
install_bison()
|
|
|
|
SWIG_ZIP = f"swig-{SWIG_VERSION}.zip"
|
|
download_file(
|
|
DEPENDENCY_NAME,
|
|
f"https://github.com/swig/swig/archive/refs/tags/v{SWIG_VERSION}.zip",
|
|
vs_cfg_vars.deps_dir / SWIG_ZIP,
|
|
)
|
|
|
|
extract_file(
|
|
DEPENDENCY_NAME,
|
|
vs_cfg_vars.deps_dir / SWIG_ZIP,
|
|
vs_cfg_vars.deps_dir,
|
|
dependency_dir,
|
|
)
|
|
|
|
run_cmake(
|
|
DEPENDENCY_NAME,
|
|
dependency_dir,
|
|
vs_cfg_vars,
|
|
build_type,
|
|
f"-DCMAKE_INSTALL_PREFIX={dependency_install_dir}",
|
|
"-DWITH_PCRE=OFF",
|
|
f"-DBISON_EXECUTABLE={vs_cfg_vars.deps_dir / WIN_FLEX_BISON / 'win_bison.exe'}",
|
|
)
|
|
|
|
build_path = dependency_dir / vs_cfg_vars.build_dir
|
|
build_cmake_project(DEPENDENCY_NAME, build_path, "Release", msbuild_multiproc)
|
|
install_cmake_project(DEPENDENCY_NAME, build_path, "Release")
|
|
|
|
|
|
def install_cgal(
|
|
vs_cfg_vars: VsCfgResult,
|
|
build_type: BuildType,
|
|
build_cfg: BuildCfg,
|
|
msbuild_multiproc: tuple[str, ...],
|
|
) -> None:
|
|
deps_dir = vs_cfg_vars.deps_dir
|
|
install_dir = vs_cfg_vars.install_dir
|
|
|
|
# TODO: bump to v5.6.3 to match nix/build-all.py.
|
|
# TODO: add CGAL_VERSION to the install path during the next version bump.
|
|
CGAL_VERSION = "5.5.5"
|
|
DEPENDENCY_NAME = "cgal"
|
|
dependency_dir = deps_dir / "cgal"
|
|
dependency_install_dir = install_dir / "cgal"
|
|
|
|
if is_already_installed(dependency_install_dir):
|
|
return
|
|
|
|
git_clone_and_checkout_revision(
|
|
DEPENDENCY_NAME,
|
|
"https://github.com/CGAL/cgal.git",
|
|
dependency_dir,
|
|
f"v{CGAL_VERSION}",
|
|
)
|
|
|
|
run_streamed("git", "reset", "--hard", cwd=dependency_dir)
|
|
run_streamed(
|
|
"git",
|
|
"apply",
|
|
"--ignore-whitespace",
|
|
str(SCRIPT_DIR / "patches" / "cgal_no_zlib.patch"),
|
|
cwd=dependency_dir,
|
|
)
|
|
|
|
run_cmake(
|
|
DEPENDENCY_NAME,
|
|
dependency_dir,
|
|
vs_cfg_vars,
|
|
build_type,
|
|
f"-DCMAKE_INSTALL_PREFIX={dependency_install_dir}",
|
|
)
|
|
|
|
build_path = dependency_dir / vs_cfg_vars.build_dir
|
|
build_cmake_project(DEPENDENCY_NAME, build_path, build_cfg, msbuild_multiproc)
|
|
install_cmake_project(DEPENDENCY_NAME, build_path, build_cfg)
|
|
|
|
|
|
def install_eigen(vs_cfg_vars: VsCfgResult) -> None:
|
|
install_dir = vs_cfg_vars.install_dir
|
|
|
|
# TODO: bump to 3.4.0 to match nix/build-all.py.
|
|
# TODO: add EIGEN_VERSION to the install path during the next version bump.
|
|
EIGEN_VERSION = "3.3.9"
|
|
DEPENDENCY_NAME = "Eigen"
|
|
dependency_dir = install_dir / DEPENDENCY_NAME
|
|
|
|
if is_already_installed(dependency_dir):
|
|
return
|
|
|
|
git_clone_and_checkout_revision(
|
|
DEPENDENCY_NAME,
|
|
"https://gitlab.com/libeigen/eigen.git",
|
|
dependency_dir,
|
|
EIGEN_VERSION,
|
|
)
|
|
|
|
|
|
def install_zstd(
|
|
vs_cfg_vars: VsCfgResult,
|
|
build_type: BuildType,
|
|
build_cfg: BuildCfg,
|
|
msbuild_multiproc: tuple[str, ...],
|
|
) -> None:
|
|
deps_dir = vs_cfg_vars.deps_dir
|
|
install_dir = vs_cfg_vars.install_dir
|
|
|
|
ZSTD_VERSION = "1.5.7"
|
|
DEPENDENCY_NAME = "zstd"
|
|
dependency_dir = deps_dir / f"{DEPENDENCY_NAME}-{ZSTD_VERSION}"
|
|
dependency_install_dir = install_dir / DEPENDENCY_NAME
|
|
|
|
if is_already_installed(dependency_install_dir):
|
|
return
|
|
|
|
ZSTD_ZIP = f"zstd-{ZSTD_VERSION}.zip"
|
|
download_file(
|
|
DEPENDENCY_NAME,
|
|
f"https://github.com/facebook/zstd/archive/refs/tags/v{ZSTD_VERSION}.zip",
|
|
deps_dir / ZSTD_ZIP,
|
|
)
|
|
|
|
extract_file(
|
|
DEPENDENCY_NAME,
|
|
deps_dir / ZSTD_ZIP,
|
|
deps_dir,
|
|
dependency_dir,
|
|
)
|
|
|
|
cmake_source_dir = dependency_dir / "build" / "cmake"
|
|
run_cmake(
|
|
DEPENDENCY_NAME,
|
|
cmake_source_dir,
|
|
vs_cfg_vars,
|
|
build_type,
|
|
f"-DCMAKE_INSTALL_PREFIX={dependency_install_dir}",
|
|
"-DZSTD_BUILD_STATIC=ON",
|
|
"-DZSTD_BUILD_SHARED=OFF",
|
|
)
|
|
|
|
build_path = cmake_source_dir / vs_cfg_vars.build_dir
|
|
build_cmake_project(DEPENDENCY_NAME, build_path, build_cfg, msbuild_multiproc)
|
|
install_cmake_project(DEPENDENCY_NAME, build_path, build_cfg)
|
|
|
|
|
|
def install_rocksdb(
|
|
vs_cfg_vars: VsCfgResult,
|
|
build_type: BuildType,
|
|
build_cfg: BuildCfg,
|
|
msbuild_multiproc: tuple[str, ...],
|
|
) -> None:
|
|
deps_dir = vs_cfg_vars.deps_dir
|
|
install_dir = vs_cfg_vars.install_dir
|
|
|
|
# TODO: bump to 10.4.2 to match nix/build-all.py.
|
|
ROCKSDB_VERSION = "9.11.2"
|
|
DEPENDENCY_NAME = "rocksdb"
|
|
dependency_dir = deps_dir / f"{DEPENDENCY_NAME}-{ROCKSDB_VERSION}"
|
|
dependency_install_dir = install_dir / DEPENDENCY_NAME
|
|
|
|
if is_already_installed(dependency_install_dir, expected_build_cfg=build_cfg):
|
|
return
|
|
|
|
ROCKSDB_ZIP = f"rocksdb-{ROCKSDB_VERSION}.zip"
|
|
download_file(
|
|
DEPENDENCY_NAME,
|
|
f"https://github.com/facebook/rocksdb/archive/refs/tags/v{ROCKSDB_VERSION}.zip",
|
|
deps_dir / ROCKSDB_ZIP,
|
|
)
|
|
|
|
extract_file(
|
|
DEPENDENCY_NAME,
|
|
deps_dir / ROCKSDB_ZIP,
|
|
deps_dir,
|
|
dependency_dir,
|
|
)
|
|
|
|
# see rocksdb/thirdparty.inc
|
|
# providing package is not supported on Windows.
|
|
# ZSTD_INCLUDE / ZSTD_LIB_DEBUG / ZSTD_LIB_RELEASE must be env vars - as cmake -D args they have no effect on MSVC.
|
|
zstd_include = install_dir / "zstd" / "include"
|
|
zstd_lib = install_dir / "zstd" / "lib" / "zstd_static.lib"
|
|
|
|
run_cmake(
|
|
DEPENDENCY_NAME,
|
|
dependency_dir,
|
|
vs_cfg_vars,
|
|
build_type,
|
|
f"-DCMAKE_INSTALL_PREFIX={dependency_install_dir}",
|
|
"-DROCKSDB_INSTALL_ON_WINDOWS=ON",
|
|
"-DFAIL_ON_WARNINGS=OFF",
|
|
"-DWITH_TESTS=OFF",
|
|
"-DWITH_TOOLS=OFF",
|
|
"-DWITH_BENCHMARK_TOOLS=OFF",
|
|
"-DWITH_CORE_TOOLS=OFF",
|
|
"-DROCKSDB_BUILD_SHARED=OFF",
|
|
"-DWITH_ZSTD=ON",
|
|
"-DPORTABLE=1",
|
|
"-DCMAKE_DEBUG_POSTFIX=_d",
|
|
env={
|
|
"ZSTD_INCLUDE": str(zstd_include),
|
|
"ZSTD_LIB_DEBUG": str(zstd_lib),
|
|
"ZSTD_LIB_RELEASE": str(zstd_lib),
|
|
},
|
|
)
|
|
|
|
build_path = dependency_dir / vs_cfg_vars.build_dir
|
|
build_cmake_project(DEPENDENCY_NAME, build_path, build_cfg, msbuild_multiproc)
|
|
install_cmake_project(DEPENDENCY_NAME, build_path, build_cfg)
|
|
mark_installation(dependency_install_dir, build_cfg)
|
|
|
|
|
|
def install_manifold(
|
|
vs_cfg_vars: VsCfgResult,
|
|
build_type: BuildType,
|
|
build_deps_cache: BuildDepsCache,
|
|
build_cfg: BuildCfg,
|
|
msbuild_multiproc: tuple[str, ...],
|
|
) -> None:
|
|
deps_dir = vs_cfg_vars.deps_dir
|
|
install_dir = vs_cfg_vars.install_dir
|
|
|
|
MANIFOLD_VERSION = "3.2.1"
|
|
DEPENDENCY_NAME = "manifold"
|
|
dependency_dir = deps_dir / f"{DEPENDENCY_NAME}-{MANIFOLD_VERSION}"
|
|
dependency_install_dir = install_dir / f"{DEPENDENCY_NAME}-{MANIFOLD_VERSION}"
|
|
|
|
# TODO: test whether manifold links the debug CRT for Debug builds and needs separate
|
|
# Release/Debug install dirs instead of sharing one.
|
|
build_deps_cache.add_entry("MANIFOLD_INSTALL_PATH", str(dependency_install_dir))
|
|
|
|
if is_already_installed(dependency_install_dir):
|
|
return
|
|
|
|
git_clone_and_checkout_revision(
|
|
DEPENDENCY_NAME,
|
|
"https://github.com/elalish/manifold.git",
|
|
dependency_dir,
|
|
f"v{MANIFOLD_VERSION}",
|
|
)
|
|
|
|
run_cmake(
|
|
DEPENDENCY_NAME,
|
|
dependency_dir,
|
|
vs_cfg_vars,
|
|
build_type,
|
|
f"-DCMAKE_INSTALL_PREFIX={dependency_install_dir}",
|
|
"-DBUILD_SHARED_LIBS=OFF",
|
|
"-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",
|
|
)
|
|
|
|
build_path = dependency_dir / vs_cfg_vars.build_dir
|
|
build_cmake_project(DEPENDENCY_NAME, build_path, build_cfg, msbuild_multiproc)
|
|
install_cmake_project(DEPENDENCY_NAME, build_path, build_cfg)
|