How to run cmake commands in add_custom_command in order - cmake

Specifically I'm looking for an example to do what is stated in the cmake documentation for add_custom_command:
If more than one COMMAND is specified they will be executed in order, but not necessarily composed into a stateful shell or batch script. (To run a full script, use the configure_file() command or the file(GENERATE) command to create it, and then specify a COMMAND to launch it.)
A little more detail without bulking this up too much: There's an external program that generates 3 source files that get compiled later. The generation program only updates the timestamp on the files it changes, not all files. So even though my DEPENDS timestamp is newer, it may not need to change 1 of the source files and thus cmake tries to run the code generator each time. I want to touch all the files at the end of the code generation so that ALL their timestamps get updated.
What is the process to run COMMANDS in add_custom_command in order?
EDIT:
This is what I'm currently trying to do:
add_custom_command(
OUTPUT
${CONFIG_TOOLS_GENERATED_FILES}
COMMAND if exist ${Application_SOURCE_DIR}/..MCUExpresso/board rmdir ${Application_SOURCE_DIR}/..MCUExpresso/board
COMMAND
"${MCU_CONFIG_TOOLS_DIR}/bin/eclipsec.exe" -noSplash
-Load ${MEX_FILE}
-HeadlessTool Pins -ExportSrc "${Application_SOURCE_DIR}/../MCUExpresso"
-HeadlessTool Clocks -ExportSrc "${Application_SOURCE_DIR}/../MCUExpresso"
-HeadlessTool Peripherals -ExportSrc "${Application_SOURCE_DIR}/../MCUExpresso"
DEPENDS ${MEX_FILE}
COMMENT "Generating source files using MCU Config Tools"
)
There are two issues here - the directory I'm trying to remove (with the generated code) could end up getting deleted after the code generation runs since the commands aren't stateful. Secondly, the directory doesn't actually get deleted - seems like it's a pathing problem with windows...

Related

How to build multiple configurations of an ESP-IDF application

