2021-03-21 15:07:09 +00:00
.. include :: /substitutions.rst
.. _cpp_cmake:
2023-10-29 16:40:32 +01:00
=======================
2021-03-21 15:07:09 +00:00
C++ Example using CMake
=======================
In some situations, developers intend to implement software using the NuttX platform in
a previously set hardware and configuration where it is not possible or allowed to make
changes. In such situations, less contact with the operating source tree is better, where
it is only used for the application.
Some approaches are possible to do that today:
* https://cwiki.apache.org/confluence/display/NUTTX/Building+NuttX+with+Applications+Outside+of+the+Source+Tree
* https://www.programmersought.com/article/61604062421/
We have been seen the increase of the use of C++ language in embedded systems application. And
CMake (https://www.cmake.org) is the preferred build system used to build C++ projects. NuttX
support C++ based projects.
Using the 'build as a library' procedure of NuttX, it is possible to build NuttX
applications using C++ language and also the cmake build tool.
This document will show how to reimplement the hellocpp project using this cmake.
Preparation
2023-10-29 16:40:32 +01:00
===========
2021-03-21 15:07:09 +00:00
#. Base NuttX compilation changes
2025-09-03 09:50:12 +02:00
For this example, load the configuration 'stm32f4discovery:nsh' for building (Linux host)
2021-03-21 15:07:09 +00:00
.. code-block :: console
$ cd nuttx
2025-09-03 09:50:12 +02:00
$ ./tools/configure.sh -l stm32f4discovery:nsh
See :ref: `quickstart/compiling_make:Initialize Configuration` for more information about configure.sh tool.
2021-03-21 15:07:09 +00:00
In menuconfig, the main points to be changed on a typical NuttX configuration are the following:
2025-09-03 09:50:12 +02:00
* RTOS Features -> Tasks and Scheduling -> Application entry point to 'main'
* Library Routines -> Have C++ compiler
* Library Routines -> Have C++ initialization -> C++ Library -> Toolchain C++ support (you can also choose the basic version or the LLVM one)
* Library Routines -> Have C++ initialization -> C++ Library -> C++ low level library select -> GNU low level libsupc++
* Library Routines -> Language standard -> choose the version you want - for this example we will use "c++17"
* Library Routines -> Enable Exception Support -> to enable to support C++ exceptions - for this example we will select it
* Library Routines -> Enable RTTI Support -> to enable to support C++ RTTI features (like dynamic_cast()/typeid()) - for this example we will not enable it
2021-03-21 15:07:09 +00:00
2025-09-03 09:50:12 +02:00
Build NuttX and generate the export
2021-03-21 15:07:09 +00:00
.. code-block :: console
$ make export
Creating the project
2023-10-29 16:40:32 +01:00
====================
2021-03-21 15:07:09 +00:00
#. Create your project file structure
The project structure is organized as follow:
.. code-block :: console
hellocpp/
hellocpp/CMakeLists.txt
2025-09-03 09:50:12 +02:00
hellocpp/nuttx-export-12.10.0/
hellocpp/main.cpp
hellocpp/HelloWorld.h
hellocpp/HelloWorld.cpp
The directory 'nuttx-export-12.10.0' is the unzipped content from the file created during
2021-03-21 15:07:09 +00:00
make export procedure done before.
#. File contents
* hellocpp/CMakeLists.txt
.. code-block :: cmake
2025-09-03 09:50:12 +02:00
cmake_minimum_required(VERSION 3.12...3.31)
2021-03-21 15:07:09 +00:00
project(HelloCpp
VERSION 1.0
2021-07-04 11:31:21 -04:00
DESCRIPTION "Hello world C++ NuttX"
2021-03-21 15:07:09 +00:00
)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(SOURCE_FILES
2025-09-03 09:50:12 +02:00
${CMAKE_CURRENT_SOURCE_DIR}/HelloWorld.cpp
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
2021-03-21 15:07:09 +00:00
)
2025-09-03 09:50:12 +02:00
set(EXE_NAME "hello")
add_executable(${EXE_NAME} ${SOURCE_FILES})
2021-03-21 15:07:09 +00:00
add_custom_command(
TARGET ${EXE_NAME}
POST_BUILD
2025-09-03 09:50:12 +02:00
COMMAND ${CMAKE_OBJCOPY} ARGS -S -O binary ${CMAKE_BINARY_DIR}/${EXE_NAME} ${CMAKE_BINARY_DIR}/${EXE_NAME}.bin
2021-03-21 15:07:09 +00:00
2025-09-03 09:50:12 +02:00
* hellocpp/main.cpp
2021-03-21 15:07:09 +00:00
.. code-block :: c++
2025-09-03 09:50:12 +02:00
#include <memory>
2021-03-21 15:07:09 +00:00
#include "HelloWorld.h"
2025-09-03 09:50:12 +02:00
extern "C" int main(int, char*[])
2021-03-21 15:07:09 +00:00
{
2025-09-03 09:50:12 +02:00
auto pHelloWorld = std::make_shared<CHelloWorld>();
pHelloWorld->HelloWorld();
2021-03-21 15:07:09 +00:00
2025-09-03 09:50:12 +02:00
CHelloWorld helloWorld;
helloWorld.HelloWorld();
2021-03-21 15:07:09 +00:00
2025-09-03 09:50:12 +02:00
return 0;
2021-03-21 15:07:09 +00:00
}
2025-09-03 09:50:12 +02:00
* hellocpp/HelloWorld.h
2021-03-21 15:07:09 +00:00
2025-09-03 09:50:12 +02:00
.. code-block :: c++
2021-03-21 15:07:09 +00:00
2025-09-03 09:50:12 +02:00
#ifndef HELLOWORLD_H
#define HELLOWORLD_H
2021-03-21 15:07:09 +00:00
class CHelloWorld
{
2025-09-03 09:50:12 +02:00
public:
CHelloWorld();
~CHelloWorld() = default;
bool HelloWorld();
private:
int mSecret;
2021-03-21 15:07:09 +00:00
};
#endif
2025-09-03 09:50:12 +02:00
* hellocpp/HelloWorld.cpp
2021-03-21 15:07:09 +00:00
.. code-block :: c++
#include <cstdio>
#include <string>
#include "HelloWorld.h"
2025-09-03 09:50:12 +02:00
CHelloWorld::CHelloWorld()
{
mSecret = 42;
std::printf("Constructor: mSecret=%d\n",mSecret);
2021-03-21 15:07:09 +00:00
}
2025-09-03 09:50:12 +02:00
bool CHelloWorld::HelloWorld()
{
std::printf("HelloWorld: mSecret=%d\n",mSecret);
std::string sentence = "Hello";
std::printf("TEST=%s\n",sentence.c_str());
if (mSecret == 42)
{
std::printf("CHelloWorld: HelloWorld: Hello, world!\n");
return true;
}
else
{
std::printf("CHelloWorld: HelloWorld: CONSTRUCTION FAILED!\n");
return false;
}
2021-03-21 15:07:09 +00:00
}
Building
2023-10-29 16:40:32 +01:00
========
2021-03-21 15:07:09 +00:00
To launch build, you use the cmake procedure:
.. code-block :: console
$ mkdir build
$ cd build
2025-09-03 09:50:12 +02:00
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=../nuttx-export-12.10.0/scripts/toolchain.cmake
2021-03-21 15:07:09 +00:00
$ make
2025-09-03 09:50:12 +02:00
Two binaries are generated: an elf one - useful for debug purpose - and a binary one to be flashed on the board