10
10
import os
11
11
import sys
12
12
import re
13
+ import shutil
13
14
import argparse
14
15
import platform
15
16
import subprocess
20
21
os .getenv ("TRAVIS" ) is not None or
21
22
os .getenv ("GITHUB_ACTIONS" ) is not None )
22
23
is_running_on_windows = "Windows" in platform .platform ()
23
- build_dir = (Path (os .path .abspath (__file__ )).parents [2 ] / "build" )
24
+ is_running_on_arm64 = "arm" in os .uname ()[4 ]
25
+ repo_dir = Path (os .path .abspath (__file__ )).parents [2 ]
26
+ build_dir = repo_dir / "build"
24
27
cache_dir = build_dir / "cache"
25
- global_options = {}
26
- if is_running_in_ci :
27
- global_options ["::build.path" ] = "build/"
28
- 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
+
29
34
30
35
def run_command (where , command , all_output = False ):
31
36
result = subprocess .run (command , shell = True , cwd = where , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
@@ -35,16 +40,45 @@ def run_command(where, command, all_output=False):
35
40
output += result .stderr .decode ("utf-8" , errors = "ignore" ).strip (" \n " )
36
41
return (result .returncode , output )
37
42
43
+
38
44
def generate (project ):
39
- path = project .parent
40
- output = ["=" * 90 , "Generating: {}" .format (path )]
41
- options = " " .join ("-D{}={}" .format (k , v ) for k ,v in global_options .items ())
42
- # Compile Linux examples under macOS with hosted-darwin target
43
- if "hosted-linux" in project .read_text ():
44
- options += " -D:target=hosted-{}" .format (platform .system ().lower ())
45
- rc , ro = run_command (path , "lbuild {} build" .format (options ))
46
- print ("\n " .join (output + [ro ]))
47
- return None if rc else project
45
+ project_cfg = project .read_text ()
46
+ configs = set (re .findall (r"<extends>(.+?)</extends>" , project_cfg ))
47
+ if len (configs ) >= 2 :
48
+ output = ["=" * 90 , f"Parsing: { project .parent } \n " ]
49
+ config_options_collectors = re .findall (option_collector_pattern , project_cfg , flags = re .MULTILINE )
50
+ config_modules = re .findall (module_pattern , project_cfg , flags = re .MULTILINE )
51
+ generators = []
52
+ for config in sorted (configs ):
53
+ config_name = re .sub (r"[:-]+" , "_" , config )
54
+ new_project_xml = re .search (r'<option +name="modm:build:build\.path">(.*?)</option>' , project_cfg )[1 ]
55
+ new_project_xml = (project .parent / new_project_xml / config_name .replace ("modm_" , "" ) / "project.xml" )
56
+ shutil .copytree (project .parent , new_project_xml .parent , dirs_exist_ok = True )
57
+ new_project_cfg = re .sub (r"<extends>.*?</extends>" , "" , project_cfg )
58
+ new_project_cfg = re .sub (r"<library>" , f"<library>\n <extends>{ config } </extends>" , new_project_cfg )
59
+ new_project_xml .write_text (new_project_cfg )
60
+ options = "" .join (f" { option_map [t ]} { k } ={ v } " for d ,t ,k ,v in config_options_collectors if config in d )
61
+ build_options = "" .join (f" -m { m } " for d ,m in config_modules if config in d )
62
+ lbuild_options = f"-r { repo_file } -D modm:build:build.path=build/" + options
63
+ generators .append ((config , lbuild_options , build_options , new_project_xml ))
64
+ output .append (f"- { config :30} { options } { build_options } " )
65
+ print ("\n " .join (output ))
66
+ else :
67
+ if '<option name="modm:target">hosted-linux</option>' in project_cfg :
68
+ target = "hosted-" + platform .system ().lower ()
69
+ if is_running_on_arm64 : target += "-arm64"
70
+ generators = [(target , "-D modm:target=" + target , "" , project )]
71
+ else :
72
+ generators = [("project.xml" , "" , "" , project )]
73
+
74
+ projects = []
75
+ for config , lbuild_options , build_options , project_xml in generators :
76
+ output = ["=" * 90 , f"Generating: { project .parent } for { config } " ]
77
+ cmd = f"lbuild { global_options } { lbuild_options } build { build_options } --no-log"
78
+ rc , ro = run_command (project_xml .parent , cmd )
79
+ print ("\n " .join (output + [ro ]))
80
+ projects .append (None if rc else project_xml .resolve ())
81
+ return projects
48
82
49
83
def build (project ):
50
84
path = project .parent
@@ -56,14 +90,14 @@ def build(project):
56
90
commands .append ( ("make build" , "Make" ) )
57
91
elif ":build:cmake" in project_cfg :
58
92
build_dir = re .search (r'name=".+?:build:build.path">(.*?)</option>' , project_cfg )[1 ]
59
- cmd = "cmake -E make_directory {}/cmake-build-release; " . format ( build_dir )
60
- cmd += '(cd {}/cmake-build-release && cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" {}); ' . format ( build_dir , path .absolute ())
61
- cmd += "cmake --build {}/cmake-build-release" . format ( build_dir )
93
+ cmd = f "cmake -E make_directory { build_dir } /cmake-build-release; "
94
+ cmd += f '(cd { build_dir } /cmake-build-release && cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" { path .absolute ()} ); '
95
+ cmd += f "cmake --build { build_dir } /cmake-build-release"
62
96
commands .append ( (cmd , "CMake" ) )
63
97
64
98
rcs = 0
65
99
for command , build_system in commands :
66
- output = ["=" * 90 , "Building: {} with {}" . format ( path / " main.cpp" , build_system ) ]
100
+ output = ["=" * 90 , f "Building: { path . relative_to ( repo_dir ) } / main.cpp with { build_system } " ]
67
101
rc , ro = run_command (path , command )
68
102
rcs += rc
69
103
print ("\n " .join (output + [ro ]))
@@ -81,7 +115,7 @@ def run(project):
81
115
82
116
rcs = 0
83
117
for command , build_system in commands :
84
- output = ["=" * 90 , "Running: {} with {}" . format ( path / " main.cpp" , build_system ) ]
118
+ output = ["=" * 90 , f "Running: { path . relative_to ( repo_dir ) } / main.cpp with { build_system } " ]
85
119
rc , ro = run_command (path , command , all_output = True )
86
120
print ("\n " .join (output + [ro ]))
87
121
if "CI: run fail" in project_cfg :
@@ -92,7 +126,7 @@ def run(project):
92
126
return None if rcs else project
93
127
94
128
def compile_examples (paths , jobs , split , part ):
95
- print ("Using {}x parallelism" . format ( jobs ) )
129
+ print (f "Using { jobs } x parallelism" )
96
130
# Create build folder to prevent process race
97
131
cache_dir .mkdir (exist_ok = True , parents = True )
98
132
(cache_dir / "config" ).write_text ('{"prefix_len": 2}' )
@@ -111,6 +145,8 @@ def compile_examples(paths, jobs, split, part):
111
145
# first generate all projects
112
146
with ThreadPool (jobs ) as pool :
113
147
projects = pool .map (generate , projects )
148
+ # Unlistify the project configs
149
+ projects = [p for plist in projects for p in plist ]
114
150
results += projects .count (None )
115
151
116
152
# Filter projects for successful generation
0 commit comments