Skip to content

Commit 4595eea

Browse files
committed
feat: CMake prototype for L433RCTxP.
Most CMakeLists.txt here are autogenerated: - /cores/arduino - /libraries - /variants
1 parent 6591736 commit 4595eea

File tree

527 files changed

+6188
-1890
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

527 files changed

+6188
-1890
lines changed

CI/update/cmake_core.py

+14-17
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,32 @@
1+
#!/usr/bin/env python3
12

23
import sys
34
from pathlib import Path
4-
55
from jinja2 import Environment, FileSystemLoader
66

7+
script_path = Path(__file__).parent.resolve()
8+
sys.path.append(str(script_path.parent))
9+
from utils.cmake_gen import *
10+
711
if len(sys.argv) != 2 :
812
print("Usage: cmake_core.py <.../cores/arduino>")
913
print("Generates a CMakeLists.txt describing a core")
1014
print("The resulting static library will be named \"core\".")
1115

12-
13-
SOURCEFILE_EXTS = (".c", ".cpp", ".S")
14-
1516
rootdir = Path(sys.argv[1]).resolve()
1617
script_path = Path(__file__).parent.resolve()
1718
templates_dir = script_path / "templates"
1819
j2_env = Environment(
19-
loader=FileSystemLoader(str(templates_dir)), trim_blocks=True, lstrip_blocks=True
20+
loader=FileSystemLoader(str(templates_dir)), trim_blocks=True, lstrip_blocks=True
2021
)
2122
cmake_template = j2_env.get_template("CMakeLists.txt")
2223

23-
sources = [
24-
file.relative_to(rootdir)
25-
for file in rootdir.rglob("*")
26-
if file.is_file() and file.suffix in SOURCEFILE_EXTS
27-
]
24+
if not (rootdir.exists() and rootdir.is_dir()) :
25+
print(f"Can't find {rootdir}/")
26+
exit(1)
27+
2828

29-
with open(rootdir / "CMakeLists.txt", "w") as outfile :
30-
outfile.write(cmake_template.render(
31-
target="core",
32-
objlib=False,
33-
sources=sources,
34-
includedir=None,
35-
))
29+
config = config_for_bareflat(rootdir, force_recurse=True)
30+
config["target"] = "core"
31+
config["objlib"] = False
32+
render(rootdir, cmake_template, config)

CI/update/cmake_libs.py

+23-27
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1+
#!/usr/bin/env python3
12

23
import sys
34
from pathlib import Path
4-
55
from jinja2 import Environment, FileSystemLoader
66

7+
script_path = Path(__file__).parent.resolve()
8+
sys.path.append(str(script_path.parent))
9+
from utils.cmake_gen import *
10+
711
if len(sys.argv) != 2 :
812
print("Usage: cmake_libs.py <.../libraries>")
9-
print("Generates a CMakeLists.txt describing a library")
10-
print("The resulting object library will be named like the folder.")
13+
print("Generates a CMakeLists.txt for each library in the folder")
14+
print("Usage: cmake_libs.py <.../AwesomeArduinoLibrary>")
15+
print("Generates a CMakeLists.txt for the specified library")
16+
print("The resulting library targets will be named like their folders.")
1117

1218

13-
SOURCEFILE_EXTS = (".c", ".cpp", ".S", )
14-
1519
rootdir = Path(sys.argv[1]).resolve()
1620
script_path = Path(__file__).parent.resolve()
1721
templates_dir = script_path / "templates"
@@ -20,25 +24,17 @@
2024
)
2125
cmake_template = j2_env.get_template("CMakeLists.txt")
2226

23-
if not (rootdir.exists() and rootdir.name == "libraries") :
24-
print(f"Invalid variant folder : {rootdir}")
25-
exit()
26-
27-
for lib in rootdir.iterdir() :
28-
# technically several variants may be gathered in the same folder
29-
if not lib.is_dir() :
30-
continue
31-
32-
sources = [
33-
file.relative_to(lib)
34-
for file in (lib / "src").rglob("*")
35-
if file.is_file() and file.suffix in SOURCEFILE_EXTS
36-
]
37-
38-
with open(lib / "CMakeLists.txt", "w") as outfile :
39-
outfile.write(cmake_template.render(
40-
target=lib.name,
41-
objlib=True,
42-
sources=sources,
43-
includedir=(lib / "src").relative_to(lib),
44-
))
27+
if not rootdir.exists() :
28+
print(f"Can't find {rootdir}/")
29+
exit(1)
30+
31+
if rootdir.name == "libraries" :
32+
for lib in rootdir.iterdir() :
33+
if not lib.is_dir() :
34+
continue
35+
36+
config = autoconfig(lib)
37+
render(lib, cmake_template, config)
38+
else :
39+
config = autoconfig(rootdir)
40+
render(rootdir, cmake_template, config)

CI/update/cmake_variant.py

+12-22
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1+
#!/usr/bin/env python3
12

