Skip to content

Commit e4d5263

Browse files
committed
Refactor build_windows.py, add --codesign-enabled flag
1 parent b20dfcc commit e4d5263

File tree

1 file changed

+137
-81
lines changed

1 file changed

+137
-81
lines changed

scripts/build_windows.py

Lines changed: 137 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -9,72 +9,150 @@
99
import pprint
1010
import subprocess
1111

12-
def _is_truthy_envvar(s : str):
13-
sl = s.lower()
14-
return sl in {"on", "true", "yes", "1"}
12+
def _envvar_as_tristate(key : str, default=None):
13+
value = os.getenv(key, default)
14+
if value is None:
15+
return None
16+
else:
17+
return value.lower() in {"on", "true", "yes", "1"}
1518

1619
def _run(s: str, extra_env_vars={}):
1720
logging.info(f"running: {s}")
1821
subprocess.run(s, check=True, env={**extra_env_vars, **os.environ})
1922

20-
def _run_cmake_configure(source_dir, binary_dir, generator, architecture, cache_variables, extra_env_vars={}):
21-
all_cache_variables = ' '.join([f'-D{k}={v}' for k, v in cache_variables.items()])
22-
maybe_arch_flag = f'-A {architecture}' if 'Visual Studio' in generator else ''
23-
_run(f'cmake -S {source_dir} -B {binary_dir} -G "{generator}" {maybe_arch_flag} {all_cache_variables}', extra_env_vars)
24-
25-
def _run_cmake_build(binary_dir, config, concurrency, target=None):
26-
maybe_target_flag = f'--target {target}' if target else ''
27-
_run(f'cmake --build {binary_dir} --verbose --config {config} -j{concurrency} {maybe_target_flag}')
28-
2923
def _log_dir_contents(path: str):
3024
logging.info(f"listing {path}")
3125
for el in os.listdir(path):
3226
logging.info(f"{path}/{el}")
3327

34-
class BuildConfiguration:
28+
def _default_generator():
29+
return 'Visual Studio 17 2022'
3530

36-
def __init__(
37-
self,
38-
*,
39-
base_build_type="Release",
40-
build_dir=os.curdir,
41-
build_concurrency=multiprocessing.cpu_count(),
42-
build_target="package",
43-
build_docs="OFF",
44-
system_version=None,
45-
build_skip_osc=False):
46-
47-
self.base_build_type = os.getenv("OSC_BASE_BUILD_TYPE", base_build_type)
48-
self.osc_deps_build_type = os.getenv("OSC_DEPS_BUILD_TYPE")
49-
self.osc_build_type = os.getenv("OSC_BUILD_TYPE")
50-
self.concurrency = int(os.getenv("OSC_BUILD_CONCURRENCY", build_concurrency))
51-
self.build_target = os.getenv("OSC_BUILD_TARGET", build_target)
52-
self.build_docs = _is_truthy_envvar(os.getenv("OSC_BUILD_DOCS", build_docs))
53-
self.generator = 'Visual Studio 17 2022'
54-
self.architecture = 'x64'
55-
self.system_version = os.getenv('OSC_SYSTEM_VERSION', system_version)
56-
self.build_dir = build_dir
57-
self.skip_osc = build_skip_osc
31+
def _generator_requires_architecture_flag(generator):
32+
return 'Visual Studio' in generator
33+
34+
def _is_multi_configuration_generator(generator):
35+
return 'Visual Studio' in generator or 'Xcode' in generator
36+
37+
def _run_cmake_configure(source_dir, binary_dir, generator, architecture, cache_variables, extra_env_vars={}):
38+
args = ['-S', source_dir, '-B', binary_dir] # base arguments
39+
40+
# append generator (-G) argument (if specified)
41+
if generator:
42+
args += ['-G', generator]
43+
# append architecture (-A) argument (if necessary)
44+
if _generator_requires_architecture_flag(generator):
45+
args += ['-A', architecture if architecture else 'x64']
46+
# append cache variables (-DK=V)
47+
for k, v in cache_variables.items():
48+
args += [f'-D{k}={v}']
49+
50+
_run(f'cmake {" ".join(args)}', extra_env_vars)
51+
52+
def _run_cmake_build(binary_dir, generator, build_type, concurrency, target=None, extra_env_vars={}):
53+
args = ['--build', binary_dir, '--verbose', '-j', str(concurrency)] # base arguments
54+
55+
# append --config argument (if necessary)
56+
if _is_multi_configuration_generator(generator):
57+
args += ['--config', build_type]
58+
# append --target argument (if specified)
59+
if target:
60+
args += ['--target', target]
61+
62+
_run(f'cmake {" ".join(args)}', extra_env_vars)
63+
64+
def _run_ctest(test_dir, concurrency, excluded_tests=[], extra_env_vars={}):
65+
args = ['--test-dir', test_dir, '-j', str(concurrency)] # base arguments
66+
if excluded_tests:
67+
args += ['-E', '|'.join(excluded_tests)]
68+
_run(f'ctest {" ".join(args)}', extra_env_vars)
69+
70+
# Represents the top-level, potentially caller-controlled, build configuration.
71+
class BuildConfiguration:
72+
def __init__(self):
73+
self.base_build_type = os.getenv("OSC_BASE_BUILD_TYPE", "Release")
74+
self.concurrency = int(os.getenv("OSC_BUILD_CONCURRENCY", multiprocessing.cpu_count()))
75+
self.build_target = os.getenv("OSC_BUILD_TARGET", "package")
76+
self.build_docs = _envvar_as_tristate("OSC_BUILD_DOCS")
77+
self.generator = _default_generator()
78+
self.architecture = None
79+
self.system_version = os.getenv('OSC_SYSTEM_VERSION')
80+
self.build_dir = os.curdir
81+
self.codesign_enabled = None
82+
self.skip_osc = False
83+
self.exclude_tests_that_use_windowing_system = True
84+
self.headless_mode = True
85+
86+
# these can be `None`, meaning "fall back to `base_build_type` at runtime"
87+
self._osc_deps_build_type = os.getenv("OSC_DEPS_BUILD_TYPE")
88+
self._osc_build_type = os.getenv("OSC_BUILD_TYPE")
5889

