mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 14:23:53 +00:00
Add install-/build-ifcopenshell.py, deprecate corresponding .bat files
Mainly drop-in replacement for `build-ifcopenshell.bat` with `--help`, kw args and args validation, but there's a small caveat. Previously it was possible to pass args to the underlying build tool as simple positionals - e.g. `build-ifcopenshell vs2022-x64 Release /p:Foo=bar`. This behaviour is disabled now, because it doesn't allow validating provided args - it's impossible to tell whether `--config Release` is meant to be passed to msbuild or was meant as `--build-cfg Release` for `build-ifcopenshell`. But it's still possible to pass args to msbuild by using `--` - `python build-ifcopenshell.py vs2022-x64 Release -- /p:Foo=bar` `install-ifcopenshell.py` is now just a small wrapper passing `--target INSTALL` arg.
This commit is contained in:
@@ -236,7 +236,7 @@ def build() -> None:
|
||||
]
|
||||
)
|
||||
restore_env(*OLD_ADD_COMMIT_SHA)
|
||||
run([str(REPO_WIN / "install-ifcopenshell.bat"), build_generator(), "Release"])
|
||||
run([sys.executable, str(REPO_WIN / "install-ifcopenshell.py"), build_generator(), "Release"])
|
||||
|
||||
|
||||
def archive_executables() -> None:
|
||||
|
||||
+8
-19
@@ -28,7 +28,6 @@ import os
|
||||
import shutil
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import NamedTuple
|
||||
|
||||
from common import (
|
||||
@@ -43,7 +42,9 @@ from common import (
|
||||
BuildDepsCache,
|
||||
BuildType,
|
||||
C,
|
||||
HelpStrings,
|
||||
colorize,
|
||||
ensure_script_dir,
|
||||
is_on_off,
|
||||
logger,
|
||||
require_command,
|
||||
@@ -144,19 +145,13 @@ def parse_args() -> Args:
|
||||
"generator",
|
||||
nargs="?",
|
||||
default=None,
|
||||
help=(
|
||||
"CMake generator to use. Accepts 3 forms: "
|
||||
"(1) omitted - deduced from the active Visual Studio environment; "
|
||||
"(2) shorthand, e.g. 'vs2022', 'vs2022-x64', 'vs2019-x86-v141' - optionally provide platform/toolset "
|
||||
"using the suffix; "
|
||||
"(3) full CMake generator name, e.g. 'Visual Studio 17 2022'."
|
||||
),
|
||||
help=HelpStrings.generator("deduced from the active Visual Studio environment"),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--generator",
|
||||
dest="generator_flag",
|
||||
default=None,
|
||||
help="Alternative way to specify the generator, instead of the positional argument. See above for accepted forms.",
|
||||
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.
|
||||
@@ -165,14 +160,14 @@ def parse_args() -> Args:
|
||||
nargs="?",
|
||||
default=argparse.SUPPRESS,
|
||||
choices=BUILD_CFGS,
|
||||
help=f"Build configuration type. (default: {BUILD_CFG_DEFAULT})",
|
||||
help=HelpStrings.BUILD_CFG,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--build-cfg",
|
||||
dest="build_cfg_flag",
|
||||
default=BUILD_CFG_DEFAULT,
|
||||
choices=BUILD_CFGS,
|
||||
help="Alternative way to specify the build configuration type, instead of the positional argument.",
|
||||
help=HelpStrings.BUILD_CFG_FLAG,
|
||||
)
|
||||
parser.add_argument(
|
||||
"build_type",
|
||||
@@ -208,11 +203,7 @@ def parse_args() -> Args:
|
||||
dest="num_build_procs",
|
||||
type=int,
|
||||
default=argparse.SUPPRESS,
|
||||
help=(
|
||||
"How many build processes may be run in parallel. "
|
||||
"Also can be specified by using IFCOS_NUM_BUILD_PROCS env variable. "
|
||||
"(default: NUMBER_OF_PROCESSORS)"
|
||||
),
|
||||
help=HelpStrings.NUM_BUILD_PROCS,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--install-python",
|
||||
@@ -274,9 +265,7 @@ def main() -> None:
|
||||
|
||||
logger.info(f"This script fetches and builds all {PROJECT_NAME} dependencies\n")
|
||||
|
||||
if Path.cwd() != SCRIPT_DIR:
|
||||
logger.error(f"This script must be run from '{SCRIPT_DIR}'.")
|
||||
sys.exit(1)
|
||||
ensure_script_dir()
|
||||
|
||||
# Make sure vcvarsall.bat is called and dev env set is up.
|
||||
get_vs_var("VSINSTALLDIR")
|
||||
|
||||
@@ -58,6 +58,11 @@ if not defined IFCOS_NUM_BUILD_PROCS set IFCOS_NUM_BUILD_PROCS=%NUMBER_OF_PROCES
|
||||
call cecho.cmd 0 13 "* IFCOS_NUM_BUILD_PROCS`t= %IFCOS_NUM_BUILD_PROCS%"
|
||||
echo.
|
||||
|
||||
call cecho.cmd 0 12 "WARNING: build-ifcopenshell.bat is deprecated since 11 Sep 2026 and will be removed very shortly."
|
||||
call cecho.cmd 0 12 "Use `python build-ifcopenshell.py` instead. It's intended to be a drop-in replacement, so exactly the same args apply,"
|
||||
call cecho.cmd 0 12 "except MSBuild args now need to be passed after `"--`", e.g. `python build-ifcopenshell.py vs2022-x64 -- /p:Foo=bar`."
|
||||
echo.
|
||||
|
||||
call cecho.cmd 0 13 "Building %VS_PLATFORM% %BUILD_CFG% %PROJECT_NAME%"
|
||||
set MSBUILD_MULTIPROC=/m /p:CL_MPCount=%IFCOS_NUM_BUILD_PROCS% /p:UseMultiToolTask=true /p:EnforceProcessCountAcrossBuilds=true
|
||||
cmake --build ..\%BUILD_DIR% -- /nologo %MSBUILD_MULTIPROC% /p:Platform=%VS_PLATFORM% /p:Configuration=%BUILD_CFG% ^
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
# /// 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 argparse
|
||||
import multiprocessing
|
||||
import os
|
||||
import sys
|
||||
from typing import NamedTuple, NoReturn
|
||||
|
||||
from common import (
|
||||
BUILD_CFG_DEFAULT,
|
||||
BUILD_CFGS,
|
||||
PROJECT_NAME,
|
||||
REPO_ROOT,
|
||||
BuildCfg,
|
||||
C,
|
||||
HelpStrings,
|
||||
colorize,
|
||||
ensure_script_dir,
|
||||
find_cached_gen_shorthand,
|
||||
logger,
|
||||
run_streamed,
|
||||
)
|
||||
from vs_cfg import vs_cfg
|
||||
|
||||
|
||||
class Args(NamedTuple):
|
||||
generator: str | None
|
||||
build_cfg: BuildCfg
|
||||
num_build_procs: int
|
||||
target: str | None
|
||||
extra_args: list[str]
|
||||
|
||||
|
||||
class ArgumentParser(argparse.ArgumentParser):
|
||||
def error(self, message: str) -> NoReturn:
|
||||
# TODO: this hint can be removed later, it's just for anyone transitioning from build-ifcopenshell.bat,
|
||||
# which allowed providing additional args as positionals. We disallow it here (they can be passed after
|
||||
# '--') to ensure we can validate the provided args.
|
||||
if message.startswith("unrecognized arguments"):
|
||||
message += (
|
||||
"\nHint: put args meant for the underlying build tool (e.g. MSBuild) after '--', "
|
||||
"e.g. `build-ifcopenshell.py -- /p:Foo=bar`."
|
||||
)
|
||||
super().error(message)
|
||||
|
||||
|
||||
def parse_args() -> Args:
|
||||
parser = ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
epilog="Arguments after '--' are passed through as-is to the underlying build tool (e.g. MSBuild).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"generator",
|
||||
nargs="?",
|
||||
default=None,
|
||||
help=HelpStrings.generator("GEN_SHORTHAND from the most recently modified BuildDepsCache-*.txt is used"),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--generator",
|
||||
dest="generator_flag",
|
||||
default=None,
|
||||
help=HelpStrings.GENERATOR_FLAG,
|
||||
)
|
||||
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(
|
||||
"--num-build-procs",
|
||||
dest="num_build_procs",
|
||||
type=int,
|
||||
default=argparse.SUPPRESS,
|
||||
help=HelpStrings.NUM_BUILD_PROCS,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--target",
|
||||
dest="target",
|
||||
default=None,
|
||||
help=(
|
||||
"cmake --build target, passed as-is. E.g. 'INSTALL' to also install after building. "
|
||||
"By default no target is passed, which builds the whole solution."
|
||||
),
|
||||
)
|
||||
argv = sys.argv[1:]
|
||||
if "--" in argv:
|
||||
separator_idx = argv.index("--")
|
||||
own_argv, extra_args = argv[:separator_idx], argv[separator_idx + 1 :]
|
||||
else:
|
||||
own_argv, extra_args = argv, []
|
||||
|
||||
args = parser.parse_args(own_argv)
|
||||
|
||||
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
|
||||
|
||||
num_build_procs = getattr(args, "num_build_procs", None) or int(
|
||||
os.getenv("IFCOS_NUM_BUILD_PROCS") or multiprocessing.cpu_count()
|
||||
)
|
||||
|
||||
return Args(
|
||||
generator=generator,
|
||||
build_cfg=build_cfg,
|
||||
num_build_procs=num_build_procs,
|
||||
target=args.target,
|
||||
extra_args=extra_args,
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ARGS = parse_args()
|
||||
|
||||
ensure_script_dir()
|
||||
|
||||
generator = ARGS.generator
|
||||
if generator is None:
|
||||
generator = find_cached_gen_shorthand()
|
||||
if generator is None:
|
||||
logger.error(
|
||||
"BuildDepsCache file does not exist and/or GEN_SHORTHAND missing from it. Run build-deps.py to create it."
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
vs_cfg_vars = vs_cfg(generator, REPO_ROOT)
|
||||
|
||||
logger.info("")
|
||||
logger.info(colorize(f"* IFCOS_NUM_BUILD_PROCS\t= {ARGS.num_build_procs}", C.PURPLE))
|
||||
logger.info("")
|
||||
|
||||
if ARGS.target:
|
||||
target_suffix = f" (target: {ARGS.target})"
|
||||
target_args = ("--target", ARGS.target)
|
||||
else:
|
||||
target_suffix = ""
|
||||
target_args = ()
|
||||
logger.info(
|
||||
colorize(f"Building {vs_cfg_vars.vs_platform} {ARGS.build_cfg} {PROJECT_NAME}{target_suffix}", C.PURPLE)
|
||||
)
|
||||
MSBUILD_MULTIPROC = (
|
||||
"/m",
|
||||
f"/p:CL_MPCount={ARGS.num_build_procs}",
|
||||
"/p:UseMultiToolTask=true",
|
||||
"/p:EnforceProcessCountAcrossBuilds=true",
|
||||
)
|
||||
run_streamed(
|
||||
"cmake",
|
||||
"--build",
|
||||
str(REPO_ROOT / vs_cfg_vars.build_dir),
|
||||
*target_args,
|
||||
"--",
|
||||
"/nologo",
|
||||
*MSBUILD_MULTIPROC,
|
||||
f"/p:Platform={vs_cfg_vars.vs_platform}",
|
||||
f"/p:Configuration={ARGS.build_cfg}",
|
||||
*ARGS.extra_args,
|
||||
)
|
||||
|
||||
logger.info("")
|
||||
logger.info(colorize(f"{vs_cfg_vars.vs_platform} {ARGS.build_cfg} {PROJECT_NAME} build finished.", C.GREEN))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -111,10 +111,41 @@ BUILD_TYPES = get_args(BuildType)
|
||||
BUILD_TYPE_DEFAULT: BuildType = "Build"
|
||||
|
||||
|
||||
class HelpStrings:
|
||||
NUM_BUILD_PROCS = (
|
||||
"How many build processes may be run in parallel. "
|
||||
"Also can be specified by using IFCOS_NUM_BUILD_PROCS env variable. "
|
||||
"(default: NUMBER_OF_PROCESSORS)"
|
||||
)
|
||||
|
||||
GENERATOR_FLAG = (
|
||||
"Alternative way to specify the generator, instead of the positional argument. See above for accepted forms."
|
||||
)
|
||||
|
||||
BUILD_CFG = f"Build configuration type. (default: {BUILD_CFG_DEFAULT})"
|
||||
BUILD_CFG_FLAG = "Alternative way to specify the build configuration type, instead of the positional argument."
|
||||
|
||||
@staticmethod
|
||||
def generator(omitted_behavior: str) -> str:
|
||||
return (
|
||||
"CMake generator to use. Accepts 3 forms: "
|
||||
f"(1) omitted - {omitted_behavior}; "
|
||||
"(2) shorthand, e.g. 'vs2022', 'vs2022-x64', 'vs2019-x86-v141' - optionally provide platform/toolset "
|
||||
"using the suffix; "
|
||||
"(3) full CMake generator name, e.g. 'Visual Studio 17 2022'."
|
||||
)
|
||||
|
||||
|
||||
def debug_or_release(build_cfg: BuildCfg) -> DebugOrRelease:
|
||||
return "Debug" if build_cfg == "Debug" else "Release"
|
||||
|
||||
|
||||
def ensure_script_dir() -> None:
|
||||
if Path.cwd() != SCRIPT_DIR:
|
||||
logger.error(f"This script must be run from '{SCRIPT_DIR}'.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def require_command(command: str) -> str:
|
||||
path = shutil.which(command)
|
||||
if not path:
|
||||
@@ -149,3 +180,21 @@ class BuildDepsCache:
|
||||
def add_entry(self, key: str, value: str) -> None:
|
||||
with self.path.open("a") as f:
|
||||
f.write(f"{key}={value}\n")
|
||||
|
||||
@staticmethod
|
||||
def parse(path: Path) -> dict[str, str]:
|
||||
entries: dict[str, str] = {}
|
||||
for line in path.read_text().splitlines():
|
||||
key, _, value = line.partition("=")
|
||||
entries[key] = value
|
||||
return entries
|
||||
|
||||
|
||||
def find_cached_gen_shorthand() -> str | None:
|
||||
"""Read GEN_SHORTHAND from the most recently modified BuildDepsCache-*.txt, if any."""
|
||||
cache_files = sorted(SCRIPT_DIR.glob("BuildDepsCache-*.txt"), key=lambda p: p.stat().st_mtime, reverse=True)
|
||||
if not cache_files:
|
||||
return None
|
||||
cache_file = cache_files[0]
|
||||
logger.info(f"Found {cache_file.name}, reading GEN_SHORTHAND from it.")
|
||||
return BuildDepsCache.parse(cache_file).get("GEN_SHORTHAND")
|
||||
|
||||
@@ -57,6 +57,11 @@ IF "%IFCOS_NUM_BUILD_PROCS%"=="" set IFCOS_NUM_BUILD_PROCS=%NUMBER_OF_PROCESSORS
|
||||
call cecho.cmd 0 13 "* IFCOS_NUM_BUILD_PROCS`t= %IFCOS_NUM_BUILD_PROCS%"
|
||||
echo.
|
||||
|
||||
call cecho.cmd 0 12 "WARNING: install-ifcopenshell.bat is deprecated since 11 Sep 2026 and will be removed very shortly."
|
||||
call cecho.cmd 0 12 "Use `python install-ifcopenshell.py` instead. It's intended to be a drop-in replacement, so exactly the same args apply,"
|
||||
call cecho.cmd 0 12 "except MSBuild args now need to be passed after `"--`", e.g. `python install-ifcopenshell.py vs2022-x64 -- /p:Foo=bar`."
|
||||
echo.
|
||||
|
||||
call cecho.cmd 0 13 "Installing %VS_PLATFORM% %BUILD_CFG% %PROJECT_NAME%"
|
||||
set MSBUILD_MULTIPROC=/m /p:CL_MPCount=%IFCOS_NUM_BUILD_PROCS% /p:UseMultiToolTask=true /p:EnforceProcessCountAcrossBuilds=true
|
||||
cmake --build ..\%BUILD_DIR% --target INSTALL -- /nologo %MSBUILD_MULTIPROC% /p:Platform=%VS_PLATFORM% ^
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# /// 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 sys
|
||||
|
||||
from common import SCRIPT_DIR, run_streamed
|
||||
|
||||
|
||||
def main() -> None:
|
||||
run_streamed(sys.executable, str(SCRIPT_DIR / "build-ifcopenshell.py"), "--target", "INSTALL", *sys.argv[1:])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+7
-7
@@ -39,11 +39,11 @@ After the dependencies are built, execute `run-cmake.bat`. The batch file expect
|
||||
Note that building IfcOpenShell as 64-bit is recommended as many of real life IFC files has been observed to take easily more than 2 GBs of RAM while converting.
|
||||
|
||||
After this, one can build the project using the `IfcOpenShell.sln` file in the build folder. Build the `INSTALL` project
|
||||
if wanted. Convenience batch files `build-ifcopenshell.bat` and `install-ifcopenshell.bat` can also be used. The batch
|
||||
files expect `%1` and `%2` in same fashion as above and possible extra parameters are passed for the `MSBuild` call.
|
||||
`run-cmake.bat`, `build-ifcopenshell.bat`, and `install-ifcopenshell.bat` can also be directly invoked from Filer Explorer
|
||||
or regular Command Prompt if BuildDepsCache file exists (the last modified version is used). Running the scripts without extra
|
||||
parameters reads the build options from an existing CMakeCache.txt.
|
||||
if wanted. Convenience scripts `python build-ifcopenshell.py` and `python install-ifcopenshell.py` can also be used. The
|
||||
scripts expect the generator and build configuration type in the same fashion as `build-deps.py` and possible extra
|
||||
parameters are passed for the `MSBuild` call after `--`. `run-cmake.bat` can also be directly invoked from File
|
||||
Explorer or regular Command Prompt if BuildDepsCache file exists (the last modified version is used). Running the
|
||||
scripts without extra parameters reads the build options from an existing CMakeCache.txt.
|
||||
|
||||
The project will be installed to `_installed-vs<VERSION>-<ARCHITECTURE>\` folder in the project's root folder and the
|
||||
required IfcOpenShell-Python parts are deployed to the `<PYTHONHOME>\Lib\site-packages\` folder. The 3ds Max plug-in,
|
||||
@@ -80,9 +80,9 @@ Directory Structure
|
||||
| build-all.cmd - Runs all of the build scripts for IFCOS and it dependencies in a row without pauses
|
||||
| build-deps.py - Fetches and builds all needed dependencies for IFCOS using MSVC
|
||||
| BuildDepsCache-<ARCH>.txt - Cache file created by build-deps.py
|
||||
| build-ifcopenshell.bat - Builds IFCOS using MSVC
|
||||
| build-ifcopenshell.py - Builds IFCOS using MSVC
|
||||
| build-type-cfg.cmd - Utility file used by the build scripts
|
||||
| install-ifcopenshell.bat - Installs/deploys IFCOS using MSVC.
|
||||
| install-ifcopenshell.py - Installs/deploys IFCOS using MSVC.
|
||||
| readme.md - This file
|
||||
| run-cmake.bat - Sets environment variables for the dependencies and runs CMake for IFCOS using MSVC
|
||||
| vs-cfg.cmd - Utility file used by the build scripts
|
||||
|
||||
Reference in New Issue
Block a user