Skip to content

Implementing an alternative build framework with CMake #1776

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 30 commits into from
Dec 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0f3e09f
feat: CMake prototype for L433RCTxP.
massonal Sep 15, 2022
b79e0a6
feat: CMake downloads the CMSIS, GCC
massonal May 30, 2022
f701aee
feat: make __FILE__ relative
massonal Jun 7, 2022
6591736
feat: Implemented board selection
massonal Jun 10, 2022
4595eea
feat: CMake prototype for L433RCTxP.
fpistm Dec 19, 2022
2f2feb1
fix: align with changes in boards.txt from 2.3.0
massonal Jun 22, 2022
ef166a5
feat: full support of precompiled libraries
massonal Jun 23, 2022
e036d88
refactor: moved flags out of the toolchain file
massonal Jun 23, 2022
2dcd73f
feat: added user handles to pick board features.
massonal Jun 24, 2022
5e9ae0c
feat: generate prototypes for .ino files
massonal Jun 29, 2022
4be8d86
refactor: enhanced user interface
massonal Jul 1, 2022
f8050de
feat: autogenerate the user's CMakeLists.txt
massonal Jul 18, 2022
ce91928
refactor: change the way set_board returns its result
massonal Jul 19, 2022
da5af70
feat: manage dependencies wrt. core version
massonal Jul 21, 2022
0e35d7a
feat: new optional features
massonal Jul 25, 2022
c4af950
doc: add a CMake README file
massonal Jul 26, 2022
4a169ad
refactor: general cleanup, messaging
massonal Jul 25, 2022
95cfdcd
feat: Added an updater script for CMake
massonal Jul 28, 2022
01a1064
feat: easy_setup prompts board codenames
massonal Aug 18, 2022
b7a8115
feat: handle bootloaders
massonal Sep 6, 2022
ff8a68e
fix: apply black formatter
fpistm Sep 16, 2022
f926891
fix: error and warning raised by flake8
fpistm Sep 16, 2022
128addd
feat: add argparse to cmake_updater_hook
massonal Sep 16, 2022
2d5d817
doc: update links in easy_setup
massonal Sep 16, 2022
a06ddd7
fix: add `enable_language()` calls at library level
massonal Sep 16, 2022
0db425c
fix: harden cmake_easy_setup
massonal Oct 25, 2022
ad5a28b
fix: force the .elf suffix on output
massonal Nov 14, 2022
5d9f8dc
chore(cmake): update after rebase
fpistm Dec 19, 2022
62eabec
fix: update BareMinimum CMakeLists.txt
fpistm Dec 20, 2022
9283782
ci: create new workflow to test cmake
fpistm Dec 20, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
29 changes: 29 additions & 0 deletions .github/workflows/Cmake.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CMake config and build

on:
push:
branches:
- main
pull_request:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
cmake:
name: Check CMake usage
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@main

- name: Get latest CMake and Ninja
uses: lukka/get-cmake@latest

- name: Configure
run: |
mkdir build
cmake -S CI/build/examples/BareMinimum -B ./build -G Ninja

- name: Build example
working-directory: '${{ github.workspace }}/build'
run: ninja
48 changes: 48 additions & 0 deletions CI/build/examples/BareMinimum/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# This file was autogenerated by cmake\scripts\cmake_easy_setup.py.
# Use it in your CMake configuration by `include()`'ing it.
# You can also copy it in your sketch's folder and edit it to fit your project.

cmake_minimum_required(VERSION 3.21)

# STEP 1: set up bases of environment
# -----------------------------------------------------------------------------

file(REAL_PATH "../../../../" CORE_PATH EXPAND_TILDE)
file(TO_CMAKE_PATH "${CORE_PATH}" CORE_PATH)

set(BOARDNAME "NUCLEO_F103RB")

list(APPEND CMAKE_MODULE_PATH ${CORE_PATH}/cmake)
set(CMAKE_TOOLCHAIN_FILE toolchain)


