November 23, 2020

How to generate sources file cmake

Today, I feature to you a short tutorial about CMake. How to generate source files during a build! During this post, we will create a binary with CMake and generated files. Don’t hesitate to review my short tutorial about CMake basis here.

The issue - CMAKE returns an error on the generated source file

Sometimes, you could build an application with a generated files. Unfortunately, those files could be sources.

If those files don't exist during the CMake configuration, then it results in an error “No rule to make target 'GeneratedFile.cpp'”.

The Solution - Define a custom command, and change the file property

The solution is done in three steps:

  • Create a custom command with the instruction “add_custom_command”. You will launch your file generator here. 
  • "Make depends" on this new custom target . CMake will be able to launch this target ONLY if those source files are not present.
  • In your target, change the file property to “GENERATED”.
  • EXTRA: In your custom command, you can also add a “DEPENDS” instruction. This command helps CMake to control your custom target and then apply launching rules when dependencies change.

If you apply it, your CMake can control perfectly your file generator!

The Example - A simple C++ file

CMAKE - Generate source file with custom target

cmake_minimum_required(VERSION 3.8)

project(GeneratedFileProject)

# Set generated file
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/GeneratedFile.cpp PROPERTIES GENERATED 1)

add_executable(GeneratedExecutable GeneratedFile.cpp)

#Generator definition - Custom Target
add_custom_command(COMMAND  ${CMAKE_CURRENT_SOURCE_DIR}/fileGenerator.sh
                  OUTPUT    ${CMAKE_CURRENT_BINARY_DIR}/GeneratedFile.cpp
                  DEPENDS   ${CMAKE_CURRENT_SOURCE_DIR}/fileGenerator.sh
                  COMMENT   "Generating GeneratedFile.cpp"
                  )
        
add_custom_target(gen_bar DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/bar.cpp)

As you see here, I applied the instructions:

  1. I create a custom target to launch my fileGenerator.sh
  2. I make depends on this custom target to the generated file.
  3. I set this file as “GENERATED” in my new target.
  4. I make DEPENDS it directly on my file generator script to relaunch it in case of modification.

Now, I can launch my CMake configuration and build the program!

CMake build with generated sources

As you see, the configuration is pretty simple!

About the author 

Axel Fortun

​Developer specialized in Linux environment and embedded systems.
​Knowledge in multiple languages as C/C++, Java, Python​ and AngularJs.
​Working as Software developer since 2014 with a beginning in the car industry​ and then in ​medical systems.