Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3e34e94

Browse files
committedAug 10, 2022
feat: autogenerate the user's CMakeLists.txt
The script uses its location and arduino-cli to write a template of the sketch's CMakeLists.txt. * Defines: - CORE_PATH - USER_LIBS -> for use with `external_library()` * Includes all user libraries * Usable on a given sketch or generically (use placeholders) * Optionally: run CMake (config+build)
1 parent 8c0a382 commit 3e34e94

File tree

2 files changed

+212
-0
lines changed

2 files changed

+212
-0
lines changed
 

‎CI/update/templates/easy_cmake.cmake

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# This file was autogenerated by {{scriptfile}}.
2+
# Use it in your CMake configuration by `include()`'ing it.
3+
# You can also copy it in your sketch's folder and edit it to fit your project.
4+
5+
cmake_minimum_required(VERSION 3.13)
6+
7+
# STEP 1: set up bases of environment
8+
# -----------------------------------------------------------------------------
9+
10+
file(REAL_PATH "{{corepath}}" CORE_PATH EXPAND_TILDE)
11+
file(TO_CMAKE_PATH "{{"${CORE_PATH}"}}" CORE_PATH)
12+
13+
file(REAL_PATH "{{userlibs}}" USER_LIBS EXPAND_TILDE)
14+
file(TO_CMAKE_PATH "{{"${USER_LIBS}"}}" USER_LIBS)
15+
16+
set(BOARDNAME "{{boardname or "@board_name_here@"}}")
17+
18+
list(APPEND CMAKE_MODULE_PATH {{"${CORE_PATH}"}}/cmake)
19+
set(CMAKE_TOOLCHAIN_FILE toolchain)
20+
21+
22+
# You may remove this block when using this file as the sketch's CMakeLists.txt
23+
if (NOT ${CMAKE_PARENT_LIST_FILE} STREQUAL ${CMAKE_CURRENT_LIST_FILE})
24+
# When we are imported from the main CMakeLists.txt, we should stop here
25+
# not to interfere with the true build config.
26+
return()
27+
endif()
28+
29+
30+
31+
# STEP 2: configure the build
32+
# -----------------------------------------------------------------------------
33+
34+
include(set_board)
35+
set_board("{{"${BOARDNAME}"}}"
36+
# SERIAL generic
37+
# USB none
38+
# XUSB FS
39+
# VIRTIO disabled
40+
)
41+
42+
include(overall_settings)
43+
overall_settings(
44+
# STANDARD_LIBC
45+
# PRINTF_FLOAT
46+
# SCANF_FLOAT
47+
# DEBUG_SYMBOLS
48+
# LTO
49+
# NO_RELATIVE_MACRO
50+
# UNDEF_NDEBUG
51+
# OPTIMIZATION "s"
52+
# BUILD_OPT ./build.opt
53+
# DISABLE_HAL_MODULES ADC I2C RTC SPI TIM DAC EXTI ETH SD QSPI
54+
)
55+
56+
# STEP 3: configure your sketch
57+
# -----------------------------------------------------------------------------
58+
project("{{tgtname+"_project" if tgtname else "@project_name_here@"}}")
59+
60+
include(external_library)
61+
# I cannot tell the dependencies of the library ahead-of-time
62+
# Please write them in using the DEPENDS ... clause
63+
{% for libdir in libs | sort %}
64+
external_library(PATH "{{"${USER_LIBS}"}}/{{libdir}}")
65+
{% endfor %}
66+
67+
include(build_sketch)
68+
build_sketch(TARGET "{{tgtname or "@binary_name_here@"}}"
69+
SOURCES
70+
{% for file in scrcfiles | sort %}
71+
{{file}}
72+
{% else %}
73+
./file1.ino
74+
./file2.ino
75+
./file3.cpp
76+
./file4.c
77+
./file5.S
78+
{% endfor %}
79+
80+
# DEPENDS
81+
# SD
82+
# Wire
83+
)
84+
85+
# STEP 4: optional features
86+
# -----------------------------------------------------------------------------
87+
88+
include(insights)
89+
insights(TARGET "{{tgtname or "@binary_name_here@"}}"
90+
# DIRECT_INCLUDES
91+
# TRANSITIVE_INCLUDES
92+
# SYMBOLS
93+
# ARCHIVES
94+
# LOGIC_STRUCTURE
95+
)