5990
def __repr__(self):
6091
return pprint.pformat(vars(self))
6192

6293
def get_dependencies_build_dir(self):
63-
return os.path.join(self.build_dir, f"third_party-build-{self.osc_deps_build_type}")
94+
return os.path.join(self.build_dir, f"third_party-build-{self.get_osc_deps_build_type()}")
6495

6596
def get_dependencies_install_dir(self):
66-
return os.path.join(self.build_dir, f"third_party-install-{self.osc_deps_build_type}")
97+
return os.path.join(self.build_dir, f"third_party-install-{self.get_osc_deps_build_type()}")
6798

6899
def get_osc_build_dir(self):
69-
# note: clangd usually expects that the build directory is located at `build/`
70-
return os.path.join(self.build_dir, "build")
100+
return os.path.join(self.build_dir, f"build/{self.get_osc_build_type()}")
71101

72102
def get_osc_deps_build_type(self):
73-
return self.osc_deps_build_type or self.base_build_type
103+
return self._osc_deps_build_type or self.base_build_type
74104

75105
def get_osc_build_type(self):
76-
return self.osc_build_type or self.base_build_type
106+
return self._osc_build_type or self.base_build_type
107+
108+
def get_dependencies_cmake_cache_variables(self):
109+
rv = {
110+
'CMAKE_BUILD_TYPE': self.get_osc_deps_build_type(),
111+
'CMAKE_INSTALL_PREFIX': self.get_dependencies_install_dir(),
112+
}
113+
if self.system_version:
114+
rv['CMAKE_SYSTEM_VERSION'] = self.system_version
77115

116+
return rv
117+
118+
def get_osc_cmake_cache_variables(self):
119+
# calculate cache variables
120+
rv = {
121+
'CMAKE_BUILD_TYPE': self.get_osc_build_type(),
122+
'CMAKE_PREFIX_PATH': os.path.abspath(self.get_dependencies_install_dir()),
123+
}
124+
if self.build_docs is not None:
125+
rv['OSC_BUILD_DOCS'] = 'ON' if self.build_docs else 'OFF'
126+
if self.codesign_enabled is not None:
127+
rv['OSC_CODESIGN_ENABLED'] = 'ON' if self.codesign_enabled else 'OFF'
128+
if self.system_version:
129+
rv['CMAKE_SYSTEM_VERSION'] = self.system_version
130+
131+
return rv
132+
133+
def get_osc_ctest_extra_environment_variables(self):
134+
rv = {}
135+
if self.headless_mode:
136+
rv['OSC_INTERNAL_HIDE_WINDOW'] = '1'
137+
return rv
138+
139+
def get_excluded_tests(self):
140+
if not self.exclude_tests_that_use_windowing_system:
141+
return [] # no tests excluded
142+
else:
143+
return [
144+
'Graphics',
145+
'MeshDepthWritingMaterialFixture',
146+
'MeshNormalVectorsMaterialFixture',
147+
'ShaderTest',
148+
'MaterialTest',
149+
'RegisteredDemoTabsTest',
150+
'RegisteredOpenSimCreatorTabs',
151+
'AddComponentPopup',
152+
'LoadingTab',
153+
]
154+
155+
# Represents a section (grouping, substep) of the build
78156
class Section:
79157
def __init__(self, name):
80158
self.name = name
@@ -89,26 +167,19 @@ def log_build_params(conf: BuildConfiguration):
89167