I have one ESP-IDF application and two hardware boards. I use a preprocessor definition to control which hardware board version to build. For now, I'm modifying the config in the sdkconfig file via menuconfig. But I would like to build both versions at once from a script, or build only one specific config without the manual process of menuconfig.
I have a header that looks like this, and works when HW_VER is set correctly:
#if HW_VER == 2
#define BTN_GPIO 9
#elif HW_VER == 3
#define BTN_GPIO 10
#endif
And from the a script I would like to build each by selecting a value for HW_VER, for example:
idf.py build -DHW_VER=2
idf.py build -DHW_VER=3
The idf.py build command runs cmake and ninja. I'm new to cmake, so perhaps there is a natural way to do this?
I would also like to build release and debug builds, turn on/off memory debugging etc. from the command line.
I've tried idf.py build -DHW_VER=2 but I've learned that these vars are only sent to cmake and not to the preprocessor. The HW_VER macro remains undefined.
Using add_definitions() in my CMakeLists.txt can set HW_VER, but doesn't help me make different builds from the same files.
Using a config variable like CONFIG_HW_VER in the sdkconfig works to control builds using menuconfig but I don't see a way to automate this.
I've considered modifying the configuration variable, CONFIG_HW_VER in the sdkconfig file programmatically, but this file is under source control, and it is auto generated by menuconfig, so that doesn't seem wise.
Similarly I can modify the CMakeLists.txt file programmatically, but that file is also under source control, and isn't a trivial format.
I use two ways to feed custom configurations into an ESP IDF project.
Firstly, the light weight stuff like preprocessor definitions from the environment are quite simple. You have to configure CMakeLists.txt file (the one in project root) to pass variable values from environment into the build process. For example, to create something equivalent to preprocessor definitions -DMY_NUMBER=123 and -DMY_STRING="abc" add this somewhere before the "project" line:
add_compile_definitions(MY_NUMBER=$ENV{MY_NUMBER})
add_compile_definitions(MY_STRING=\"$ENV{MY_STRING}\")
...
project(myproject)
Assuming you're working in Bash, build with:
$ MY_NUMBER=123 MY_STRING="abc" idf.py build
or (for a slightly more "sticky" enviroment):
$ export MY_NUMBER=123 MY_STRING="abc"
$ idf.py build
You can use cmake to add more advanced logic, e.g. setting default values in case the environment doesn't set anything.
Secondly, the more powerful configuration tool for ESP IDF is the menuconfig target and sdkconfig file. As you've already noticed, playing with sdkconfig directly is not so easy. In my projects I consider this a generated temporary file and I never commit it to git. Instead I delete it. When sdkconfig is missing, idf.py will take file sdkconfig.defaults, copy it into sdkconfig and work with this. That is your best mechanism for supporting different hardware configurations - no sdkconfig and instead different variants of sdkconfig.defaults for each hardware you wish to support.
As an example, assume you have two different HW versions described in sdkconfig.defaults.hw_ver1 and sdkconfig.defaults.hw_ver2 and you wish to build for HW ver2 configuration:
$ rm sdkconfig && cp sdkconfig.defaults.hw_ver2 sdkconfig.defaults
$ idf.py reconfigure
Now you can build for this configuration like you usually would:
$ idf.py build
When you wish to build for the other FW configuration, re-execute the previous commands with sdkconfig.defaults.hw_ver1
All this is rather thoroughly documented in the Build System documentation, so feel free to dig in.

CMake: What is the advantage of using -D (command line) over add_compile_definitions or target_compile_definitions or set?

New to CMake. When adding libraries I see a lot of instructions saying do this:
cmake -D OPENSSL_ROOT_DIR=/usr/local/opt/openssl
Why is that preferred over putting it in the actual CMakeLists.txt? e.g.
set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl")
You do not commit the first one to the repository while you either commit the second one or have to be careful to not commit it with other stuff.
The second method is usually used to allow users of some project to modify some aspect of that project. So whatever pertains to the project itself (not customizable) goes straight to the CMake files everything else might be provided from the command line.
Note, also, that the CMake presets add an ability to customize the build outside the CMake files so the method of providing variables directly via a console call is something I'd expect going away and getting replaced with presets. But the way they work is still the same: variables defined in the preset get to CMake cache with generated console call (with an IDE it might be different).

Why there are two buttons in GUI Configure and Generate when CLI does all in one command

I understand that cmake is build generator. It mean that it can generate appropriate builds (makefiles, Visual Studio project etc.) based on instructions from CMakeLists.txt. But I do not understand two things which I guess are related:
Why there are two buttons "Configure" and "Generate" in cmake-gui? In command line tutorials that I've read (e.g. this one) usual process was done with one cmake command.
What is cache in cmake world? AFAIK it is state when "Configure" button was pressed but "Generate" button was not pressed. But why is this useful? What all those variables that pops-up after pressing "Configure" mean? Why I'm supposed to edit them? Isn't the only allowed configuration done via CMakeLists.txt?
Thanks
There are two stages when CMake is run, as reflected by the two buttons in the CMake GUI. The first stage is the configure step where the CMakeLists.txt file is read in. CMake builds up an internal representation of the project during this stage. After that, the second stage called generation occurs where the project files are written out based on that internal representation.
In CMake GUI, the two stages can be run separately. When you run the configure step, the GUI shows all cache variables (see below) which changed their values since the last time configure was run or since CMake GUI was started if this is the first configure run. Normal practice is to re-run the configure stage until no variables are highlighted red. Once configure leaves no variables in red, you can press the generate button and the build tool's native project files will be created and you are good to go starting your builds, etc.
The command line cmake tool doesn't allow you to separate out running the configure and generate steps individually. Rather, it always runs configure and then generate.
For simple projects, the distinction between configuration and generation is not all that important. Simple tutorials will often just lump the two together since the reader can get away without understanding the distinction for basic project arrangements. There are, however, some CMake features which rely on this distinction. In particular, generator expressions are a generation-time feature where decisions about certain aspects of the build are delayed to generation time rather than being fully handled at configure time. One example of this is configuration-specific content such as compiler flags, source files only compiled in for some configurations, etc. The build configuration isn't always known at CMake's configure step (e.g. Xcode and Visual Studio are multi configuration build tools, so there can be more than one and it is selected by the user at build time). The generation step will process generator expressions for each build type and the result can be different for each configuration. You might also find this answer informative regarding this particular example. For a more advanced example of a technique which takes advantage of the distinction between configure and generation stages, see this post, but be aware it is not a common technique.
Regarding your other question about what is the cache, CMake records information between runs in the variable cache. At the end of the run, it updates a file called CMakeCache.txt in the build directory. When you next run CMake, it reads in that cache to pre-populate various things so it doesn't have to recompute them (like finding libraries and other packages) and so that you don't have to supply custom options you want to override each time. You wouldn't typically edit CMakeCache.txt by hand (although it's okay to do so). Rather, you can modify the variables you want in CMake GUI and then re-run the configure step (don't forget to then also run generate to create updated project files). You can also define or modify cache variables at the cmake command line with the -D option.

Using CMake to generate multiple Code Composer build configurations

My goal is to use a script/CMake to create a "Debug" build configuration and a "Release" build configuration that can be switched between within Code Composer Studio's UI (using the "Build Configuration -> Set Active..." option).
Currently,
A script is ran that runs CMake with desired commands (toolchain, etc). A Code Composer Studio project is generated (as described in CMakeLists.txt)
CCS project is imported into CCS
The problem is this only generates a "Debug" build configuration. Is it possible to add a command to CMakeLists.txt, or to cmake command line, or even ccs command line that allows multiple build configurations to be generated?
The only difference between the two will basically be defining NDEBUG, and possibly changing optimization level.
I had this same question...then realized I am the one who originally asked this ~4 years ago! Anyways, I found a way to do this:
Using Code Composer, create the build configuration(s) as you want them to behave. When done, copy the .cproject file to a cproject.in "template". CMake will use this template to generate an identical .cproject for any future cmake builds. Make sure to replace any hardcoded values (ex: project name) with proper cmake variables.
For me, my CMakeLists.txt called configure_file(path/to/cproject.in ${CMAKE_SOURCE_DIR}/.cproject #ONLY).
Also be sure to delete your CMakeCache and CMakeFiles if they already exist...I believe those were preventing me from seeing the resulting change.

Is it possible to execute a command as a super user while using cmake?

I'm working on a project that uses the proxygen library by facebook.
The latter builds itself by means of a script called deps.sh which uses to invoke apt-get as a super user.
I've successfully created a custom target with cmake using the add_custom_target directive, but it fails because of the above call with the error sudo: no tty present and no askpass program specified and it makes sense, of course.
Anyway I've not been able to find a way of executing that script, thus invoking a command as a super user, using the add_custom_target.
I can safely install the library and write a FindProxygen module for my colleagues, so that the build process remains coherent, but I'd like to know if there is a clean solution to the problem of launching a command as root from cmake and thus put the library as a submodule of the project.
You can run installation script in new terminal, so sudo, executed by this script, will work as usual.
COMMAND x-terminal-emulator -e "<...>/deps.sh"
(This may be written as part of add_custom_target, add_custom_command, execute_process, etc.)
add_custom_target(
apt-downloads ALL
COMMAND sudo apt install -y ${DEPENDENCY_LIBRARIES}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "download required dependencies straight from apt on ubuntu"
)
Worked for me
The response is pretty simple: no.
As remarked in the comments, cmake expects to find all the required libraries already installed in the system (or at least, within the search paths) and any other solution would stop the execution and wait for user inputs.
As far as I've seen around, the usual approach, the one I've used too in the above mentioned project and in another one started immediately after, is to create a script that is in charge to download, compile and prepare the project environment, the same way proxygen itself does.
The final user will be asked to firstly executes that script, thus he will be able to proceed using cmake.
That's all, thank you for the comments.