From befc031ec55149cc807392ead02ce80d8e3c2069 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Mon, 14 Sep 2026 15:06:42 +0500 Subject: [PATCH] build-deps.py: cli args to provide qt6 and Python version --- win/build-deps.py | 58 +++++++++++++++++++++++++++++---------- win/build-ifcopenshell.py | 6 ++-- win/common.py | 27 +++++++++++++++++- win/installers.py | 42 ++++++++++++---------------- 4 files changed, 90 insertions(+), 43 deletions(-) diff --git a/win/build-deps.py b/win/build-deps.py index 740ecf2908..628990ee10 100644 --- a/win/build-deps.py +++ b/win/build-deps.py @@ -24,7 +24,6 @@ # import argparse import multiprocessing -import os import shutil import sys from datetime import datetime @@ -45,9 +44,9 @@ from common import ( HelpStrings, colorize, ensure_script_dir, - is_on_off, logger, require_command, + resolve_cli_or_env, validate_cmake_version, ) from installers import ( @@ -79,7 +78,9 @@ class Args(NamedTuple): reuse_boost: bool num_build_procs: int install_python: bool + python_version: str install_qt6: bool + qt6_version: str yes: bool @@ -206,6 +207,7 @@ def parse_args() -> Args: default=argparse.SUPPRESS, help=HelpStrings.NUM_BUILD_PROCS, ) + INSTALL_PYTHON_DEFAULT = True parser.add_argument( "--install-python", dest="install_python", @@ -215,9 +217,20 @@ def parse_args() -> Args: "Download and install Python. If disabled, an already installed Python is used - " "set the PYTHONHOME env variable to its installation path before running run-cmake.py. " "Also can be specified by using IFCOS_INSTALL_PYTHON env variable. " - "(default: True)" + f"(default: {INSTALL_PYTHON_DEFAULT})" ), ) + PYTHON_VERSION_DEFAULT = "3.11.7" + parser.add_argument( + "--python-version", + dest="python_version", + default=None, + help=( + "Python version to download and install. Also can be specified by using PYTHON_VERSION env variable. " + f"(default: {PYTHON_VERSION_DEFAULT})" + ), + ) + INSTALL_QT6_DEFAULT = True parser.add_argument( "--install-qt6", dest="install_qt6", @@ -227,7 +240,17 @@ def parse_args() -> Args: "Download and install Qt6 using aqtinstall. If disabled, an already installed Qt6 is used - " "set the QT_DIR env variable to its installation path before running run-cmake.py. " "Also can be specified by using IFCOS_INSTALL_QT6 env variable. " - "(default: True)" + f"(default: {INSTALL_QT6_DEFAULT})" + ), + ) + QT6_VERSION_DEFAULT = "6.8.3" + parser.add_argument( + "--qt6-version", + dest="qt6_version", + default=None, + help=( + "Qt6 version to download and install. Also can be specified by using QT6_VERSION env variable. " + f"(default: {QT6_VERSION_DEFAULT})" ), ) parser.add_argument( @@ -246,15 +269,20 @@ def parse_args() -> Args: build_cfg = getattr(args, "build_cfg", None) or args.build_cfg_flag build_type = getattr(args, "build_type", None) or args.build_type_flag - num_build_procs = getattr(args, "num_build_procs", None) or int( - os.getenv("IFCOS_NUM_BUILD_PROCS") or multiprocessing.cpu_count() + num_build_procs = resolve_cli_or_env( + getattr(args, "num_build_procs", None), + "IFCOS_NUM_BUILD_PROCS", + multiprocessing.cpu_count(), + arg_type="int", ) - install_python = getattr(args, "install_python", None) - if install_python is None: - install_python = is_on_off(os.getenv("IFCOS_INSTALL_PYTHON"), default=True) - install_qt6 = getattr(args, "install_qt6", None) - if install_qt6 is None: - install_qt6 = is_on_off(os.getenv("IFCOS_INSTALL_QT6"), default=True) + install_python = resolve_cli_or_env( + getattr(args, "install_python", None), "IFCOS_INSTALL_PYTHON", INSTALL_PYTHON_DEFAULT, arg_type="bool" + ) + python_version = resolve_cli_or_env(args.python_version, "PYTHON_VERSION", PYTHON_VERSION_DEFAULT, arg_type="str") + install_qt6 = resolve_cli_or_env( + getattr(args, "install_qt6", None), "IFCOS_INSTALL_QT6", INSTALL_QT6_DEFAULT, arg_type="bool" + ) + qt6_version = resolve_cli_or_env(args.qt6_version, "QT6_VERSION", QT6_VERSION_DEFAULT, arg_type="str") return Args( generator=generator, @@ -263,7 +291,9 @@ def parse_args() -> Args: reuse_boost=args.reuse_boost, num_build_procs=num_build_procs, install_python=install_python, + python_version=python_version, install_qt6=install_qt6, + qt6_version=qt6_version, yes=args.yes, ) @@ -346,13 +376,13 @@ def main() -> None: install_json(vs_cfg_vars.install_dir) install_opencollada(vs_cfg_vars, ARGS.build_type, ARGS.build_cfg, MSBUILD_MULTIPROC) install_occt(vs_cfg_vars, ARGS.build_type, build_deps_cache, ARGS.build_cfg, MSBUILD_MULTIPROC) - pythonhome = install_python(vs_cfg_vars, ARGS.install_python, build_deps_cache, nuget_exe) + pythonhome = install_python(vs_cfg_vars, ARGS.install_python, ARGS.python_version, build_deps_cache, nuget_exe) install_swig(vs_cfg_vars, ARGS.build_type, build_deps_cache, MSBUILD_MULTIPROC) install_cgal(vs_cfg_vars, ARGS.build_type, ARGS.build_cfg, MSBUILD_MULTIPROC) install_eigen(vs_cfg_vars) install_zstd(vs_cfg_vars, ARGS.build_type, ARGS.build_cfg, MSBUILD_MULTIPROC) install_rocksdb(vs_cfg_vars, ARGS.build_type, ARGS.build_cfg, MSBUILD_MULTIPROC) - install_qt6(vs_cfg_vars, build_deps_cache, ARGS.build_cfg, ARGS.install_qt6, pythonhome) + install_qt6(vs_cfg_vars, build_deps_cache, ARGS.build_cfg, ARGS.install_qt6, ARGS.qt6_version, pythonhome) install_manifold(vs_cfg_vars, ARGS.build_type, build_deps_cache, ARGS.build_cfg, MSBUILD_MULTIPROC) print_success(START_TIME) diff --git a/win/build-ifcopenshell.py b/win/build-ifcopenshell.py index 84f8b20e54..31f8da6ac9 100644 --- a/win/build-ifcopenshell.py +++ b/win/build-ifcopenshell.py @@ -23,7 +23,6 @@ # import argparse import multiprocessing -import os import sys from typing import NamedTuple, NoReturn @@ -38,6 +37,7 @@ from common import ( colorize, ensure_script_dir, logger, + resolve_cli_or_env, resolve_generator, run_streamed, ) @@ -127,8 +127,8 @@ def parse_args() -> Args: build_cfg = getattr(args, "build_cfg", None) or args.build_cfg_flag - num_build_procs = getattr(args, "num_build_procs", None) or int( - os.getenv("IFCOS_NUM_BUILD_PROCS") or multiprocessing.cpu_count() + num_build_procs = resolve_cli_or_env( + getattr(args, "num_build_procs", None), "IFCOS_NUM_BUILD_PROCS", multiprocessing.cpu_count(), arg_type="int" ) return Args( diff --git a/win/common.py b/win/common.py index 7b39adf1f1..e8e8fd25da 100644 --- a/win/common.py +++ b/win/common.py @@ -27,7 +27,7 @@ import shutil import subprocess import sys from pathlib import Path -from typing import TYPE_CHECKING, Literal, get_args +from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast, get_args if TYPE_CHECKING: from vs_cfg import VsCfgResult @@ -99,6 +99,31 @@ def is_on_off(value: str | None, *, default: bool) -> bool: return default +T = TypeVar("T") + + +def resolve_cli_or_env( + cli_value: T | None, env_var_name: str, default: T, *, arg_type: Literal["str", "int", "bool"] +) -> T: + if cli_value is not None: + return cli_value + env_value = os.getenv(env_var_name) + if not env_value: + return default + logger.info(f"Using {env_var_name} from env: '{env_value}'") + parsed: Any = env_value + if arg_type == "str": + parsed = env_value + elif arg_type == "int": + parsed = int(env_value) + elif arg_type == "bool": + parsed = is_on_off(env_value, default=True) + else: + # TODO: use assert_never once we bump min version to 3.11. + assert False, f"Unhandled arg_type: {arg_type!r}" + return cast(T, parsed) + + OFF_ON = ("OFF", "ON") diff --git a/win/installers.py b/win/installers.py index 7fc24e7db1..434703d107 100644 --- a/win/installers.py +++ b/win/installers.py @@ -757,16 +757,10 @@ def install_qt6( build_deps_cache: BuildDepsCache, build_cfg: BuildCfg, ifcos_install_qt6: bool, + qt6_version: str, 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) + build_deps_cache.add_entry("QT6_VERSION", qt6_version) vs_toolset = vs_cfg_vars.vs_toolset QT6_MSVC_YEAR = VS_TOOLSET_TO_VS_VER[vs_toolset] @@ -800,9 +794,9 @@ def install_qt6( ) sys.exit(1) - DEPENDENCY_INSTALL_NAME = f"qt6-{QT6_VERSION}-{QT6_INSTALL_SUFFIX}" + 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 + QT6_INSTALL_DIR = QT6_AQT_OUTPUT_DIR / qt6_version / QT6_INSTALL_SUFFIX QT_DIR = QT6_INSTALL_DIR QT6_HOST_AQT_OUTPUT_DIR = None @@ -810,8 +804,8 @@ def install_qt6( 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 + 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" @@ -869,7 +863,7 @@ def install_qt6( "install-qt", "windows", "desktop", - QT6_VERSION, + qt6_version, arch, "-O", str(output_dir), @@ -909,15 +903,13 @@ def install_qt6( def install_python( - vs_cfg_vars: VsCfgResult, ifcos_install_python: bool, build_deps_cache: BuildDepsCache, nuget_exe: Path + vs_cfg_vars: VsCfgResult, + ifcos_install_python: bool, + python_version: str, + 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 @@ -925,14 +917,14 @@ def install_python( 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") + 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" + PYTHONHOME = vs_cfg_vars.deps_dir / f"pythonarm64.{python_version}" / "tools" else: - PYTHONHOME = vs_cfg_vars.deps_dir / f"python.{PYTHON_VERSION}" / "tools" + PYTHONHOME = vs_cfg_vars.deps_dir / f"python.{python_version}" / "tools" build_deps_cache.add_entry("PYTHONHOME", str(PYTHONHOME)) @@ -946,7 +938,7 @@ def install_python( "install", nuget_package, "-Version", - PYTHON_VERSION, + python_version, "-OutputDirectory", str(vs_cfg_vars.deps_dir), )