90168
def build_osc_dependencies(conf: BuildConfiguration):
91169
with Section("build osc dependencies"):
92-
# calculate cache variables
93-
cache_variables = {
94-
'CMAKE_BUILD_TYPE': conf.get_osc_deps_build_type(),
95-
'CMAKE_INSTALL_PREFIX': conf.get_dependencies_install_dir(),
96-
}
97-
if conf.system_version:
98-
cache_variables['CMAKE_SYSTEM_VERSION'] = conf.system_version
99-
100170
# configure
101171
_run_cmake_configure(
102172
source_dir='third_party',
103173
binary_dir=conf.get_dependencies_build_dir(),
104174
generator=conf.generator,
105175
architecture=conf.architecture,
106-
cache_variables=cache_variables
176+
cache_variables=conf.get_dependencies_cmake_cache_variables()
107177
)
108178
# build
109179
_run_cmake_build(
110180
binary_dir=conf.get_dependencies_build_dir(),
111-
config=conf.get_osc_deps_build_type(),
181+
generator=conf.generator,
182+
build_type=conf.get_osc_deps_build_type(),
112183
concurrency=conf.concurrency
113184
)
114185

@@ -118,54 +189,37 @@ def build_osc_dependencies(conf: BuildConfiguration):
118189

119190
def build_osc(conf: BuildConfiguration):
120191
if conf.skip_osc:
121-
logging.info("--skip-osc was provided: skipping the OSC build")
192+
logging.info("skip_osc was set: skipping the OSC build")
122193
return
123194

124195
with Section("build osc"):
125-
# calculate cache variables
126-
cache_variables = {
127-
'CMAKE_BUILD_TYPE': conf.get_osc_build_type(),
128-
'CMAKE_PREFIX_PATH': os.path.abspath(conf.get_dependencies_install_dir()),
129-
'OSC_BUILD_DOCS': 'ON' if conf.build_docs else 'OFF'
130-
}
131-
if conf.system_version:
132-
cache_variables['CMAKE_SYSTEM_VERSION'] = conf.system_version
133-
134196
# configure
135197
_run_cmake_configure(
136198
source_dir='.',
137199
binary_dir=conf.get_osc_build_dir(),
138200
generator=conf.generator,
139201
architecture=conf.architecture,
140-
cache_variables=cache_variables
202+
cache_variables=conf.get_osc_cmake_cache_variables()
141203
)
142-
143204
# build
144205
_run_cmake_build(
145206
binary_dir=conf.get_osc_build_dir(),
146-
config=conf.get_osc_build_type(),
207+
generator=conf.generator,
208+
build_type=conf.get_osc_build_type(),
147209
concurrency=conf.concurrency
148210
)
149-
150211
# test
151-
excluded_tests = [ # necessary in CI: no windowing system available
152-
'Graphics',
153-
'MeshDepthWritingMaterialFixture',
154-
'MeshNormalVectorsMaterialFixture',
155-
'ShaderTest',
156-
'MaterialTest',
157-
'RegisteredDemoTabsTest',
158-
'RegisteredOpenSimCreatorTabs',
159-
'AddComponentPopup',
160-
'LoadingTab',
161-
]
162-
excluded_tests_str = '|'.join(excluded_tests)
163-
_run(f'ctest --test-dir {conf.get_osc_build_dir()} -j {conf.concurrency} -E {excluded_tests_str}')
164-
165-
# ensure final target is built - even if it isn't in ALL (e.g. `package`)
212+
_run_ctest(
213+
test_dir=conf.get_osc_build_dir(),
214+
concurrency=conf.concurrency,
215+
excluded_tests=conf.get_excluded_tests(),
216+
extra_env_vars=conf.get_osc_ctest_extra_environment_variables()
217+
)
218+
# build final target (which might not be in ALL, e.g. `package`)
166219
_run_cmake_build(
167220
binary_dir=conf.get_osc_build_dir(),
168-
config=conf.get_osc_build_type(),
221+
generator=conf.generator,
222+
build_type=conf.get_osc_build_type(),
169223
concurrency=conf.concurrency,
170224
target=conf.build_target
171225
)
@@ -184,6 +238,7 @@ def main():
184238
parser.add_argument('--generator', '-G', help='set the build generator for cmake', type=str, default=conf.generator)
185239
parser.add_argument('--build-type', help='the type of build to produce (CMake string: Debug, Release, RelWithDebInfo, etc.)', type=str, default=conf.base_build_type)
186240
parser.add_argument('--system-version', help='specify the value of CMAKE_SYSTEM_VERSION (e.g. "10.0.26100.0", a specific Windows SDK)', type=str, default=conf.system_version)
241+
parser.add_argument('--codesign-enabled', help='enable signing resulting binaries/package', default=conf.codesign_enabled, action='store_true')
187242

188243
# overwrite build configuration with any CLI args
189244
args = parser.parse_args()
@@ -193,6 +248,7 @@ def main():
193248
conf.generator = args.generator
194249
conf.base_build_type = args.build_type
195250
conf.system_version = args.system_version
251+
conf.codesign_enabled = args.codesign_enabled
196252

197253
log_build_params(conf)
198254
build_osc_dependencies(conf)

0 commit comments

Comments
 (0)