# You may remove this block when using this file as the sketch's CMakeLists.txt
if (NOT ${CMAKE_PARENT_LIST_FILE} STREQUAL ${CMAKE_CURRENT_LIST_FILE})
# When we are imported from the main CMakeLists.txt, we should stop here
# not to interfere with the true build config.
return()
endif()

project("BareMinimum_project")

# STEP 2: configure the build
# -----------------------------------------------------------------------------
include(set_board)
set_board("${BOARDNAME}")

include(overall_settings)
overall_settings()

include(build_sketch)
build_sketch(TARGET "BareMinimum"
SOURCES
BareMinimum.ino
DEPENDS
CMSIS_DSP
EEPROM
IWatchdog
Servo
SoftwareSerial
SPI
Wire
)
66 changes: 66 additions & 0 deletions README_CMAKE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
CMake can now be used to build Arduino sketches with this core.
Examples of use can be found on this repo: [stm32duino/CMake_workspace](https://github.com/stm32duino/CMake_workspace).

This README only provides a quick walk-through.
For all the glorious details, please head over to [the wiki](https://github.com/stm32duino/wiki/wiki/CMake_presentation).

# Prerequisites

- CMake version >= 3.21
- Python3 version >= 3.9
- `make` / `ninja` (prefer `ninja`)
- graphviz layout engines: `dot`, `sfdp` (optional)
- Python modules: `graphviz`, `jinja2`; install them with `pip install ...`

Some additional dependencies (toolchain...) will be downloaded on the first build.

If your system does not provide a recent enough version of CMake, a suitable version may be installed with [`pip`](https://pypi.org/): `pip install cmake`.

# Usage

This section will describe the process of building a sketch "by hand", with a system shell. Other methods, such as with an IDE plug-in, may require adaptations.

Please see [stm32duino/CMake_workspace](https://github.com/stm32duino/CMake_workspace) for some quick examples; more may be added over time.

First of all, there has to be a CMakeLists.txt in the sketch folder.

- easy way: fire `cmake/scripts/cmake_easy_setup.py -b <board> -s <sketch folder>` (this requires arduino-cli and jinja)
- advanced way: write your own by adapting from an example

--------

__Board name__: either through the script or directly in the CMakeLists.txt, the board name is the identifier found in boards.txt. (Yes, CMake is made aware of boards.txt/platform.txt.)
In the following example, the value to retain would be "NUCLEO_F207ZG" (the part after "menu.pnum."):
```
# NUCLEO_F207ZG board
Nucleo_144.menu.pnum.NUCLEO_F207ZG=Nucleo F207ZG
Nucleo_144.menu.pnum.NUCLEO_F207ZG.node=NODE_F207ZG
```

--------

Then CMake can be run to launch the configuration step. This is only needed on the very first time, at the beginning of the project.
```sh
cmake -S [sketch folder] -B [build folder] -G Ninja # "-G Ninja" -> generate ninja files (default = make)
```
The build folder is conventionally located at the root of the sketch folder and named `build`, e.g. :
```
.
|-- Blink/
| |-- Blink.ino
| |-- CMakeLists.txt
| `-- build/
```

Finally, the sketch can be (re-)built with `cmake --build <build folder>`.
This can also be done by invoking the build tool (usually `make` or `ninja`) directly from the build folder.
**This last step is the only one needed in order to rebuild the project, even if some source files, or even the CMakeLists.txt, have changed.**

For more details on how to use CMake, please read the CMake [User Interaction Guide](https://cmake.org/cmake/help/v3.21/guide/user-interaction/index.html).

The official [CMake tutorial](https://cmake.org/cmake/help/latest/guide/tutorial/index.html) may also be useful for users looking to understand all the implementation details.

# Caveats

- The CMake build model makes it hard to auto-detect dependencies between the sketch and the Arduino libraries, and between Arduino libraries. Thus, you have to specify them manually; see the examples to see how.
- Uploading the binaries to the board is not implemented; this step is up to you, using the appropriate tool. If your board supports the "mass storage" method, you can simply copy the .bin file to your board drive in the file explorer.
81 changes: 81 additions & 0 deletions cmake/FindArduinoCtags.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
cmake_minimum_required(VERSION 3.21)
include(FetchContent)
include(FindPackageHandleStandardArgs)

function(get_ctags)
cmake_host_system_information(
RESULT HOSTINFO
QUERY OS_NAME OS_PLATFORM
)
list(GET HOSTINFO 0 HOST_OS)
list(GET HOSTINFO 1 HOST_ARCH)

unset(CPUCODE)
string(TOUPPER ${HOST_ARCH} HOST_ARCH)
if (${HOST_ARCH} MATCHES "^(AMD64|X86_64|x64)$")
set(CPUCODE "x86_64")
elseif (${HOST_ARCH} MATCHES "^(ARM|ARM64)$")
# not sure there, am I specific enough?
set(CPUCODE "armv6")
elseif (${HOST_ARCH} MATCHES "^(I386|IA32|x86|i686)$")
set(CPUCODE "i686")
endif()

unset(OSCODE)
unset(ARCHIVE_EXT)
if (${HOST_OS} STREQUAL "Linux")
if(${CPUCODE} STREQUAL "armv6")
set(OSCODE "linux-gnueabihf")
# ... I guess? Is there any further check to perform?
else()
set(OSCODE "pc-linux-gnu")
endif()
set(ARCHIVE_EXT ".tar.bz2")
elseif (${HOST_OS} STREQUAL "Windows")
if(${CPUCODE} MATCHES "i686|x86_64")
# ctags supports only 32-bit for Windows
set(CPUCODE "i686")
set(OSCODE "mingw32")
set(ARCHIVE_EXT ".zip")
endif()
elseif (${HOST_OS} STREQUAL "Darwin")
if(${CPUCODE} STREQUAL "x86_64")
set(OSCODE "apple-darwin")
set(ARCHIVE_EXT ".zip")
endif()
endif()

# the SHA512 file is of the form "hash_in_hexa filename"
if(NOT EXISTS ${DL_DIR}/ctags_sha512.txt)
file(DOWNLOAD
"https://github.com/arduino/ctags/releases/download/5.8-arduino11/ctags-5.8-arduino11-${CPUCODE}-${OSCODE}${ARCHIVE_EXT}.sha512"
${DL_DIR}/ctags_sha512.txt
)
endif()
file(READ ${DL_DIR}/ctags_sha512.txt CHECKSUM_FULLTEXT)
string(SUBSTRING "${CHECKSUM_FULLTEXT}" 0 128 CHECKSUM) # keep just the hash; 512 bits make 128 hex characters

FetchContent_Declare(
ctags
SOURCE_DIR ${DL_DIR}/dist/ctags
PREFIX ${DL_DIR}
URL "https://github.com/arduino/ctags/releases/download/5.8-arduino11/ctags-5.8-arduino11-${CPUCODE}-${OSCODE}${ARCHIVE_EXT}"
URL_HASH SHA512=${CHECKSUM}
UPDATE_DISCONNECTED
)
message(STATUS "Downloading Arduino's ctags...")
FetchContent_MakeAvailable(ctags)
message(STATUS "Downloading Arduino's ctags... Done.")
endfunction()

# -------------------------------------------------------------------------------

if(NOT EXISTS ${DL_DIR}/dist/ctags)
get_ctags()
endif()

find_program(ARDUINOCTAGS_EXECUTABLE ctags PATHS ${DL_DIR}/dist/ctags NO_DEFAULT_PATH)

find_package_handle_standard_args(ArduinoCtags DEFAULT_MSG
ARDUINOCTAGS_EXECUTABLE
)
Loading