23
import sys
34
from pathlib import Path
4-
55
from jinja2 import Environment, FileSystemLoader
66

7+
script_path = Path(__file__).parent.resolve()
8+
sys.path.append(str(script_path.parent))
9+
from utils.cmake_gen import *
10+
711
if len(sys.argv) != 2 :
812
print("Usage: cmake_variant.py <.../variants>")
913
print("Generates a CMakeLists.txt describing a variant folder")
1014
print("The resulting static library will be named \"variant\".")
1115

12-
13-
SOURCEFILE_EXTS = (".c", ".cpp", ".S")
14-
1516
rootdir = Path(sys.argv[1]).resolve()
1617
script_path = Path(__file__).parent.resolve()
1718
templates_dir = script_path / "templates"
@@ -20,9 +21,9 @@
2021
)
2122
cmake_template = j2_env.get_template("CMakeLists.txt")
2223

23-
if not (rootdir.exists() and rootdir.name == "variants") :
24-
print(f"Invalid variant folder : {rootdir}")
25-
exit()
24+
if not (rootdir.exists() and rootdir.is_dir()) :
25+
print(f"Can't find {rootdir}/")
26+
exit(1)
2627

2728
for family in rootdir.iterdir() :
2829
if not family.is_dir() :
@@ -32,18 +33,7 @@
3233
if not variant.is_dir() :
3334
continue
3435

35-
sources = [
36-
file.relative_to(variant)
37-
for file in variant.iterdir()
38-
if file.is_file() and file.suffix in SOURCEFILE_EXTS
39-
]
40-
41-
with open(variant / "CMakeLists.txt", "w") as outfile :
42-
# I'd gladly name the target something less generic;
43-
# if only the variant folder were a valid identifier...
44-
outfile.write(cmake_template.render(
45-
target="variant",
46-
objlib=False,
47-
sources=sources,
48-
includedir=None,
49-
))
36+
config = config_for_bareflat(variant, force_recurse=True)
37+
config["target"] = "variant"
38+
config["objlib"] = False
39+
render(variant, cmake_template, config)

CI/update/templates/CMakeLists.txt

+85-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,95 @@
1+
{% if precompiled != "full" %}
12

