Add custom build step in CMake - c++

I'm trying to add a custom build step in CMake that generates some files. I haven't found a description how it works.
I have an project where source, header & implementation files have to be generated by ODB for C++. ODB takes class headers as arguments and generates source files that I want to use in my project.
Right now I have the following command in my CMakeLists.txt:
add_custom_command(TARGET ${PROJECT_NAME}
PRE_BUILD
COMMAND odb -o /home/david/dev/ --std c++11 -I/home/david/dev/ -d sqlite --generate- query --generate-schema ${PROMOTER_LIB_PREFIX}/entities/person.hpp
DEPENDS ${PROJECT_NAME}
VERBATIM
)
For a file person.hpp ODB should generate person-odb.hxx, person-odb.cxx, person-odb.ixx but the CMake command I''ve used doesn't generate anything. In a terminal this command works fine.
What am I doing wrong?
EDIT: The problem can be solved by adding the following lines:
set(FAKE_TARGET fakeTarget)
add_custom_target(fakeTarget
odb -o /home/david/dev/ --std c++11 -I/home/david/dev/ -d sqlite --generate-query --generate-schema ${PROMOTER_LIB_PREFIX}/entities/person.hpp
)
add_dependencies(${PROJECT_NAME} ${FAKE_TARGET})

For me, with something similar, I just use :
add_custom_command(TARGET ${PROJECT_NAME}
PRE_BUILD
COMMAND odb -o /home/david/dev/ --std c++11 -I/home/david/dev/ -d sqlite --generate- query --generate-schema ${PROMOTER_LIB_PREFIX}/entities/person.hpp
)
We don't use DEPENDS or VERBATIM.
The DEPENDS option specify that the command must be executed only after that the project you gave to this option is built.
EDIT :
Note that the PRE_BUILD option is only supported on Visual Studio 7 or later. For all other generators PRE_BUILD will be treated as PRE_LINK.
Maybe that's why it doesn't work for you.
A work around could be (a bit ugly) :
Create a fake project
Add your custom command on it as POST_BUILD
Make you current project dependent on the fake one

Way I'm using it is:
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/gen_icinstrtab.hpp
COMMAND xsltproc --output ${CMAKE_CURRENT_BINARY_DIR}/gen_icinstrtab.hpp ${CMAKE_SOURCE_DIR}/xml/genictabc.xslt ${CMAKE_SOURCE_DIR}/xml/icminstr.xml
)
add_executable(
du4
${CMAKE_CURRENT_BINARY_DIR}/gen_icinstrtab.hpp
.
.
.
)
The key was to add even .hpp files into add_executable block.

Related

Cmake: How to have add_custom_command() run after all project files are built

Using Cmake v3.8, I need my custom command to run only after my newly built .hex, .map, and .elf files are produced. However, the command is not truly running after all of the *.hex, *.map, and *.elf files are produced. Here is what I have:
add_custom_command(
POST_BUILD
COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/performCrc32.py
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT performCrc32.out
COMMENT "Running CRC32 check..."
)
add_custom_target(
performCrc32 ALL
DEPENDS performCrc32.py
performCrc32.out
)
What am I missing, if anything?
There is no way for add commands to be executed "after the build is entirely complete".
You may add commands to be executed after specific target is built:
add_custom_command(TARGET <kernel-target> POST_BUILD
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/performCrc32.py
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Running CRC32 check..."
)
This would add command to be executed after <kernel-target> and all its dependencies will be built. Note on the absence of OUTPUT option in this case.
This is preferrable way for post-build checks, as a check will be performed every time target is actually (re)built.
You may bind your custom command to your custom target (as usual), and add dependencies for the target:
add_custom_command(
COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/performCrc32.py
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT performCrc32.out
COMMENT "Running CRC32 check..."
)
add_custom_target(
performCrc32 ALL
DEPENDS performCrc32.py
performCrc32.out
)
add_dependencies(performCrc32 <hex-targets...> <map-targets> <elf-target>)
In this case command will be executed after all dependent targets are built. However, the command will be executed only first build: once OUTPUT file will be created, the command won't be executed again.
POST_BUILD option for add_custom_command is applicable only for TARGET flow of this command, as described above. I am curious why CMake doesn't emit error for your case, when you use POST_BUILD without TARGET.

CMake: Embed ELF into executable

