bouncing this thread as I'm recently playing with CMake
for CMake, the canonical way is that each sub-directory is deemed a 'library' and needs to have its own CMakeList.txt file.
CMakeList.txt file is practically the 'makefile', but that on its own it doesn't directly drives the build commands, instead it declares the targets and dependencies. So there are 2 steps, the first step is to generate build scripts (makefiles) in the "build" directory.
https://github.com/stm32duino/Arduino_C ... tart-guide
Code: Select all
cmake -S [source folder] -B [build folder] -G Ninja
then that the next step drives the actual build from the generated scripts
--
if you have source codes within subdirectories in the sketch folder
you need to add
In the CMakeList.txt file in the sketch (parent) folder.
Then in the sub-directory, it needs to have its own
CMakeList.txt
to build the codes within the sub directory as a library
---
one of the bummer I ran into and frustrating is that in sub directories in the sketch folder.
the includes that links headers in the core e.g.
is not added to the include search path, the same happens to all the stm32 series (register) header files
and HAL includes.
Initially I worked around the problem with, adding in the sub-directory CMakeList.txt file
Code: Select all
target_include_directories(sensor PUBLIC "${CORE_PATH}/libraries/SrcWrapper/inc")
target_include_directories(sensor PUBLIC "${CORE_PATH}/libraries/SrcWrapper/inc/LL")
target_include_directories(sensor PUBLIC "${CM5_PATH}/CMSIS/Core/Include")
target_include_directories(sensor PUBLIC "${CORE_PATH}/system/Drivers/CMSIS/Device/ST/STM32F4xx/Include")
target_include_directories(sensor PUBLIC "${CORE_PATH}/system/STM32F4xx")
target_include_directories(sensor PUBLIC "${CORE_PATH}/system/Drivers/STM32F4xx_HAL_Driver/Inc")
target_include_directories(sensor PUBLIC "${CORE_PATH}/cores/arduino")
target_include_directories(sensor PUBLIC "${CORE_PATH}/cores/arduino/stm32")
This works but is not portable. After much frustrating troubleshooting.
It turns out the following works:
-- in the sub-directory say a sensor, the CMakeList should look like
Code: Select all
add_library(sensor)
target_include_directories(sensor PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
target_sources(sensor
PUBLIC
sensor.cpp
sensor.h
)
target_link_libraries(sensor PUBLIC
base_config
core_usage
)
In the above, the
PUBLIC clause for target_link_libraries is critical, apparently using INTERFACE in place of that, do not link the core dependencies (e.g. Arduino.h and/or the Hal and/or register defines). The above links the sensor (lib) to the core base_config and core_usage targets, and resolves the various missing includes. This target_link_libraries() clause is what links sensor to its dependencies e.g. the base_config and core_usage targets in the core.
Then in the skech (parent) folder's CMakeList.txt
Code: Select all
...
include(set_board)
set_board(BLACKPILL_F401CC
# ... use default Serial/USB configuration ...
USB CDC
)
# STEP 3: configure your sketch
# -----------------------------------------------------------------------------
include(build_sketch)
build_sketch(TARGET mysketch
SOURCES
sketch.ino
DEPENDS
USBDevice
)
add_subdirectory("sensor");
target_link_libraries(mysketch PRIVATE sensor)
target_link_libraries(mysketch PRIVATE sensor) clause links the mysketch target (which is the sketch/firmware itself) with the sensor
(lib) in the sub-directory. one could practically, simply place 'sensor' under DEPENDS clause of build_sketch() to the same effect.
but that 'sensor' need to be declared as a library target as above.
----
dependency graph:
In the CMakeList.txt file in the sketch folder add (say at the last line)
Code: Select all
set_property(GLOBAL PROPERTY GLOBAL_DEPENDS_DEBUG_MODE 1)
then run from the parent directory
Code: Select all
cmake -S [source folder] -B [build folder] -G Ninja
this generates a text dependency graph about what target depends on which other targets.
--
I think CMake is a more mature and yet more flexible system vs 'canonical' arduino. CMakes spell dependencies explicitly using executable (add_executable()) or (add_library()) to specify targets. Then using target_link_libraries() to connect targets to one another as dependencies.