In csolution it is possible to describe several projects and build-types/target-types resulting in several contexts and several build artifacts which may have inter-dependencies. To replace the CPRJ
with cbuild.yml
format and re-implement the CMakeLists.txt generation the following topics are being investigated:
- generating CMakeLists for inter-dependent multi-context solutions
- handling multiple toolchains in the same solution
- modular generation of CMake targets allowing its integration with other CMake based projects and/or build plates (i.e. crossplatform toolchain specific handling)
- integration of existing images (that are i.e. generated using CMake)
- pre/post-build steps
The following diagram gives an overview of the current proposal considering all elements needed or recommended for reaching the above enumerated goals. A practical example addressing some of these concepts can be found in the example folder.
One common approach of describing related CMake projects, with or without inter-dependencies, is adding them to an entry point CMakeLists.txt
using the function add_subdirectory
:
All CMake targets are visible and it is easy to set dependencies using add_dependencies
.
However it has the following drawbacks:
- Only one toolchain per language is supported.
- The
configure
step is common to all targets, leading to the generation of a singlecompile_commands.json
for all subprojects. - It makes difficult the integration of an external stand-alone project in the same solution.
To overcome such limitations it would be advisable to use the ExternalProject
functions:
Example: SuperProject CMakeLists orchestrating contexts as external projects.
This allows to run individual steps such as configure
and build
independently, enabling the use of a different toolchain for each context as well as the generation of a compilation database at context level. The steps can be managed as CMake targets via ExternalProject_Add_StepTargets
as well as ExternalProject_Add_StepDependencies
.
A possible disadvantage of this pattern is the superfluous overhead introduced by the CMake Compiler Detection phase when several contexts use the same toolchain. A custom step to optionally run the compiler detection just once per toolchain could be developed to overcome this drawback.
Toolchain configuration data and CMakeLists could be generated without explicit absolute paths nor references to the CMSIS-Toolbox installation files, making them portable.
For reaching this goal the destination platform must be properly configured: the environment variable CMSIS_PACK_ROOT
must be set, the CMSIS-Pack repository must be initialized, the needed packs downloaded and installed, the needed toolchains should be installed and properly registered via environment variables <name>_TOOLCHAIN_<major>_<minor>_<patch>
.
The experience with the current Build Manager has shown communalities among the different embedded toolchains are frequent while newer versions usually bring only small deltas. Also a better machine-readable format such as YML/JSON would be preferred over *.cmake files allowing tools such as the Project Manager to easily read information that is currently only available at the CMake running phase.
For this reason the suggestion here is to keep the common functions in *.cmake templates and shift the toolchain specific data into YML files. For example this could be a snippet of a hypothetical AC6.yml
file:
toolchain-options:
cpu:
- for-compiler: AC6@>=6.6
Cortex-M3: -mcpu=Cortex-M3
- for-compiler: AC6@>=6.18
Cortex-M85: -mcpu=Cortex-M85
For the customization of the generated CMakeLists.txt
at solution and/or at context level in a persistent way, avoiding overwriting when regenerating them, a possible approach is to use customizable templates.
In a similar way the toolchain configuration *.cmake files could also benefit from customizable templates.
CMake targets describing components build information and user files build information could be placed in modules separately from the toolchain specific handling, the so-called build plate, enabling their use from different tools and build systems.
Example: groups.cmake
and components.cmake
are generated/placed separately.
A build-run is inherently related to a context. In addition to solution level pre/post-build steps that run before/after all build-runs, individual context pre/post-build steps should be also accepted. Rather then placing execute
nodes under projects
, it sounds natural to specify them at solution or at context level.
Input and output files should be also considered for correctly triggering pre/post-build steps, unless they are intended for running always unconditionally. The execute
node alongside a file
has an obvious implicit output and can be omitted.
csolution.yml
example:
solution:
executes:
- execute: Run solution prebuild
run: generate-keys.sh
always: true
output:
- generated/keys.h
- execute: Run solution postbuild
run: zip-artifacts.sh
input:
- $elf(project.App+ARMCM3)$
- $lib(project.AC6+ARMCM3)$
- $lib(project.GCC+ARMCM3)$
output:
- archives/artifacts.zip
cproject.yml
example:
project:
executes:
- execute: Run context prebuild
run: generate-debug-src.sh
output:
- generated/Debug/$TargetType$.c
for-context: .Debug
- execute: Run context postbuild
run: sign-artifacts.sh
input:
- $lib()$
output:
- $OutDir()$/project.signed.lib
Examples of possible CMakeLists implementation:
- Example 1: Solution level pre-build step, run always.
- Example 2: Solution level post-build step, depends on all contexts build artifacts.
- Example 3: Context level pre-build step, run always.
- Example 4: Context level post-build step, depends on context build artifact.
A generic CMake based library does not bring a build plate, i.e. it does not have crossplatform settings for building it with any embedded toolchain in particular. It is expected to have a parent CMake project that configures the crossplatform environment. In the current proposal it can be added via custom templates or by extending the csolution specification to accept external projects.
See Using CMakeLists templates.
csolution.yml
example:
solution:
projects:
- project: ./CMakeGenericLibrary
cmake: generic # [standalone|generic]
input:
- $lib(AnotherLib)$
output:
- generic.lib
for-context: .Release
Stand-alone CMake based projects are fully configured and don't need a build plate. Also in such cases it is possible to integrate it via custom templates or by extending the csolution specification.
See Using CMakeLists templates.
csolution.yml
example:
solution:
projects:
- project: ./CMakeStandaloneProject
cmake: standalone # [standalone|generic]
input:
- $OutDir(CMakeGenericLibrary.Release+ARMCM3)$/generic.lib
output:
- out/standalone.elf
In this use case CMSIS Components are integrated into existing stand-alone CMake based projects. The user's CMSIS components selection/configuration needs to be translated in csolution yml files that are then processed by the Project Manager, generating cbuild.yml files and finally the CMSIS generic build info is added to the stand-alone project. A proof-of-concept for such CMake Module has been developed: CMSIS-Pack-Utils.
See Generating decoupled CMSIS components build information.
- The
CMake binary directory
of each context could be named according to its index (ordinal number) instead of its full context name and placed right after the intermediate base directory. This strategy would lead to the shortest possible object file paths.
- The intermediate and output directory customization
output-dirs
is targeted at context level. In particular theintdir
would need to be amended: in the multi-context scenario a solution level intermediate directory is needed to store the top-levelCMakeLists.txt
. - Context inter-dependencies retrieved from context related access sequences should be added to cbuild-idx.yml file.
- The
projects
references should accept external CMake based libraries and stand-alone projects. - The
execute
node should accept input and output files assignment.
A test plan for the migration of integration test cases should be developed before the implementation of the new context-level CMakeLists, enabling its test-driven development.