I have a project that needs access to an ELF file embedded into the executable in a special section.
I was handcrafting Makefiles before and simply had a shell script where I used objcopy to copy the target I wanted to embed into an .o file, then link to this file in the executable.
# Create a new section and copy the binary there ($1=input $2=output name)
objcopy --input-target binary --output-target elf64-x86-64 \
--binary-architecture i386 $1 $2.o
Now I want to get rid of the custom Makefiles and use CMake to generate them. However, I don't see an easy way to link to such a file. I am able to create and add this file, but not to link against it:
# Invoke script to package module as a library
add_custom_command(OUTPUT ${PACKAGED_FILE}
COMMAND ./package.sh ${MODULE_FILE} ${PACKAGED_FILE}
WORKING_DIRECTORY ${MODULE_DIR}
DEPENDS ${MODULE_FILE}
COMMENT packaging file into ELF object
VERBATIM
)
add_custom_target(${PACKAGED_NAME} ALL DEPENDS ${PACKAGED_FILE})
I have tried to add it with:
target_link_libraries(binary ${PROJECT_BINARY_DIR}/${PACKAGED_FILE})
However, this fails because the file isn't there yet. It will be, but CMake doesn't know that. Adding the target name as a link library doesn't help either because it can't be found. Adding it as a also dependency doesn't help. Does anyone have an idea how this could be accomplished?
We are doing a similar thing in our project - the following part of our CMakeLists.txt does the trick:
set(PROJECT_EMBED_OBJ_FILES "")
set(PROJECT_EMBED_FILES "file1.elf" "file2.elf")
foreach(FILENAME ${PROJECT_EMBED_FILES})
get_filename_component(FILENAME_ONLY ${FILENAME} NAME)
get_filename_component(FILEPATH_ONLY ${FILENAME} PATH)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${FILENAME_ONLY}.o
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/${FILEPATH_ONLY}
COMMAND ${CMAKE_OBJCOPY}
ARGS -I binary -O elf64-x86-64 -B i386 ${FILENAME_ONLY} ${CMAKE_CURRENT_BINARY_DIR}/${FILENAME_ONLY}.o )
list(APPEND PROJECT_EMBED_OBJ_FILES ${CMAKE_CURRENT_BINARY_DIR}/${FILENAME_ONLY}.o)
message(STATUS "Objcopy'ing ${FILENAME}")
endforeach(FILENAME)
And then in the call to add_executable:
add_executable(projectname ${PROJECT_SOURCES} ${PROJECT_EMBED_OBJ_FILES})
You may try
add_custom_command(TARGET $(PROJECT_NAME).elf
POST_BUILD
COMMAND ${CMAKE_OBJCOPY} ARGS -O binary ${PROJECT_NAME}.elf \
${PROJECT_NAME}.bin)
Put this after your add_executable().
The POST_BUILD means execute after build.

CMake and Flex/Bison

