Skip to content

Commit 4017751

Browse files
committed
[tools] Compile examples for multiple configurations
1 parent 605eb38 commit 4017751

File tree

1 file changed

+59
-20
lines changed

1 file changed

+59
-20
lines changed

tools/scripts/examples_compile.py

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import os
1111
import sys
1212
import re
13+
import shutil
1314
import argparse
1415
import platform
1516
import subprocess
@@ -21,12 +22,15 @@
2122
os.getenv("GITHUB_ACTIONS") is not None)
2223
is_running_on_windows = "Windows" in platform.platform()
2324
is_running_on_arm64 = "arm64" in platform.machine()
24-
build_dir = (Path(os.path.abspath(__file__)).parents[2] / "build")
25+
repo_dir = Path(os.path.abspath(__file__)).parents[2]
26+
build_dir = repo_dir / "build"
2527
cache_dir = build_dir / "cache"
26-
global_options = {}
27-
if is_running_in_ci:
28-
global_options["::build.path"] = "build/"
29-
global_options[":::cache_dir"] = str(cache_dir)
28+
repo_file = repo_dir / "repo.lb"
29+
option_collector_pattern = r'<!--(.+?)-->\n\s+<!-- *<(option|collect) +name="(.+?)">(.+?)</(?:option|collect)> *-->'
30+
option_map = {"option": "-D", "collect": "--collect"}
31+
module_pattern = r'<!--(.+?)-->\n\s+<!-- *<module>(.+?)</module> *-->'
32+
global_options = f" -D modm:build:build.path=build/ -D modm:build:scons:cache_dir={cache_dir}" if is_running_in_ci else ""
33+
3034