2-
add_library({{ target }}{{" OBJECT" if objlib}} EXCLUDE_FROM_ALL
3-
{% for file in sources %}
4-
{{ file }}
3+
4+
add_library({{target}}{{" OBJECT" if objlib}} EXCLUDE_FROM_ALL
5+
{% for file in sources | sort %}
6+
{{file}}
57
{% endfor %}
68
)
79

8-
{% if includedir %}
9-
target_include_directories({{ target }} PUBLIC
10-
{{ includedir }}
10+
{% if includedirs %}
11+
target_include_directories({{target}} PUBLIC
12+
{% for dir in includedirs | sort %}
13+
{{dir}}
14+
{% endfor %}
1115
)
1216
{% endif %}
1317

14-
target_link_libraries({{ target }} PUBLIC
18+
target_link_libraries({{target}} PUBLIC
1519
core_config
16-
{% for lib in extra_libs%}
17-
{{ lib }}
20+
{% for lib in extra_libs | sort %}
21+
{{lib}}
1822
{% endfor %}
1923
)
24+
25+
{% if precompiled == "true" %}
26+
if(EXISTS "{{"${CMAKE_CURRENT_SOURCE_DIR}"}}/src/{{"${"}}MCU{{"}"}}/lib{{target}}.a")
27+
target_link_libraries({{target}} PUBLIC
28+
"{{"${CMAKE_CURRENT_SOURCE_DIR}"}}/src/{{"${"}}MCU{{"}"}}/lib{{target}}.a"
29+
)
30+
endif()
31+
{% endif %}
32+
33+
{% if ldflags %}
34+
taget_link_options({{target}} PUBLIC
35+
{{ldflags}}
36+
)
37+
{% endif %}
38+
39+
{% else %} {# precompiled == "full" #}
40+
41+
{#
42+
When precompiled = full, we define 3 targets:
43+
target, target_bin, target_usage
44+
target is the externally usable library
45+
target_bin contains the source files, to be used as fallback
46+
target_usage contains the "transitive usage requirements", i.e., include directories, linker options...
47+
48+
target wraps target_usage and [target_bin or the precompiled library]
49+
target_bin uses target_usage (it's a public interface, i.e. meant for me and my users)
50+
#}
51+
52+
add_library({{target}} INTERFACE)
53+
add_library({{target}}_usage INTERFACE)
54+
add_library({{target}}_bin {{" OBJECT" if objlib}} EXCLUDE_FROM_ALL
55+
{% for file in sources | sort %}
56+
{{file}}
57+
{% endfor %}
58+
)
59+
target_link_libraries({{target}} INTERFACE {{target}}_usage)
60+
target_link_libraries({{target}}_bin PUBLIC {{target}}_usage)
61+
62+
if(EXISTS "./src/{{"${"}}MCU{{"}"}}/lib{{target}}.a")
63+
target_link_libraries({{target}} INTERFACE
64+
"./src/{{"${"}}MCU{{"}"}}/lib{{target}}.a"
65+
)
66+
else()
67+
target_link_libraries({{target}} INTERFACE
68+
{{target}}_bin
69+
$<TARGET_OBJECTS:{{target}}_bin>
70+
)
71+
endif()
72+
73+
74+
{% if includedirs %}
75+
target_include_directories({{target}}_usage INTERFACE
76+
{% for dir in includedirs | sort %}
77+
{{dir}}
78+
{% endfor %}
79+
)
80+
{% endif %}
81+
82+
target_link_libraries({{target}}_usage INTERFACE
83+
core_config
84+
{% for lib in extra_libs | sort %}
85+
{{lib}}
86+
{% endfor %}
87+
)
88+
89+
{% if ldflags %}
90+
taget_link_options({{target}}_usage INTERFACE
91+
{{ldflags}}
92+
)
93+
{% endif %}
94+
95+
{% endif %} {# precompiled ?= "full" #}

CI/utils/cmake_gen.py

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#!/usr/bin/env python3
2+
3+
SOURCEFILE_EXTS = (".c", ".cpp", ".S", )
4+
5+
def get_default_config() :
6+
return dict(
7+
sources = set(),
8+
includedirs = set(),
9+
extra_libs = set(),
10+
target = "",
11+
objlib = True,
12+
ldflags = "",
13+
precompiled = "false",
14+
)
15+
16+
def parse_configfile(file) :
17+
rawcfg = dict()
18+
19+
for line in open(file) :
20+
line = line.strip()
21+
if not line :
22+
continue
23+
if line.startswith("#") :
24+
continue
25+
26+
key, value = line.split("=", 1)
27+
key = key
28+
value = value
29+
rawcfg[key.strip()] = value.strip()
30+
31+
cfg = dict()
32+
cfg["objlib"] = False if rawcfg.get("dot_a_linkage") == "true" else True
33+
cfg["ldflags"] = rawcfg.get("ldflags", "")
34+
cfg["precompiled"] = rawcfg.get("precompiled", "false")
35+
return cfg
36+
37+
def get_sources(dir, recursive=False, relative_to=None) :
38+
if relative_to is None :
39+
relative_to = dir
40+
if recursive :
41+
walker = type(dir).rglob
42+
else :
43+
walker = type(dir).glob
44+
45+
return {
46+
file.relative_to(relative_to)
47+
for file in walker(dir, "*")
48+
if file.is_file() and file.suffix in SOURCEFILE_EXTS
49+
}
50+
51+
def render(dir, template, config) :
52+
with open(dir / "CMakeLists.txt", "w") as outfile :
53+
outfile.write(template.render(**config))
54+
55+
56+
def config_for_bareflat(dir, force_recurse=False) :
57+
# no library.properties
58+
config = get_default_config()
59+
60+
config["target"] = dir.name
61+
config["sources"].update(get_sources(dir, recursive=force_recurse))
62+
config["includedirs"].add(dir.relative_to(dir))
63+
64+
utils = dir/"utility"
65+
if (utils.exists() and utils.is_dir()) :
66+
config["sources"].update(get_sources(utils, relative_to=dir, recursive=force_recurse))
67+
config["includedirs"].add(utils.relative_to(dir))
68+
69+
return config
70+
71+
def config_for_modern(dir) :
72+
# library.properties present, src/ present
73+
config = get_default_config()
74+
config.update(parse_configfile(dir/"library.properties"))
75+
76+
config["target"] = dir.name
77+
config["sources"].update(get_sources(dir/"src", recursive=True, relative_to=dir))
78+
config["includedirs"].add((dir/"src").relative_to(dir))
79+
80+
return config
81+
82+
def autoconfig(libdir) :
83+
conf_file = libdir/"library.properties"
84+
srcdir = libdir/"src"
85+
if (conf_file.exists() and conf_file.is_file() \
86+
and srcdir.exists() and srcdir.is_dir()) :
87+
return config_for_modern(libdir)
88+
else :
89+
return config_for_bareflat(libdir)

cmake/external_library.cmake

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
set(CI_FOLDER ${CMAKE_CURRENT_LIST_DIR}/../CI)
3+
4+
function(external_library LIBPATH)
5+
if(NOT EXISTS ${LIBPATH}/CMakeLists.txt)
6+
execute_process(
7+
COMMAND ${PYTHON3} ${CI_FOLDER}/update/cmake_libs.py ${LIBPATH}
8+
)
9+
endif()
10+
get_filename_component(LIBNAME ${LIBPATH} NAME)
11+
add_subdirectory(
12+
${LIBPATH}
13+
${CMAKE_CURRENT_BINARY_DIR}/${LIBNAME}
14+
)
15+
endfunction()

0 commit comments

Comments
 (0)