I am converting my build system from configure/make to a cmake system
The system has some autogenerated files, from bison/flex. The original makefile commands are:
bison --defines=tokens.h --output=parser.cpp parser.y
flex --outfile=scanner.cpp scanner.l
I came across this ancient link which seems to explain how to do it, but when i run cmake with the following custom commands, nothing appears to happen (no error messages, no file generation)
FIND_PACKAGE(BISON REQUIRED)
IF(BISON_FOUND)
ADD_CUSTOM_COMMAND(
SOURCE ${CMAKE_SOURCE_DIR}/src/rcdgen/parser.y
COMMAND ${BISON_EXECUTABLE}
ARGS --defines=${CMAKE_SOURCE_DIR}/src/rcdgen/tokens.h
-o ${CMAKE_SOURCE_DIR}/src/rcdgen/parser.cpp
${CMAKE_SOURCE_DIR}/src/rcdgen/parser.y
COMMENT "Generating parser.cpp"
OUTPUT ${CMAKE_SOURCE_DIR}/src/rcdgen/parser.cpp
)
ENDIF(BISON_FOUND)
FIND_PACKAGE(FLEX REQUIRED)
IF(FLEX_FOUND)
ADD_CUSTOM_COMMAND(
SOURCE ${CMAKE_SOURCE_DIR}/src/rcdgen/scanner.l
COMMAND ${FLEX_EXECUTABLE}
ARGS -o${CMAKE_SOURCE_DIR}/src/rcdgen/parser.cpp
${CMAKE_SOURCE_DIR}/src/rcdgen/scanner.l
COMMENT "Generating scanner.cpp"
OUTPUT ${CMAKE_SOURCE_DIR}/src/rcdgen/scanner.cpp
)
ENDIF(FLEX_FOUND)
I am new to cmake, so it's a bit confusing to me. Does anyone have any idea what a working custom_command would be?
The new hotness for bison usage is actually documented in FindBison So for a simple parser project:
find_package(BISON)
BISON_TARGET(MyParser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp
DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/parser.h)
add_executable(Foo main.cpp ${BISON_MyParser_OUTPUTS})
is what you'd do. Likewise for Flex.
The format of your add_custom_commands is not quite right, but they appear to be almost correct. There are two versions of add_custom_command, and the one you want is the one which produces an output file (the parts inside square brackets are optional):
add_custom_command(OUTPUT output1 [output2 ...]
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[MAIN_DEPENDENCY depend]
[DEPENDS [depends...]]
[IMPLICIT_DEPENDS <lang1> depend1
[<lang2> depend2] ...]
[WORKING_DIRECTORY dir]
[COMMENT comment] [VERBATIM] [APPEND])
The idea is that the custom command only executes if the file specified as the OUTPUT of this command is used as an input elsewhere in the same CMakeLists.txt (e.g. in an add_library or add_executable call).
The custom command therefore will only run at build time (i.e. when you run make), not at configure time (when you run CMake), and only if you're building a target which directly or indirectly needs the OUTPUT file.
To fix your commands, I think the following should work (untested):
FIND_PACKAGE(BISON REQUIRED)
SET(BisonOutput ${CMAKE_SOURCE_DIR}/src/rcdgen/parser.cpp)
IF(BISON_FOUND)
ADD_CUSTOM_COMMAND(
OUTPUT ${BisonOutput}
COMMAND ${BISON_EXECUTABLE}
--defines=${CMAKE_SOURCE_DIR}/src/rcdgen/tokens.h
--output=${BisonOutput}
${CMAKE_SOURCE_DIR}/src/rcdgen/parser.y
COMMENT "Generating parser.cpp"
)
ENDIF()
FIND_PACKAGE(FLEX REQUIRED)
SET(FlexOutput ${CMAKE_SOURCE_DIR}/src/rcdgen/scanner.cpp)
IF(FLEX_FOUND)
ADD_CUSTOM_COMMAND(
OUTPUT ${FlexOutput}
COMMAND ${FLEX_EXECUTABLE}
--outfile=${FlexOutput}
${CMAKE_SOURCE_DIR}/src/rcdgen/scanner.l
COMMENT "Generating scanner.cpp"
)
ENDIF()
ADD_LIBRARY(MyLib ${BisonOutput} ${FlexOutput})

CMake add target for invoking clang analyzer

