CMAKE COMPILE_DEFINITION not working - cmake

I am trying CMAKE and I have a problem with COMPILE_DEFINITION, I want to have custom debug target which defines a GIABUILD flag. The CMakeLists.txt is the following
# top level CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.8)
FIND_PACKAGE(deal.II 8.0 REQUIRED
HINTS
${DEAL_II_DIR} $ENV{DEAL_II_DIR} )
DEAL_II_INITIALIZE_CACHED_VARIABLES()
PROJECT(GIA)
SET(CLEAN_UP_FILES
*gmv *gnuplot *gpl *eps *pov *vtk *vtu *ucd *.d2 *dat *.log *.m *.1
)
INCLUDE_DIRECTORIES(include)
FILE(GLOB headers ./include/*.h)
FILE(GLOB sources ./source/*.cc)
ADD_EXECUTABLE(elastic ${sources} ${headers})
ADD_CUSTOM_TARGET(clear
COMMAND rm ${CLEAN_UP_FILES}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
ADD_CUSTOM_TARGET(debug
COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target all
COMMENT "Switch CMAKE_BUILD_TYPE to Debug"
)
#add_definitions(-DGIABUILD)
SET_TARGET_PROPERTIES(debug PROPERTIES COMPILE_DEFINITIONS "GIABUILD")
ADD_CUSTOM_TARGET(release
COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target all
COMMENT "Switch CMAKE_BUILD_TYPE to Release"
)
set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /opt/local/lib)
TARGET_LINK_LIBRARIES(elastic /opt/local/lib/libboost_program_options-mt.a)
DEAL_II_SETUP_TARGET(elastic)
The problem is that SET_TARGET_PROPERTIES doesn't work here. add_definitions work but it defines the symbol for all targets which is not what I want.
Thank you.

The problem is that SET_TARGET_PROPERTIES doesn't work here
Because target is custom (created by add_custom_target command) it's no more CMake
responsibility to check/use target properties.
You need to add definitions to non custom target (elastic I guess):
target_compile_definitions(
elastic PUBLIC "$<$<CONFIG:Debug>:GIABUILD>"
)

A couple of solutions that should work. My initial thought is to add the definition directly to your CXX_FLAGS:
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DGIABUILD")
You can try adding the flag directly to your target:
ADD_CUSTOM_TARGET(debug
COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR} -DCMAKE_CXX_FLAGS_DEBUG="-DGIABUILD"
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target all
COMMENT "Switch CMAKE_BUILD_TYPE to Debug"
)

Related

What is the function of add_custom_target in CMake?

From the CMake Cookbook, I see that we can use the command add_custom_command and add_custom_target to run a custom command at build time. There is a toy example that I want to extract compressed files in subdirectory and link it to the final executable files. We have two CMakeLists.txt files and the following one is in the subdirectory.
find_package(BLAS REQUIRED)
find_package(LAPACK REQUIRED)
set(MATH_SRCS
${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK/CxxBLAS.cpp
${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK/CxxLAPACK.cpp
${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK/CxxBLAS.hpp
${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK/CxxLAPACK.hpp
)
add_custom_target(BLAS_LAPACK_wrappers
WORKING_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
${MATH_SRCS}
COMMENT
"Intermediate BLAS_LAPACK_wrappers target"
VERBATIM
)
add_custom_command(
OUTPUT
${MATH_SRCS}
COMMAND
${CMAKE_COMMAND} -E tar xzf ${CMAKE_CURRENT_SOURCE_DIR}/wrap_BLAS_LAPACK.tar.gz
WORKING_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/wrap_BLAS_LAPACK.tar.gz
COMMENT
"Unpacking C++ wrappers for BLAS/LAPACK"
)
add_library(math "")
target_sources(math
PRIVATE
${MATH_SRCS}
)
target_include_directories(math
INTERFACE
${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK
)
# BLAS_LIBRARIES are included in LAPACK_LIBRARIES
target_link_libraries(math
PUBLIC
${LAPACK_LIBRARIES}
)
The following CMakeLists.txt is in the main directory.
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
# Fortran needed to discover LAPACK with some compilers
project(recipe-04 LANGUAGES CXX Fortran)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(deps)
add_executable(linear-algebra linear-algebra.cpp)
target_link_libraries(linear-algebra
PRIVATE
math
)
I do not know why we need the add_custom_target in this example.
The command add_custom_command cannot be executed without generating any target. That is why we need the custom target to run this command. What's more, it can only execute at the configure time. If we want to run the command after we configure the CMakeLists.txt file, we can create a custom target to achieve that as the following.
add_custom_target(BLAS_LAPACK_wrappers
WORKING_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
${MATH_SRCS}
COMMENT
"Intermediate BLAS_LAPACK_wrappers target"
VERBATIM
)
add_custom_command(
OUTPUT
${MATH_SRCS}
COMMAND
${CMAKE_COMMAND} -E tar xzf ${CMAKE_CURRENT_SOURCE_DIR}/wrap_BLAS_LAPACK.tar.gz
WORKING_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/wrap_BLAS_LAPACK.tar.gz
COMMENT
"Unpacking C++ wrappers for BLAS/LAPACK"
)
After we configure the CMakeLists.txt file, we use the Cmake --build . --target=BLAS_LAPACK_wrappers the execute it at the build time.

selectively run doxygen in cmake

I've got a CMakeLists.txt file that handles Doxygen generation for a software project. Its contents are:
find_package(Doxygen)
if (DOXYGEN_FOUND)
set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
configure_file(${doxyfile_in} ${doxyfile} #ONLY)
add_custom_target(doc ALL
${DOXYGEN_EXECUTABLE} ${doxyfile}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen" VERBATIM)
endif()
I'd really like to only run doxygen if I'm doing an install build. Is there some straightforward way of communicating that to cmake?
First remove the ALL from add_custom_target().
add_custom_target(doc ALL
by
add_custom_target(doc
Then add
install(CODE
"EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target doc)")
src: https://cmake.org/cmake/help/latest/command/install.html#code
Examples
CMakeList.txt:
cmake_minimum_required (VERSION 3.5)
project(meta VERSION 1.0.0 LANGUAGES NONE)
# ....
enable_language(CXX)
add_executable(app main.cpp)
include(GNUInstallDirs)
set(CMAKE_INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/foo)
install(TARGETS app
EXPORT FooTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(EXPORT FooTargets
NAMESPACE foo::
DESTINATION ${CMAKE_INSTALL_CONFIGDIR}
)
# replace by your own code
add_custom_target(doxygen
COMMAND echo Hello Doxygen
VERBATIM
)
install(CODE
"EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target doxygen)")
main.cpp
int main() {
return 0;
}
Shell:
$ cmake -H. -Bbuild
...
$ cmake --build build --target install -- DESTDIR=install
Scanning dependencies of target app
[ 50%] Building CXX object CMakeFiles/app.dir/main.cpp.o
[100%] Linking CXX executable app
[100%] Built target app
Install the project...
-- Install configuration: ""
-- Installing: install/usr/local/bin/app
-- Installing: install/usr/local/lib/cmake/foo/FooTargets.cmake
-- Installing: install/usr/local/lib/cmake/foo/FooTargets-noconfig.cmake
Scanning dependencies of target doxygen
Hello Doxygen
Built target doxygen
I've come up with an approach that divides the work between add_custom_command() and add_custom_target():
find_package(Doxygen)
if (DOXYGEN_FOUND)
set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
configure_file(${doxyfile_in} ${doxyfile} #ONLY)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/doxygen.stamp
DEPENDS ${doxyfile}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}
COMMAND cmake -E touch ${CMAKE_CURRENT_BINARY_DIR}/doxygen.stamp
COMMENT "Generating API documentation with Doxygen"
VERBATIM)
add_custom_target(doc ALL
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/doxygen.stamp)
endif()
It's not exactly what I originally was asking for, but it's good enough for my purposes. I'm not going to accept this answer just yet, in case someone chimes in with an answer that does more exactly address my initial request.

How to reload cmake targets

Following is the my scenario. I have one top level CMakeList.txt and another 2 internal CMakeList.txt. In top level cmake I have 3 custom targets that are copy, build, copyandbuild. As name specifies make copy copies the source directories (i.e dir1, dir2) to ${CMAKE_SOURCE_DIR}. make build creates libs and executables. make copyandbuild (copy+build).
Running cmake .. from build directory completes successfully.
If I run make copyandbuild it is copying to ${CMAKE_SOURCE_DIR} but at the time of build it is showing error that
No rule to make target `dir1/libmylib.so', needed by `CMaketargetdbuild'. Stop
MyProject
dir1
CMakeLists.txt
dir2
CMakeLists.txt
CMakeLists.txt
It is working if i execute commands in below order.
cmake ..
make copyandbuild
cmake ..
make build
My requirement is it should work with out running cmake and make build again as copyandbuild doing the same work.
Top level CMakeLists.txt:
cmake_minimum_required(VERSION 2.6)
cmake_minimum_required(VERSION 2.6)
set(RE_BUILD make rebuild_cache)
set(OUTPUT_DIR ${CMAKE_SOURCE_DIR}/../)
if(EXISTS ${CMAKE_SOURCE_DIR}/dir1)
message(WARNING "Found dir1 dir")
add_subdirectory(dir1 EXCLUDE_FROM_ALL)
else()
message(WARNING "Couldn't find dir1 directory ")
endif()
if(EXISTS ${CMAKE_SOURCE_DIR}/dir2)
add_subdirectory(dir2 EXCLUDE_FROM_ALL)
else()
message(WARNING "Couldn't find dir2 directory")
endif()
set(MOVE_LIB_COMMAND mv src/myapp . && mv dir1/mylib .)
set(COPY_COMMAND cp -r ../sourceCode1 ../dir1 && cp -r ../sourceCode2 ../dir2)
set(CLEAN_DIR1_COMMAND cmake -E remove_directory ${CMAKE_SOURCE_DIR}/dir1)
set(CLEAN_DIR2_COMMAND cmake -E remove_directory ${CMAKE_SOURCE_DIR}/dir2)
set(SET_SLEEP sync)
#Copy command
add_custom_target(
copy ${COPY_COMMAND}
COMMAND ${RE_BUILD}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
#Compilation
add_custom_target(
build
COMMAND ${MOVE_LIB_COMMAND}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS mylib myapp
)
#copy and compile
add_custom_target(
copyandbuild
COMMAND ${MOVE_LIB_COMMAND}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS copy mylib myapp
)
add_custom_command(TARGET copy POST_BUILD
COMMAND ${SET_SLEEP}
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")
dir1 CMake is :
cmake_minimum_required(VERSION 2.6)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")
include_directories(
${MY_APP_INCLUDE_DIRS}
)
link_directories(
${MY_APP_LIBDIR}
)
add_library(mylib
SHARED
com/*.cpp
)
target_link_libraries(mylib myapp_lib)
dir2 CMake is :
cmake_minimum_required(VERSION 2.6)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")
include_directories(
${MY_APP_INCLUDE_DIRS}
)
link_directories(
${MY_APP_LIBDIR}
)
You are using CMake in a way that prevents its proper function. By explicitly invoking shell commands in many places, when you could use CMake built in features, you are robbing CMake of any context that it could use to build your programs. Also, using wildcards like *.cpp in CMake is considered bad practice. And you have a number of duplicate statements--you do not need cmake_minimum_required() or setting compiler flags other than at the top level.
In short, your CMakeLists.txt at the top level should look more like this:
cmake_minimum_required(VERSION 2.6)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")
add_subdirectory(dir1 EXCLUDE_FROM_ALL)
You should not need to copy source files around--just build them from where they are, for example your dir1/CMakeLists.txt might be:
add_library(mylib
SHARED
sourceCode1/mylib.cpp
)
Keep it simple. Get it working. Then ask questions if you need to add missing features.

Execute a CMake function on every build-time

I have two cmake function to check resources/shader files are not found/ modified matching to build.
Check.cmake
function(Check sourcefile destinationfile)
if(NOT EXISTS ${destinationfile})
execute_process(COMMAND ${CMAKE_COMMAND}
-E copy ${sourcefile} ${destinationfile})
elseif(${sourcefile} IS_NEWER_THAN ${destinationfile})
execute_process(COMMAND ${MSGMERGE_EXECUTABLE}
"--update" ${destinationfile} ${sourcefile}
OUTPUT_QUIET ERROR_VARIABLE error RESULT_VARIABLE ret)
if(ret) # Have to do this hack as msgmerge prints to stderr.
message(SEND_ERROR "${error}")
endif()
endif()
endfunction()
AddResources.cmake
include(./Check.cmake)
function(AddResources project)
file(GLOB_RECURSE resources ${PROJECT_SOURCE_DIR}/src/project1/Resources/*)
file(GLOB_RECURSE shaders ${PROJECT_SOURCE_DIR}/src/project1/Shaders/*)
foreach( each_file1 ${resources} )
get_filename_component(targetFile ${each_file1} NAME)
if(WIN32)
set(destinationfile "${CMAKE_CURRENT_SOURCE_DIR}/bin/Release/${targetFile}")
set(destinationfile2 "${CMAKE_CURRENT_SOURCE_DIR}/bin/Debug/${targetFile}")
set(sourcefile ${each_file1})
Check(${sourcefile} ${destinationfile})
Check(${sourcefile} ${destinationfile2})
else ()
set(destinationfile "${CMAKE_CURRENT_SOURCE_DIR}/bin/${targetFile}")
set(sourcefile ${each_file1})
Check(${sourcefile} ${destinationfile})
endif()
endforeach(each_file1)
foreach( each_file2 ${shaders} )
get_filename_component(targetFile ${each_file2} NAME)
if(WIN32)
set(destinationfile "${CMAKE_CURRENT_SOURCE_DIR}/bin/Release/${targetFile}")
set(destinationfile2 "${CMAKE_CURRENT_SOURCE_DIR}/bin/Debug/${targetFile}")
set(sourcefile ${each_file2})
Check(${sourcefile} ${destinationfile})
Check(${sourcefile} ${destinationfile2})
else()
set(destinationfile "${CMAKE_CURRENT_SOURCE_DIR}/bin/${targetFile}")
set(sourcefile ${each_file2})
Check(${sourcefile} ${destinationfile})
endif()
endforeach(each_file2)
endfunction()
It is executed AddResources(project1) in the CMakeLists.txt.
AddResources will copy all of resources and shaders to bin folder, but it copies only once(CMake configuration process), not every build-time.
Is there any way to execute CMake function every build-time with argument?
I think you're looking for add_custom_command
add_custom_command(TARGET target
PRE_BUILD | PRE_LINK | POST_BUILD
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[WORKING_DIRECTORY dir]
[COMMENT comment] [VERBATIM])
This defines a new command that will be associated with building the specified target. When the command will happen is determined by which of the following is specified:
PRE_BUILD - run before all other dependencies
PRE_LINK - run after other dependencies
POST_BUILD - run after the target has been built

cmake add_custom_command and DEPENDS/TARGET

I have this in my toplevel CMakeLists.txt:
add_subdirectory (src) # add_executable (${PROJECT_NAME} ${_SOURCES})
add_subdirectory (data)
In data subdirectory I want to create a file, when ${PROJECT_NAME} is build. The following doesn't work, returns target "foo" does not exist:
add_custom_command(
OUTPUT "${PROJECT_BINARY_DIR}/${PROJECT_NAME}.desktop"
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
COMMAND ${INTLTOOLMERGE} -d -u ../po ${PROJECT_NAME}.desktop.in "${PROJECT_NAME}.desktop"
COMMENT "Creating desktop file"
DEPENDS ${PROJECT_NAME}
)
This also doesn't work. Returns: The target name "foo" is unknown in this context
add_custom_command(
TARGET ${PROJECT_NAME}
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
COMMAND ${INTLTOOLMERGE} -d -u ../po ${PROJECT_NAME}.desktop.in "${PROJECT_NAME}.desktop"
COMMENT "Creating desktop file"
)
But this works as expected:
add_custom_command(
OUTPUT "${PROJECT_BINARY_DIR}/${PROJECT_NAME}.desktop"
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
COMMAND ${INTLTOOLMERGE} -d -u ../po ${PROJECT_NAME}.desktop.in "${PROJECT_NAME}.desktop"
COMMENT "Creating desktop file"
)
add_custom_target (desktopfile DEPENDS "${PROJECT_BINARY_DIR}/${PROJECT_NAME}.desktop")
add_dependencies (${PROJECT_NAME} desktopfile)
Question:
1.- How can I use add_custom_command to run the command when "foo" is build without using a target?
2.- How come add_dependencies knows about "foo" but pure add_custom_command doesn't?
update #1: Simple code:
# /CMakeLists.txt
cmake_minimum_required (VERSION 3.0)
project ("foo")
add_subdirectory (src)
add_subdirectory (data)
# : EOF~
# src/CMakeLists.txt
add_executable (${PROJECT_NAME} main.c)
# : EOF:~
# data/CMakeLists.txt
add_custom_command (
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E sleep 5
COMMENT "We're going to try to pause here for 5 seconds"
)
# EOF:~
# src/main.c
#include <stdio.h>
int main () {
printf ("Hello world");
return 0;
}
Please use POST_BUILD option.
From the cmake documentation:
add_custom_command(TARGET target
PRE_BUILD | PRE_LINK | POST_BUILD
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[WORKING_DIRECTORY dir]
[COMMENT comment] [VERBATIM])
This defines a new command that will be associated with building the specified target. When the command will happen is determined by which of the following is specified:
PRE_BUILD - run before all other dependencies
PRE_LINK - run after other dependencies
POST_BUILD - run after the target has been built
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.