How do I add files generated during the build to my include directory? - c++

I'm trying to use a Python script to generate some header and source files for my C++ code and move them to the appropriate source directories, as the subsequent C++ build requires them.
Here's what the current iteration of my code looks like :
# Generate the Parameters and ParamParser files.
add_custom_command(
OUTPUT include/waveparameters.h
include/waveparser.h
src/waveparser.cpp
DEPENDS ${PROJECT_SOURCE_DIR}/scripts/wave.json
COMMAND python3 ${CMAKE_SOURCE_DIR}/scripts/genParams.py ${CMAKE_CURRENT_SOURCE_DIR}/scripts/wave.json
COMMENT "Generating custom Parameters files"
VERBATIM USES_TERMINAL
)
add_custom_target(PAR_GENERATION
DEPENDS include/waveparameters.h
include/waveparser.h
src/waveparser.cpp
)
set(MULTIGRID_INCLUDE_FILES
include/waveparameters.h
include/firstorderwave.h
include/waveparser.h
)
set(MULTIGRID_SOURCE_FILES
src/multiGridTest.cpp
src/firstorderwave.cpp
src/waveparser.cpp
)
set(SOURCE_FILES ${MULTIGRID_INCLUDE_FILES} ${MULTIGRID_SOURCE_FILES})
add_executable(MultiGridTest ${SOURCE_FILES})
target_include_directories(MultiGridTest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_include_directories(MultiGridTest PRIVATE ${CMAKE_SOURCE_DIR}/include)
target_link_libraries(MultiGridTest oops ${EXTRA_LIBS} m)
The current code generation works just fine.
However, no matter what directory I specify for the output (including ${CMAKE_CURRENT_SOURCE_DIR}/include or ${CMAKE_SOURCE_DIR}/MultiGrid/include and related paths), the generated .h and .cpp files always get moved to the directory my binary is generated in :
${CMAKE_SOURCE_DIR}/build/MultiGrid
rather than :
${CMAKE_SOURCE_DIR}MultiGrid/include` and `${CMAKE_SOURCE_DIR}/MultiGrid/src

I figured it out a while ago using Tsyvarev's advice in the comments. The solution was to add WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} as an argument to add_custom_command.

Related

Forcing cmake to call external executable before reading source files [duplicate]

Example source of a binary I want to run before each build, once per add_executable:
#include <stdio.h>
int main(int argc, char *argv[]) {
for(int i=0; i<argc; ++i)
printf("argv[%d] = %s\n", i, argv[i]);
fclose(fopen("foo.hh", "a"));
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(foo_proj)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
set(SOURCE_FILES main.cpp)
# ---- this line changes ----
add_executable(foo_proj ${SOURCE_FILES})
Attempts:
add_custom_target(create_foo_hh COMMAND /tmp/bin/create_foo_hh)
add_dependencies(${SOURCE_FILES} create_foo_hh)
Error:Cannot add target-level dependencies to non-existent target "main.cpp".
The add_dependencies works for top-level logical targets created by the add_executable, add_library, or add_custom_target commands. If you want to add file-level dependencies see the DEPENDS option of the add_custom_target and add_custom_command commands.
execute_process(COMMAND /tmp/bin/create_foo_hh main.cpp)
No error, but foo.hh isn't created.
How do I automate the running of this command?
execute_process() is invoked at configuration time.
You can use add_custom_command():
add_custom_command(
OUTPUT foo.hh
COMMAND /tmp/bin/create_foo_h main.cpp
DEPENDS ${SOURCE_FILES} /tmp/bin/create_foo_hh main.cpp
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_executable(foo_proj ${SOURCE_FILES} foo.hh)
That way, foo.hh is a dependency of foo_proj: and your command will be invoked when building foo_proj. It depends on ${SOURCE_FILES} and /tmp/bin/create_foo_hh main.cpp so that it is generated again if one of those files changes.
Regarding paths, add_custom_command() is configured to run in the current build directory to generate the file there, and include_directories() is used to add the build directory to the include dirs.
You probably don't want the custom target to depend on your source files (because they aren't targets themselves and are therefore never "run"), but on the target you create with them:
target_add_dependencies(foo_proj create_foo_hh)
I think that the cleanest is to add two new project() (targets) and then add the resulting file to your final executable. This is how cmake can build a valid dependency tree so when your source files change they get recompiled, the command run, as necessary to get everything up to date.
Build Executable
First, as you do in your example, I create an executable from some .cpp file:
(example extracted from the as2js project)
project(unicode-characters)
add_executable(${PROJECT_NAME}
unicode_characters.cpp
)
target_include_directories(${PROJECT_NAME}
PUBLIC
${ICU_INCLUDE_DIRS}
${SNAPDEV_INCLUDE_DIRS}
)
target_link_libraries(${PROJECT_NAME}
${ICU_LIBRARIES}
${ICU_I18N_LIBRARIES}
)
As we can see,m we can add specific include paths (-I) and library paths (-L). It is specific to that one target so you can have a set of paths that is different from the one used with your other executables.
Generate Additional File
Next, you create a custom command to run your executable like so:
project(unicode-character-types)
set(UNICODE_CHARACTER_TYPES_CI ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.ci)
add_custom_command(
OUTPUT
${UNICODE_CHARACTER_TYPES_CI}
COMMAND
unicode-characters >${UNICODE_CHARACTER_TYPES_CI}
WORKING_DIRECTORY
${PROJECT_BINARY_DIR}
DEPENDS
unicode-characters
)
add_custom_target(${PROJECT_NAME}
DEPENDS
${UNICODE_CHARACTER_TYPES_CI}
)
Notice a couple of things:
I set a variable (UNICODE_CHARACTER_TYPES_CI) because I am going to reference that one file multiple times
a. Notice how I put the destination in the binary (cmake output folder) using the ${PROJECT_BINARY_DIR}/... prefix. This is best to avoid generating those files in your source tree (and possibly ending up adding that file to your source tracking system like svn or git).
b. An important aspect of the add_custom_command() is the DEPENDS section which includes the name of your special command, the one we defined in the previous step.
The add_custom_target() is what allows cmake to find your target and execute the corresponding command whenever one of the source files (a.k.a. dependency) changes; notice the DEPENDS definition.
Use the Output
Finally, here is the main project (a library in my case) that makes use of the file we generated in the step above.
Notice that I reference that file using the variable I defined in the previous step. That way, when I feel like changing that name, I can do it by simply editing that one variable.
project(as2js)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/version.h.in
${CMAKE_CURRENT_BINARY_DIR}/version.h
)
add_library(${PROJECT_NAME} SHARED
compiler/compiler.cpp
...
parser/parser_variable.cpp
${UNICODE_CHARACTER_TYPES_CI}
file/database.cpp
...
)
(Note: the ... represent a list of files, shorten for display here as these are not important, the link above will take you to the file with the complete list.)
By having the filename inside the list of files defined in the add_library() (or the add_executable() in your case), you create a dependency which will find your custom_target(), because of the filename defined in the OUTPUT section of the add_custom_command()¹.
¹ It is possible to defined multiple outputs for an add_custom_command(). For example, some of my generators output a .cpp and a .h. In that case, I simply define both files in the OUTPUT section.
Results
Important points about the final results with this solution:
the output files of your generator are saved in the binary output path instead of your current working directory
the Makefile generated by cmake includes all the necessary targets/dependencies which means changing any of the input files regenerate everything as expected (even if you just update a comment)
if the generator fails, the build fails as expected
the files are generated by the build step (make time) instead of the generation step (cmake time, like the execute_process() would do)

CMake run custom command before build?

Example source of a binary I want to run before each build, once per add_executable:
#include <stdio.h>
int main(int argc, char *argv[]) {
for(int i=0; i<argc; ++i)
printf("argv[%d] = %s\n", i, argv[i]);
fclose(fopen("foo.hh", "a"));
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(foo_proj)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
set(SOURCE_FILES main.cpp)
# ---- this line changes ----
add_executable(foo_proj ${SOURCE_FILES})
Attempts:
add_custom_target(create_foo_hh COMMAND /tmp/bin/create_foo_hh)
add_dependencies(${SOURCE_FILES} create_foo_hh)
Error:Cannot add target-level dependencies to non-existent target "main.cpp".
The add_dependencies works for top-level logical targets created by the add_executable, add_library, or add_custom_target commands. If you want to add file-level dependencies see the DEPENDS option of the add_custom_target and add_custom_command commands.
execute_process(COMMAND /tmp/bin/create_foo_hh main.cpp)
No error, but foo.hh isn't created.
How do I automate the running of this command?
execute_process() is invoked at configuration time.
You can use add_custom_command():
add_custom_command(
OUTPUT foo.hh
COMMAND /tmp/bin/create_foo_h main.cpp
DEPENDS ${SOURCE_FILES} /tmp/bin/create_foo_hh main.cpp
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_executable(foo_proj ${SOURCE_FILES} foo.hh)
That way, foo.hh is a dependency of foo_proj: and your command will be invoked when building foo_proj. It depends on ${SOURCE_FILES} and /tmp/bin/create_foo_hh main.cpp so that it is generated again if one of those files changes.
Regarding paths, add_custom_command() is configured to run in the current build directory to generate the file there, and include_directories() is used to add the build directory to the include dirs.
You probably don't want the custom target to depend on your source files (because they aren't targets themselves and are therefore never "run"), but on the target you create with them:
target_add_dependencies(foo_proj create_foo_hh)
I think that the cleanest is to add two new project() (targets) and then add the resulting file to your final executable. This is how cmake can build a valid dependency tree so when your source files change they get recompiled, the command run, as necessary to get everything up to date.
Build Executable
First, as you do in your example, I create an executable from some .cpp file:
(example extracted from the as2js project)
project(unicode-characters)
add_executable(${PROJECT_NAME}
unicode_characters.cpp
)
target_include_directories(${PROJECT_NAME}
PUBLIC
${ICU_INCLUDE_DIRS}
${SNAPDEV_INCLUDE_DIRS}
)
target_link_libraries(${PROJECT_NAME}
${ICU_LIBRARIES}
${ICU_I18N_LIBRARIES}
)
As we can see,m we can add specific include paths (-I) and library paths (-L). It is specific to that one target so you can have a set of paths that is different from the one used with your other executables.
Generate Additional File
Next, you create a custom command to run your executable like so:
project(unicode-character-types)
set(UNICODE_CHARACTER_TYPES_CI ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.ci)
add_custom_command(
OUTPUT
${UNICODE_CHARACTER_TYPES_CI}
COMMAND
unicode-characters >${UNICODE_CHARACTER_TYPES_CI}
WORKING_DIRECTORY
${PROJECT_BINARY_DIR}
DEPENDS
unicode-characters
)
add_custom_target(${PROJECT_NAME}
DEPENDS
${UNICODE_CHARACTER_TYPES_CI}
)
Notice a couple of things:
I set a variable (UNICODE_CHARACTER_TYPES_CI) because I am going to reference that one file multiple times
a. Notice how I put the destination in the binary (cmake output folder) using the ${PROJECT_BINARY_DIR}/... prefix. This is best to avoid generating those files in your source tree (and possibly ending up adding that file to your source tracking system like svn or git).
b. An important aspect of the add_custom_command() is the DEPENDS section which includes the name of your special command, the one we defined in the previous step.
The add_custom_target() is what allows cmake to find your target and execute the corresponding command whenever one of the source files (a.k.a. dependency) changes; notice the DEPENDS definition.
Use the Output
Finally, here is the main project (a library in my case) that makes use of the file we generated in the step above.
Notice that I reference that file using the variable I defined in the previous step. That way, when I feel like changing that name, I can do it by simply editing that one variable.
project(as2js)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/version.h.in
${CMAKE_CURRENT_BINARY_DIR}/version.h
)
add_library(${PROJECT_NAME} SHARED
compiler/compiler.cpp
...
parser/parser_variable.cpp
${UNICODE_CHARACTER_TYPES_CI}
file/database.cpp
...
)
(Note: the ... represent a list of files, shorten for display here as these are not important, the link above will take you to the file with the complete list.)
By having the filename inside the list of files defined in the add_library() (or the add_executable() in your case), you create a dependency which will find your custom_target(), because of the filename defined in the OUTPUT section of the add_custom_command()¹.
¹ It is possible to defined multiple outputs for an add_custom_command(). For example, some of my generators output a .cpp and a .h. In that case, I simply define both files in the OUTPUT section.
Results
Important points about the final results with this solution:
the output files of your generator are saved in the binary output path instead of your current working directory
the Makefile generated by cmake includes all the necessary targets/dependencies which means changing any of the input files regenerate everything as expected (even if you just update a comment)
if the generator fails, the build fails as expected
the files are generated by the build step (make time) instead of the generation step (cmake time, like the execute_process() would do)

Avoiding many "../include" in CMake

I just started getting into CMake with C++ and was wondering how other programmers avoid having to do "../include" in all their CMakeFiles.txt.
One example is here: https://github.com/clab/cnn/blob/master/examples/CMakeLists.txt
They create an executable for each example without having to call INCLUDE_DIRECTORIES(...).
I tried adding the headers when calling ADD_LIBRARY(...), but that didn't seem to work.
Example:
tl/src/CMakeLists.txt:
SET(SRCS "x1.cpp" "x2.cpp")
SET(HDRS "../include/tl/x1.h" "../include/tl/x2.h")
INCLUDE_DIRECTORIES("../include")
ADD_LIBRARY(test_lib ${SRCS} ${HDRS})
tl/CMakeLists.txt:
PROJECT(TEST_LIB VERSION 0.1)
ADD_SUBDIRECTORY("src")
tl/examples/CMakeLists.txt:
INCLUDE_DIRECTORIES("../include")
ADD_EXECUTABLE(e1 e1.cpp)
TARGET_LINK_LIBRARIES(e1 test_lib)
Edit: I believe that INCLUDE_DIRECTORIES(...) is only necessary one per each directory throughout the tree.
Just add the INCLUDE_DIRECTORIES command at the top level. No need to explicitly add included files then.
tl/CMakeLists.txt:
PROJECT(TEST_LIB VERSION 0.1)
INCLUDE_DIRECTORIES("include")
ADD_SUBDIRECTORY("src")
ADD_SUBDIRECTORY("examples")
tl/src/CMakeLists.txt:
ADD_LIBRARY(test_lib "x1.cpp" "x2.cpp")
tl/examples/CMakeLists.txt:
ADD_EXECUTABLE(e1 e1.cpp)
TARGET_LINK_LIBRARIES(e1 test_lib)
How about this? tl/CMakeLists.txt
SET(SRCS "x1.cpp" "x2.cpp")
SET(HDRS "../include/tl/x1.h" "../include/tl/x2.h")
INCLUDE_DIRECTORIES("${CMAKE_PROJECT_DIR}/include")
ADD_LIBRARY(test_lib ${SRCS} ${HDRS})
You do not need to add headers to ADD_LIBRARY or ADD_EXECUTABLE if you want to compile your programs and libs. Only source files "cpp,c,cxx,..." are required because through the include macro #include you tell the compiler where it finds the header files.
With INCLUDE_DIRECTORIES(...) you only add a search path to the compiler where to look for headers. If you have your headers in the same directory as your source you don't need another search path. Also subpaths with include macro like this #include "../../include" is possible. So it really depends on the structure of your source files. Also remember, compiler settings setups know where some of the system headers are found. That is why you also do not need to define them.
And last but not least there are cmake scripts and pkg search files where adding paths to specific libraries is done automatically.
This is how I did it in a project of mine:
file(GLOB_RECURSE SRC
engine/*.cpp
platfoorm/*.cpp
)
file(GLOB_RECURSE INCLUDES
engine/*.h
platform/*.h
)
This generate an internal "hardcoded" list of files that the generated makefil will use, so if you add a new source file you will need to re-run cmake.
Of course you can change and add paths, the one in the example are the one I used in my project.

CMake -- Add all sources in subdirectory to cmake project

As a follow up to this question:
Add Source in a subdirectory to a cmake project
What is the best way (perhaps using the FILE directive?) to select all the .cpp and .h files in the subdirectory and add them to the SOURCE variable defined in the parent directory?
Example from answer to question above:
set(SOURCE
${SOURCE}
${CMAKE_CURRENT_SOURCE_DIR}/file1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/file2.cpp
PARENT_SCOPE
)
set(HEADERS
${HEADERS}
${CMAKE_CURRENT_SOURCE_DIR}/file1.hpp
${CMAKE_CURRENT_SOURCE_DIR}/file2.hpp
PARENT_SCOPE
)
Is it possible to do something like this?
FILE(GLOB SUB_SOURCES *.cpp)
set(SOURCE
${SOURCE}
${CMAKE_CURRENT_SOURCE_DIR}/${SUB_SOURCES}
PARENT_SCOPE
)
What is the best way (using CMake) to compile all the sources in a directory and a subdirectory into a single output file (not multiple libraries?)
I think what you are looking for is the aux_source_directory command.
aux_source_directory Find all source files in a directory.
aux_source_directory( )
Collects the names of all the source files in the specified directory
and stores the list in the provided. This command is
intended to be used by projects that use explicit template
instantiation. Template instantiation files can be stored in a
"Templates" subdirectory and collected automatically using this
command to avoid manually listing all instantiations.
It is tempting to use this command to avoid writing the list of source
files for a library or executable target. While this seems to work,
there is no way for CMake to generate a build system that knows when a
new source file has been added. Normally the generated build system
knows when it needs to rerun CMake because the CMakeLists.txt file is
modified to add a new source. When the source is just added to the
directory without modifying this file, one would have to manually
rerun CMake to generate a build system incorporating the new file.
Your CMakeLists.txt within the subdirectory could look like this:
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SUB_SOURCES)
set(SOURCE
${SOURCE}
${SUB_SOURCES}
PARENT_SCOPE
)
The recommended practice is however, as you see from the documentation, to list the files individually within CMakeLists.txt as changes to the CMakeLists.txt file triggers running cmake.
I hope this was helpful and to the point.

CMake: conditionally generate protobuf `*pb.{h|cpp}` files when *.proto files change

I am part of a project that is using protobufs to communicate between a Python based client and a c++ based server. We are also using CMake.
With CMake, I am looking for a way to conditionally call the protoc program only when *.proto files change. My current directory structure (this seems to be part of the problem) has a directory for the *.proto files, and separate directories for the generated *.pb.{h|cc} and *_pb2.py files:
build/
Messages/proto/ <--- .proto files are here
Messages/cpp/ <--- would like the auto generated c++ files here
Messages/py/ <--- would like the auto generated Python files here
Server/Main.cpp
Client/Main.py
CMakeLists.txt
The (root) CMakeLists.txt file (below) runs the protoc program when the build/cmake .. command is executed:
project(AAA)
MESSAGE("Protobuf autogeneration STARTED")
file(GLOB proto_packages "${AAA_SOURCE_DIR}/Messages/proto/*.proto")
execute_process(COMMAND protoc -I=${AAA_SOURCE_DIR}/Messages/proto --cpp_out=${AAA_SOURCE_DIR}/Messages/cpp/ --python_out=${AAA_SOURCE_DIR}/Messages/py/ ${proto_packages})
MESSAGE("Protobuf autogeneration COMPLETED")
cmake_minimum_required(VERSION 2.8)
find_package(Boost)
find_package(Protobuf REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${PROTOBUF_INCLUDE_DIR})
add_subdirectory(Messages/proto)
add_subdirectory(Messages/cpp)
add_subdirectory(Server)
The Messages/proto/CMakeLists.txt file (which I'm not sure has any effect):
file(GLOB proto_packages "${AAA_SOURCE_DIR}/Messages/proto/*.proto")
execute_process(COMMAND protoc -I=${AAA_SOURCE_DIR}/Messages/proto --cpp_out=../cpp --python_out=../py ${proto_packages}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
Ideally, the protoc program should run as part of the build/make command, and only (re)generate the *.pb.{h|cc} and *_pb2.py files when a *.proto file changes.
Some files in the Server/ directory have #include <Messages/cpp/Xxxx.pb.h> directives.
For bonus points, I would prefer to have the *.pb.{h|cc} and *_pb2.py files be generated into their respective directories (Messages/cpp/ and Messages/py/ respectively). However, if someone is able to help with the dependency part of the problem, I am happy to have the *.pb.{h|cc} and *_pb2.py files co-exist with the *.proto files.
Thanks in advance for any suggestions !
This is untested, but you need to add a custom command a custom target.
You'd need to create some variables for the output line, but without knowing how to turn *.proto into the *.pb.{h|cc} and *_pb2.py files I can't help there. See the proto_packages_cpp and proto_packages_python variables for where those should go.
file(GLOB proto_packages "${AAA_SOURCE_DIR}/Messages/proto/*.proto")
add_custom_command(
COMMAND protoc -I=${AAA_SOURCE_DIR}/Messages/proto --cpp_out=../cpp --python_out=../py ${proto_packages}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${proto_packages}
OUTPUT ${proto_packages_cpp} ${proto_packages_python}
)
add_custom_target(protobuf_autogeneration_target ALL
DEPENDS ${proto_packages}
)