‎scripts/cmake_easy_setup.py

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/usr/bin/env python3
2+
3+
import argparse
4+
import subprocess
5+
import shutil
6+
import tempfile
7+
import os
8+
import pathlib
9+
import json
10+
from jinja2 import Environment, FileSystemLoader
11+
12+
parser = argparse.ArgumentParser()
13+
parser.add_argument("--cli", "-x", type=pathlib.Path, required=False, default=shutil.which("arduino-cli"), help="path to arduino-cli")
14+
parser.add_argument("--board", "-b", type=str, default="", help="board name")
15+
parser.add_argument("--fire", action="store_true", default=False, help="launch the build immediately (use with caution!)")
16+
output_args = parser.add_mutually_exclusive_group(required=True)
17+
output_args.add_argument("--output", "-o", type=pathlib.Path, help="output file (CMake) with placeholders")
18+
output_args.add_argument("--sketch", "-s", type=pathlib.Path, help="output file (CMake) filled given a sketch folder")
19+
20+
shargs = parser.parse_args()
21+
22+
if shargs.sketch and not shargs.board :
23+
print("""
24+
Warning: you did not specify which board you were targeting;
25+
please review the generated CMakeLists.txt to remove the placeholder value before calling `cmake`.
26+
""")
27+
28+
if shargs.cli is None :
29+
print("""
30+
Error: `arduino-cli` not found in $PATH.
31+
Please install arduino-cli and make it available from your system $PATH,
32+
or give its location through the `--cli` argument.
33+
""")
34+
exit(-1)
35+
36+
def arduino(*args) :
37+
# return (out.stdout, logfile)
38+
# raises an exception if the command fails
39+
handle, logfile = tempfile.mkstemp()
40+
os.close(handle)
41+
out = subprocess.run(
42+
(shargs.cli, "--log-file", logfile, "--log-format", "json", *args),
43+
capture_output=True,
44+
encoding="utf-8",
45+
check=True,
46+
).stdout
47+
return (out, logfile)
48+
49+
def get_log(fname) :
50+
with open(fname) as file :
51+
for line in file :
52+
yield json.loads(line)
53+
54+
55+
_, logf = arduino("lib", "list")
56+
57+
libpaths = dict()
58+
for line in get_log(logf) :
59+
if line["msg"] == "Adding libraries dir" :
60+
libpaths[line["location"]] = pathlib.Path(line["dir"])
61+
62+
# platform lib path is already known, obviously, since that's where this script resides
63+
userlibs = pathlib.Path(libpaths["user"]).resolve()
64+
libs = [u.name for u in userlibs.iterdir() if u.is_dir()]
65+
corepath = pathlib.Path(__file__).parent.parent.resolve()
66+
67+
j2_env = Environment(
68+
loader=FileSystemLoader(str(corepath/"CI"/"update"/"templates")), trim_blocks=True, lstrip_blocks=True
69+
)
70+
cmake_template = j2_env.get_template("easy_cmake.cmake")
71+
72+
73+
userhome = pathlib.Path.home()
74+
if userlibs.is_relative_to(userhome) :
75+
userlibs = "~/" + str(userlibs.relative_to(userhome))
76+
if corepath.is_relative_to(userhome) :
77+
corepath = "~/" + str(corepath.relative_to(userhome))
78+
79+
if shargs.sketch :
80+
SOURCEFILE_EXTS = (".c", ".cpp", ".S", ".ino")
81+
sources = {
82+
file.relative_to(shargs.sketch)
83+
for file in shargs.sketch.glob("*")
84+
if file.is_file() and file.suffix in SOURCEFILE_EXTS
85+
}
86+
sources |= {
87+
file.relative_to(shargs.sketch)
88+
for file in shargs.sketch.rglob("src/*")
89+
if file.is_file() and file.suffix in SOURCEFILE_EXTS
90+
}
91+
tgtname = shargs.sketch.resolve().name
92+
else :
93+
tgtname = ""
94+
sources = set()
95+
96+
scriptname = pathlib.Path(__file__)
97+
if scriptname.is_relative_to(userhome) :
98+
scriptname = "~/" + str(scriptname.relative_to(userhome))
99+
100+
with open(shargs.output or shargs.sketch/"CMakeLists.txt", "w") as out :
101+
out.write(cmake_template.render(
102+
corepath=str(corepath).replace("\\", "\\\\"), # escape backslashes for CMake
103+
userlibs=str(userlibs).replace("\\", "\\\\"),
104+
libs=libs,
105+
scriptfile=scriptname,
106+
tgtname=tgtname,
107+
scrcfiles=sources,
108+
boardname=shargs.board,
109+
))
110+
111+
112+
if shargs.fire :
113+
if not (shargs.sketch and shargs.board) :
114+
print("There remains some placeholder in the output file; I won't build _that_.")
115+
exit(1)
116+
subprocess.run(("cmake", "-S", shargs.sketch, "-B", shargs.sketch/"build"))
117+
subprocess.run(("cmake", "--build", shargs.sketch/"build"))

0 commit comments

Comments
 (0)
Please sign in to comment.