3135
def run_command(where, command, all_output=False):
3236
result = subprocess.run(command, shell=True, cwd=where, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -45,18 +49,45 @@ def enable(projects):
4549
filtered_projects.append(project)
4650
return filtered_projects
4751

52+
def prepare(project):
53+
project_cfg = project.read_text()
54+
configs = set(re.findall(r"<extends>(.+?)</extends>", project_cfg))
55+
56+
if len(configs) >= 2:
57+
output = ["=" * 90, f"Preparing: {project.parent}\n"]
58+
config_options_collectors = re.findall(option_collector_pattern, project_cfg, flags=re.MULTILINE)
59+
config_modules = re.findall(module_pattern, project_cfg, flags=re.MULTILINE)
60+
generators = []
61+
for config in sorted(configs):
62+
config_name = re.sub(r"[:-]+", "_", config)
63+
new_project_xml = re.search(r'<option +name="modm:build:build\.path">(.*?)</option>', project_cfg)[1]
64+
new_project_xml = (project.parent / new_project_xml / config_name.replace("modm_", "") / "project.xml")
65+
shutil.copytree(project.parent, new_project_xml.parent, dirs_exist_ok=True)
66+
new_project_cfg = re.sub(r"<extends>.*?</extends>", "", project_cfg)
67+
new_project_cfg = re.sub(r"<library>", f"<library>\n <extends>{config}</extends>", new_project_cfg)
68+
new_project_xml.write_text(new_project_cfg)
69+
options = "".join(f" {option_map[t]} {k}={v}" for d,t,k,v in config_options_collectors if config in d)
70+
build_options = "".join(f" -m {m}" for d,m in config_modules if config in d)
71+
lbuild_options = f"-r {repo_file} -D modm:build:build.path=build/" + options
72+
generators.append((project, config, lbuild_options, build_options, new_project_xml))
73+
output.append(f"- {config:30}{options}{build_options}")
74+
print("\n".join(output))
75+
return generators
76+
77+
if '<option name="modm:target">hosted-linux</option>' in project_cfg:
78+
target = "hosted-" + platform.system().lower()
79+
if is_running_on_arm64: target += "-arm64"
80+
return [(project, target, "-D modm:target=" + target, "", project)]
81+
82+
return [(project, "project.xml", "", "", project)]
4883

4984
def generate(project):
50-
path = project.parent
51-
output = ["=" * 90, "Generating: {}".format(path)]
52-
options = " ".join("-D{}={}".format(k, v) for k,v in global_options.items())
53-
# Compile Linux examples under macOS with hosted-darwin target
54-
if "hosted-linux" in project.read_text():
55-
options += " -D:target=hosted-{}".format(platform.system().lower())
56-
if is_running_on_arm64: options += "-arm64"
57-
rc, ro = run_command(path, "lbuild {} build".format(options))
85+
project, config, lbuild_options, build_options, project_xml = project
86+
output = ["=" * 90, f"Generating: {project.parent} for {config}"]
87+
cmd = f"lbuild {global_options} {lbuild_options} build {build_options} --no-log"
88+
rc, ro = run_command(project_xml.parent, cmd)
5889
print("\n".join(output + [ro]))
59-
return None if rc else project
90+
return None if rc else project_xml.resolve()
6091

6192
def build(project):
6293
path = project.parent
@@ -68,14 +99,14 @@ def build(project):
6899
commands.append( ("make build", "Make") )
69100
elif ":build:cmake" in project_cfg and not is_running_on_windows:
70101
build_dir = re.search(r'name=".+?:build:build.path">(.*?)</option>', project_cfg)[1]
71-
cmd = "cmake -E make_directory {}/cmake-build-release; ".format(build_dir)
72-
cmd += '(cd {}/cmake-build-release && cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" {}); '.format(build_dir, path.absolute())
73-
cmd += "cmake --build {}/cmake-build-release".format(build_dir)
102+
cmd = f"cmake -E make_directory {build_dir}/cmake-build-release; "
103+
cmd += f'(cd {build_dir}/cmake-build-release && cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" {path.absolute()}); '
104+
cmd += f"cmake --build {build_dir}/cmake-build-release"
74105
commands.append( (cmd, "CMake") )
75106

76107
rcs = 0
77108
for command, build_system in commands:
78-
output = ["=" * 90, "Building: {} with {}".format(path / "main.cpp", build_system)]
109+
output = ["=" * 90, f"Building: {path.relative_to(repo_dir)}/main.cpp with {build_system}"]
79110
rc, ro = run_command(path, command)
80111
rcs += rc
81112
print("\n".join(output + [ro]))
@@ -93,7 +124,7 @@ def run(project):
93124

94125
rcs = 0
95126
for command, build_system in commands:
96-
output = ["=" * 90, "Running: {} with {}".format(path / "main.cpp", build_system)]
127+
output = ["=" * 90, f"Running: {path.relative_to(repo_dir)}/main.cpp with {build_system}"]
97128
rc, ro = run_command(path, command, all_output=True)
98129
print("\n".join(output + [ro]))
99130
if "CI: run fail" in project_cfg:
@@ -104,7 +135,7 @@ def run(project):
104135
return None if rcs else project
105136

106137
def compile_examples(paths, jobs, split, part):
107-
print("Using {}x parallelism".format(jobs))
138+
print(f"Using {jobs}x parallelism")
108139
# Create build folder to prevent process race
109140
cache_dir.mkdir(exist_ok=True, parents=True)
110141
(cache_dir / "config").write_text('{"prefix_len": 2}')
@@ -122,9 +153,17 @@ def compile_examples(paths, jobs, split, part):
122153
# Filter projects
123154
projects = enable(projects)
124155

156+
# first prepare all projects
157+
with ThreadPool(jobs) as pool:
158+
projects = pool.map(prepare, projects)
159+
# Unlistify the project preparations
160+
projects = [p for plist in projects for p in plist]
161+
results += projects.count(None)
162+
125163
# first generate all projects
126164
with ThreadPool(jobs) as pool:
127165
projects = pool.map(generate, projects)
166+
# Unlistify the project configs
128167
results += projects.count(None)
129168

130169
# Filter projects for successful generation

0 commit comments

Comments
 (0)