I'd basically like to achieve the same as http://blog.alexrp.com/2013/09/26/clangs-static-analyzer-and-automake, but with CMake.
analyze_srcs = foo.c
analyze_plists = $(analyze_srcs:%.c=%.plist)
CLEANFILES = $(analyze_plists)
$(analyze_plists): %.plist: %.c
#echo " CCSA " $#
#$(COMPILE) --analyze $< -o $#
analyze: $(analyze_plists)
.PHONY: analyze
So you can run
make analyze
make clean
I guess I need to use add_custom_command/add_custom_target and somehow change the "object file" extension just for that target.
Afterwards get a list of the generated files to perhaps pass them to a script for combining them into 1 output file.
Can anyone point me in the right direction?
You can use scan-build when running cmake.
scan-build cmake /path/to/source
scan-build make
scan-build sets the CC and CXX environment variables which are picked up by cmake.
I found a way:
function(add_clang_static_analysis target)
get_target_property(SRCs ${target} SOURCES)
add_library(${target}_analyze OBJECT EXCLUDE_FROM_ALL ${SRCs})
set_target_properties(${target}_analyze PROPERTIES
COMPILE_OPTIONS "--analyze"
EXCLUDE_FROM_DEFAULT_BUILD true)
endfunction()
Combining clang's plist files (which get extension .o this way) into a report is still open ($<TARGET_OBJECTS:objlibtarget>?).
The following solution has the drawback of compiling and analyzing the entire project, not the specific targets.
set(on_side_build_path ${CMAKE_BINARY_DIR}/clang_static_analysis)
set(scan_build_path scan-build)
set(reports_path ${CMAKE_BINARY_DIR}/clang_static_analysis_reports)
# Creates clean directory where the analysis will be built.
add_custom_target(clang_static_analysis_prepare
COMMAND ${CMAKE_COMMAND} -E rm -rf ${on_side_build_path}
COMMAND ${CMAKE_COMMAND} -E make_directory ${on_side_build_path}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
# Runs the analysis from the path created specifically for that task. Use 'my own' project source directory as the source directory.
add_custom_target(clang_static_analysis
# scan-build wants Debug build, for better analysis.
COMMAND ${scan_build_path} ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR} -DCMAKE_BUILD_TYPE=Debug
COMMAND ${scan_build_path}
-v -v -o ${reports_path}
${CMAKE_COMMAND} --build .
WORKING_DIRECTORY ${on_side_build_path}
)
# Run the *_prepare target always before the analysis
add_dependencies(clang_static_analysis clang_static_analysis_prepare)
Invoke it with:
cmake --build . --target clang_static_analysis
Bonus #1: Allowing custom toolchains to work
scan-build injects the CC and CXX environment variables to specify the replaced compilers, which are ccc-analyzer and c++-analyzer. When defining CMAKE_C_COMPILER and CMAKE_CXX_COMPILER the CC and CXX variables will be ignored. What you need to do to support scan-build is to point CMAKE_C*_COMPILER variables to use the one from environment, if defined. So having that in your toolchain file:
set(CMAKE_C_COMPILER some/path/to/c_compiler)
set(CMAKE_Cxx_COMPILER some/path/to/cxx_compiler)
Replace it with:
if(DEFINED ENV{CC})
set(CMAKE_C_COMPILER $ENV{CC})
else()
set(CMAKE_C_COMPILER some/path/to/c_compiler)
endif()
if(DEFINED ENV{CXX})
set(CMAKE_CXX_COMPILER $ENV{CXX})
else()
set(CMAKE_CXX_COMPILER some/path/to/cxx_compiler)
endif()
Bonus #2: Using scan-build from the LLVM toolchain
If your custom toolchain is LLVM, then most probably you want to use the scan-build command from the toolchain. To enable it, simply define the path to toolchain path using cmake's cache variables:
set(LLVM_TOOLCHAIN_PATH "some/path/here" CACHE PATH "Path to the LLVM toolchain")
or from the command line:
cmake -DLLVM_TOOLCHAIN_PATH=some/path/here ...
and then reuse the path from the custom target:
set(scan_build_path ${LLVM_TOOLCHAIN_PATH}/bin/scan-build)
Bonus #3: Adding test command
Note: enable_testing shall be called before add_test. enable_testing() must be called from the project's top level CMakeLists.txt for ctest to resolve paths to tests.
add_test(
NAME clang_static_analysis
COMMAND ${CMAKE_COMMAND} --build . --target clang_static_analysis
)
Run it like that:
# Fire configure and generate stages
cmake ../source/dir
ctest -R clang_static_analysis --verbose

CMake compile C++ file in custom command

I'm trying to precompile a header file in GCC with the following command:
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/all.hpp.gch
COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} -o ${CMAKE_BINARY_DIR}/all.hpp.gch ${CMAKE_CURRENT_SOURCE_DIR}/all.hpp
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/all.hpp
COMMENT "Generating precompiled headers"
)
However, I don't get CMAKE_CXX_FLAGS to expand into flags I've set using CMake's add_definitions(). What is the correct way of compiling in add_custom_command()?
I don't believe that add_definitions() adds its arguments to CMAKE_CXX_FLAGS. In fact, as far as I can tell they aren't saved anywhere (apart from arguments beginning with -D or /D which get added to COMPILE_DEFINITIONS).
The simplest way to solve that would be to, whenever calling add_definitions(), to also manually add those flags to CMAKE_CXX_FLAGS.
To see what is in CMAKE_CXX_FLAGS at any point, you can do
message(STATUS ${CMAKE_CXX_FLAGS})
or check the CMakeCache.txt in the build directory (or via ccmake or cmake-gui).