1010import os
1111import sys
1212import re
13+ import shutil
1314import argparse
1415import platform
1516import subprocess
2021 os .getenv ("TRAVIS" ) is not None or
2122 os .getenv ("GITHUB_ACTIONS" ) is not None )
2223is_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"
2427cache_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+
2934
3035def run_command (where , command , all_output = False ):
3136 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):
3540 output += result .stderr .decode ("utf-8" , errors = "ignore" ).strip (" \n " )
3641 return (result .returncode , output )
3742
43+
3844def 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
4882
4983def build (project ):
5084 path = project .parent
@@ -56,14 +90,14 @@ def build(project):
5690 commands .append ( ("make build" , "Make" ) )
5791 elif ":build:cmake" in project_cfg :
5892 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"
6296 commands .append ( (cmd , "CMake" ) )
6397
6498 rcs = 0
6599 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 } " ]
67101 rc , ro = run_command (path , command )
68102 rcs += rc
69103 print ("\n " .join (output + [ro ]))
@@ -81,7 +115,7 @@ def run(project):
81115
82116 rcs = 0
83117 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 } " ]
85119 rc , ro = run_command (path , command , all_output = True )
86120 print ("\n " .join (output + [ro ]))
87121 if "CI: run fail" in project_cfg :
@@ -92,7 +126,7 @@ def run(project):
92126 return None if rcs else project
93127
94128def compile_examples (paths , jobs , split , part ):
95- print ("Using {}x parallelism" . format ( jobs ) )
129+ print (f "Using { jobs } x parallelism" )
96130 # Create build folder to prevent process race
97131 cache_dir .mkdir (exist_ok = True , parents = True )
98132 (cache_dir / "config" ).write_text ('{"prefix_len": 2}' )
@@ -111,6 +145,8 @@ def compile_examples(paths, jobs, split, part):
111145 # first generate all projects
112146 with ThreadPool (jobs ) as pool :
113147 projects = pool .map (generate , projects )
148+ # Unlistify the project configs
149+ projects = [p for plist in projects for p in plist ]
114150 results += projects .count (None )
115151
116152 # Filter projects for successful generation
0 commit comments