mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 23:31:00 +00:00
392 lines
15 KiB
Python
392 lines
15 KiB
Python
# /// script
|
|
# [tool.ty.environment]
|
|
# # Lets ty resolve sibling imports (common, installers, etc).
|
|
# 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 argparse
|
|
import multiprocessing
|
|
import shutil
|
|
import sys
|
|
from datetime import datetime
|
|
from typing import NamedTuple
|
|
|
|
from common import (
|
|
BUILD_CFG_DEFAULT,
|
|
BUILD_CFGS,
|
|
BUILD_TYPE_DEFAULT,
|
|
BUILD_TYPES,
|
|
PROJECT_NAME,
|
|
REPO_ROOT,
|
|
SCRIPT_DIR,
|
|
BuildCfg,
|
|
BuildDepsCache,
|
|
BuildType,
|
|
C,
|
|
HelpStrings,
|
|
colorize,
|
|
ensure_script_dir,
|
|
logger,
|
|
require_command,
|
|
resolve_cli_or_env,
|
|
validate_cmake_version,
|
|
)
|
|
from installers import (
|
|
install_boost,
|
|
install_ccache,
|
|
install_cgal,
|
|
install_eigen,
|
|
install_json,
|
|
install_manifold,
|
|
install_mpfr,
|
|
install_mpir,
|
|
install_nuget,
|
|
install_occt,
|
|
install_opencollada,
|
|
install_proj,
|
|
install_python,
|
|
install_qt6,
|
|
install_rocksdb,
|
|
install_swig,
|
|
install_zstd,
|
|
)
|
|
from vs_cfg import VsCfgResult, get_vs_var, vs_cfg
|
|
|
|
|
|
class Args(NamedTuple):
|
|
generator: str | None
|
|
build_cfg: BuildCfg
|
|
build_type: BuildType
|
|
reuse_boost: bool
|
|
num_build_procs: int
|
|
install_python: bool
|
|
python_version: str
|
|
install_qt6: bool
|
|
qt6_version: str
|
|
yes: bool
|
|
|
|
|
|
def print_build_config(
|
|
vs_cfg_vars: VsCfgResult,
|
|
build_cfg: BuildCfg,
|
|
build_type: BuildType,
|
|
ifcos_install_python: bool,
|
|
ifcos_install_qt6: bool,
|
|
ifcos_num_build_procs: int,
|
|
) -> None:
|
|
def field(text: str) -> str:
|
|
return colorize(text, C.PURPLE)
|
|
|
|
logger.info(colorize("Script configuration:", C.GREEN))
|
|
logger.info(field(f"* CMake Generator\t= '{vs_cfg_vars.generator.name}'"))
|
|
logger.info(" - Passed to CMake -G option.")
|
|
logger.info(field(f"* Target Platform\t= {vs_cfg_vars.vs_platform}"))
|
|
logger.info(" - Whether were doing 32-bit (Win32) or 64-bit (x64, ARM64) build. Passed to CMake -A option.")
|
|
logger.info(field(f"* Target Toolset Override\t= {vs_cfg_vars.vs_toolset_override}"))
|
|
logger.info(" - Passed to CMake -T option.")
|
|
logger.info(field(f"* Dependency Directory\t= {vs_cfg_vars.deps_dir}"))
|
|
logger.info(f" - The directory where {PROJECT_NAME} dependencies are fetched and built.")
|
|
logger.info(field(f"* Installation Directory = {vs_cfg_vars.install_dir}"))
|
|
logger.info(f" - The directory where {PROJECT_NAME} dependencies are installed.")
|
|
logger.info(field(f"* Build Config Type\t= {build_cfg}"))
|
|
logger.info(" - The used build configuration type for the dependencies.")
|
|
logger.info(" Defaults to RelWithDebInfo if not specified.")
|
|
if build_cfg == "MinSizeRel":
|
|
logger.warning(" WARNING: MinSizeRel build can suffer from a significant performance loss.")
|
|
logger.info(field(f"* Build Type\t\t= {build_type}"))
|
|
logger.info(" - The used build type for the dependencies (Build, Rebuild, Clean).")
|
|
logger.info(" Defaults to Build if not specified.")
|
|
logger.info(field(f"* IFCOS_INSTALL_PYTHON\t= {ifcos_install_python}"))
|
|
logger.info(" - Download and install Python.")
|
|
logger.info(" Set to something other than TRUE if you wish to use an already installed version of Python.")
|
|
logger.info(
|
|
" But then you'll need to set PYTHONHOME env variable to your Python installation before running run-cmake.py"
|
|
)
|
|
logger.info(" to your Python installation path.")
|
|
logger.info(field(f"* IFCOS_INSTALL_QT6\t= {ifcos_install_qt6}"))
|
|
logger.info(" - Download and install Qt6 using aqtinstall.")
|
|
logger.info(" Set to something other than TRUE if you wish to use an already installed version of Qt6.")
|
|
logger.info(
|
|
" But then you'll need to set QT_DIR env variable to your Qt6 installation before running run-cmake.py."
|
|
)
|
|
logger.info(field(f"* IFCOS_NUM_BUILD_PROCS\t= {ifcos_num_build_procs}"))
|
|
logger.info(" - How many MSBuild.exe processes may be run in parallel.")
|
|
logger.info(" Defaults to NUMBER_OF_PROCESSORS. Used also by other IfcOpenShell build scripts.\n")
|
|
|
|
|
|
def print_success(start_time: datetime) -> None:
|
|
logger.info("")
|
|
logger.info(colorize(f"{PROJECT_NAME} dependencies built.", C.GREEN))
|
|
|
|
end_time = datetime.now().replace(microsecond=0)
|
|
logger.info("")
|
|
logger.info(f"Build ended at {end_time}. Time elapsed {end_time - start_time}.")
|
|
|
|
|
|
def parse_args() -> Args:
|
|
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
parser.add_argument(
|
|
"generator",
|
|
nargs="?",
|
|
default=None,
|
|
help=HelpStrings.generator("deduced from the active Visual Studio environment"),
|
|
)
|
|
parser.add_argument(
|
|
"--generator",
|
|
dest="generator_flag",
|
|
default=None,
|
|
help=HelpStrings.GENERATOR_FLAG,
|
|
)
|
|
# SUPPRESS avoids a misleading "(default: None)" in `--help`,
|
|
# though then arg might not be set and we use `getattr` to get it.
|
|
parser.add_argument(
|
|
"build_cfg",
|
|
nargs="?",
|
|
default=argparse.SUPPRESS,
|
|
choices=BUILD_CFGS,
|
|
help=HelpStrings.BUILD_CFG,
|
|
)
|
|
parser.add_argument(
|
|
"--build-cfg",
|
|
dest="build_cfg_flag",
|
|
default=BUILD_CFG_DEFAULT,
|
|
choices=BUILD_CFGS,
|
|
help=HelpStrings.BUILD_CFG_FLAG,
|
|
)
|
|
parser.add_argument(
|
|
"build_type",
|
|
nargs="?",
|
|
default=argparse.SUPPRESS,
|
|
choices=BUILD_TYPES,
|
|
help=f"Build type. (default: {BUILD_TYPE_DEFAULT})",
|
|
)
|
|
parser.add_argument(
|
|
"--build-type",
|
|
dest="build_type_flag",
|
|
default=BUILD_TYPE_DEFAULT,
|
|
choices=BUILD_TYPES,
|
|
help="Alternative way to specify the build type, instead of the positional argument.",
|
|
)
|
|
parser.add_argument(
|
|
"--log-level",
|
|
default="INFO",
|
|
choices=("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"),
|
|
help="Logging verbosity.",
|
|
)
|
|
parser.add_argument(
|
|
"--reuse-boost",
|
|
action="store_true",
|
|
help=(
|
|
"Skip building Boost if it's already installed from this script's previous runs, instead of always rebuilding it. "
|
|
"Speeds up the build a bit when iterating/debugging this script."
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--num-build-procs",
|
|
dest="num_build_procs",
|
|
type=int,
|
|
default=argparse.SUPPRESS,
|
|
help=HelpStrings.NUM_BUILD_PROCS,
|
|
)
|
|
INSTALL_PYTHON_DEFAULT = True
|
|
parser.add_argument(
|
|
"--install-python",
|
|
dest="install_python",
|
|
action=argparse.BooleanOptionalAction,
|
|
default=argparse.SUPPRESS,
|
|
help=(
|
|
"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. "
|
|
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",
|
|
action=argparse.BooleanOptionalAction,
|
|
default=argparse.SUPPRESS,
|
|
help=(
|
|
"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. "
|
|
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(
|
|
"-y",
|
|
"--yes",
|
|
action="store_true",
|
|
help="Skip the confirmation prompt before proceeding with the build.",
|
|
)
|
|
args = parser.parse_args()
|
|
logger.setLevel(args.log_level)
|
|
|
|
if args.generator is not None and args.generator_flag is not None:
|
|
parser.error("generator was specified both as a positional argument and as --generator.")
|
|
generator = args.generator or args.generator_flag
|
|
|
|
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 = resolve_cli_or_env(
|
|
getattr(args, "num_build_procs", None),
|
|
"IFCOS_NUM_BUILD_PROCS",
|
|
multiprocessing.cpu_count(),
|
|
arg_type="int",
|
|
)
|
|
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,
|
|
build_cfg=build_cfg,
|
|
build_type=build_type,
|
|
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,
|
|
)
|
|
|
|
|
|
def main() -> None:
|
|
ARGS = parse_args()
|
|
|
|
logger.info(f"This script fetches and builds all {PROJECT_NAME} dependencies\n")
|
|
|
|
ensure_script_dir()
|
|
|
|
# Make sure vcvarsall.bat is called and dev env set is up.
|
|
get_vs_var("VSINSTALLDIR")
|
|
|
|
# Check for cl.exe - at least the "Typical" Visual Studio 2015 installation does not include the C++ toolset by default,
|
|
# http://blogs.msdn.com/b/vcblog/archive/2015/07/24/setup-changes-in-visual-studio-2015-affecting-c-developers.aspx
|
|
if not shutil.which("cl"):
|
|
logger.error(
|
|
"cl.exe not in PATH. Make sure to select the C++ toolset when installing Visual Studio- cannot proceed."
|
|
)
|
|
sys.exit(1)
|
|
|
|
vs_cfg_vars = vs_cfg(ARGS.generator, REPO_ROOT)
|
|
build_deps_cache = BuildDepsCache(vs_cfg_vars)
|
|
|
|
# Cache last used CMake generator and configurable dependency dirs for other scripts to use.
|
|
build_deps_cache.add_entry("GEN_SHORTHAND", vs_cfg_vars.gen_shorthand)
|
|
|
|
# Make sure deps and install folders exists.
|
|
vs_cfg_vars.deps_dir.mkdir(parents=True, exist_ok=True)
|
|
vs_cfg_vars.install_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Note BUILD_TYPE not passed, Clean e.g. wouldn't delete the installed files.
|
|
# TODO: consider inlining.
|
|
MSBUILD_MULTIPROC = (
|
|
"/m",
|
|
f"/p:CL_MPCount={ARGS.num_build_procs}",
|
|
"/p:UseMultiToolTask=true",
|
|
"/p:EnforceProcessCountAcrossBuilds=true",
|
|
)
|
|
MSBUILD_CMD = ("MSBuild.exe", "/nologo", *MSBUILD_MULTIPROC)
|
|
|
|
# Check that required tools are in PATH.
|
|
# TODO: drop "powershell" later.
|
|
REQUIRED_COMMANDS = ("powershell", "git", "cmake", "7z")
|
|
for command in REQUIRED_COMMANDS:
|
|
require_command(command)
|
|
|
|
validate_cmake_version()
|
|
|
|
print_build_config(
|
|
vs_cfg_vars,
|
|
ARGS.build_cfg,
|
|
ARGS.build_type,
|
|
ARGS.install_python,
|
|
ARGS.install_qt6,
|
|
ARGS.num_build_procs,
|
|
)
|
|
|
|
logger.warning("Warning: You will need roughly 8 GB of disk space to proceed.\n")
|
|
if not ARGS.yes:
|
|
logger.info(
|
|
"If you are not ready with the above: type 'n' in the prompt below. Build proceeds on all other inputs!"
|
|
)
|
|
do_continue = input("> ")
|
|
if do_continue == "n":
|
|
sys.exit(0)
|
|
|
|
START_TIME = datetime.now().replace(microsecond=0)
|
|
logger.info(f"Build started at {START_TIME}.")
|
|
|
|
nuget_exe = install_nuget(vs_cfg_vars.deps_dir)
|
|
install_ccache(vs_cfg_vars.deps_dir, nuget_exe, build_deps_cache)
|
|
install_proj(vs_cfg_vars, ARGS.build_type, ARGS.build_cfg, MSBUILD_MULTIPROC)
|
|
install_mpir(vs_cfg_vars, vs_cfg_vars.deps_dir, vs_cfg_vars.install_dir, ARGS.build_cfg)
|
|
install_mpfr(
|
|
vs_cfg_vars, vs_cfg_vars.deps_dir, vs_cfg_vars.install_dir, ARGS.build_cfg, ARGS.build_type, MSBUILD_CMD
|
|
)
|
|
install_boost(vs_cfg_vars, build_deps_cache, ARGS.build_cfg, ARGS.num_build_procs, ARGS.reuse_boost)
|
|
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, 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, ARGS.qt6_version, pythonhome)
|
|
install_manifold(vs_cfg_vars, ARGS.build_type, build_deps_cache, ARGS.build_cfg, MSBUILD_MULTIPROC)
|
|
|
|
print_success(START_TIME)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|