I have some trouble when I use PRE_BUILD | PRE_LINK | POST_BUILD in command add_custom_command(...). When I use POST_BUILD, I found the command will execute before the target has been built, like this:
[root#VM_33_35_centos build]# make
Scanning dependencies of target main
[100%] Building C object CMakeFiles/main.dir/main.c.o
Linking C executable main
This is pre build
This is post build
[100%] Built target main
The contents of my CMakeLists.txt are:
cmake_minimum_required(VERSION 2.8)
add_executable(main main.c)
add_custom_command(TARGET main
PRE_BUILD
COMMAND echo "This is pre build "
)
add_custom_command(TARGET main
POST_BUILD
COMMAND echo "This is post build"
)
Why did the command echo "This is post build" on line 8 of CMakeLists.txt not execute after the [100%] Built target main message on line 7(Linux command)?
Command added with add_custom_command(TARGET) signature becomes part of the target, that is target can be assumed to be built (Built target main) only after given command is executed.
Description of POST_BUILD keyword
run after the target has been built
means that command is executed after target file (in your case executable main) is created. This file is created as part of linking process, started after line Linking C executable main.
Related
this is a simplified version of my cmake
cmake_minimum_required(VERSION 2.8.4)
project(math)
add_library(math math.cpp)
function(install_package)
install(TARGETS math
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
add_custom_command(TARGET math
POST_BUILD
COMMAND cmake ARGS -P cmake_install.cmake)
endfunction()
install_package()
But when I build Debug version I get the following error
CMake Error at cmake_install.cmake:55 (file):
file INSTALL cannot find
"<my project's root>/build/Release/math.lib".
Why is it looking in Release folder despite that I build for Debug?
When I build for Release then, obviously, everything works.
I tried to add CONFIGURATIONS option to install method, but it doesn't help.
I'm using Visual Studio 15.
If I look into my cmake_install.cmake, Release is the default if you don't specify anything in your add_custom_command() call:
# Set the install configuration name.
if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)
if(BUILD_TYPE)
string(REGEX REPLACE "^[^A-Za-z0-9_]+" ""
CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}")
else()
set(CMAKE_INSTALL_CONFIG_NAME "Release")
endif()
message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"")
endif()
So if you look into INSTALL.vcxproj the call that CMake is generating looks like:
"C:\Program Files\CMake\bin\cmake.exe" -DBUILD_TYPE=$(Configuration) -P cmake_install.cmake
Which would translate into:
add_custom_command(TARGET math
POST_BUILD
COMMAND ${CMAKE_COMMAND} ARGS -D BUILD_TYPE=$<CONFIG> -P cmake_install.cmake)
New to CMake, and I'm having a hard time understanding how to use generator expressions. I'm trying to use add_custom_command to create a post-build command to copy Qt DLLs to the executable directory.
In Qt5WidgetsConfig.cmake I can see it creates different properties for the Qt5::Widgets target to refer to the DLL, depending on the currently active configuration. Either IMPORTED_LOCATION_DEBUG or IMPORTED_LOCATION_RELEASE. I expected to be able to use the $<CONFIG:Debug> generator expression as a condition in an if() but that doesn't work.
My CMakeLists.txt:
# minimum version required for proper support of C++11 features in Qt
cmake_minimum_required(VERSION 3.1.0)
set(CMAKE_CONFIGURATION_TYPES Debug;Release)
# project name and version
project(TPBMon VERSION 0.0.0.1)
# Qt5 libs
find_package(Qt5Widgets REQUIRED)
# run Qt's MOC when needed
set(CMAKE_AUTOMOC ON)
add_executable(
tpbmon
src/main.cpp
src/mainwindow.hpp
src/mainwindow.cpp
)
target_link_libraries(tpbmon Qt5::Widgets)
set_target_properties(
tpbmon
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin
)
if(WIN32)
if($<CONFIG:Debug>)
get_target_property(WIDGETDLL Qt5::Widgets IMPORTED_LOCATION_DEBUG)
else($<CONFIG:Debug>)
get_target_property(WIDGETDLL Qt5::Widgets IMPORTED_LOCATION_RELEASE)
endif($<CONFIG:Debug>)
add_custom_command(
TARGET tpbmon POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${WIDGETDLL} $<TARGET_FILE_DIR:tpbmon>
)
endif(WIN32)
Figured it out myself by modifying the add_custom_command call to
add_custom_command(
TARGET tpbmon POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:Qt5::Widgets>
$<TARGET_FILE_DIR:tpbmon>
)
It's amazing what a fresh perspective after a good night's sleep can do. ;)
You can use windeployqt program which is part of Qt binary release. It will scan your binary and collect all used Qt DLLs, plugins and QML modules. It could be wrapped in CMake as a post-build event by add_custom_command(TARGET target_name POST_BUILD ...) signature.
For the future you can add all Qt5 dependencies to your executable folder:
find_package(Qt5 COMPONENTS Core Gui Widgets)
...
add_custom_command(TARGET MyQtProj POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Core> $<TARGET_FILE_DIR:MyQtProj>
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Gui> $<TARGET_FILE_DIR:MyQtProj>
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Widgets> $<TARGET_FILE_DIR:MyQtProj>
)
I'm writing makefile, that works with cmake. makefile just creates the build directory and start cmake in it, if build directory is not created yet, or redirects targets to makefile created by cmake, if it already exists. I used mkdir -p to create a build directory, but it is not cross platform.
Is there any cross platform variant for mkdir -p? May be cmake provides alternative command, like it does autoconf?
You can use cmake -E make_directory (see documentation). If the parent directories are not existing, it does create all directories up the given one.
If you use it inside a CMake script itself, e.g. as pre-build step: ${CMAKE_COMMAND} -E make_directory
References
Creating a directory in CMake
cmake: make_directory in built time
I have an existing project (wvdial) that has a working makefile. I'm trying to integrate it into our main build process which uses CMake. Can anyone advise on how to do this? I made an attempt below based on some of the other projects we build but the makefile is never called. All I want to do is call the makefile for wvdial and include the binary in the .deb package we build.
cmake_minimum_required(VERSION 2.6)
SET(COMPONENT_NAME roots-vendor-wvdial)
SET(DEBIAN_PACKAGE_VERSION 1.6.1)
SET(WVDIAL_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
SET(WVDIAL_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
SET(WVDIAL_INSTALLED ${CMAKE_CURRENT_BINARY_DIR})
ADD_CUSTOM_TARGET(
wvdial ALL
DEPENDS ${WVDIAL_INSTALLED}
)
IF (${ROOTS_TARGET_ARCHITECTURE} STREQUAL "armhf")
SET(TARGET_FLAG "--host=arm-linux-gnueabihf")
ENDIF()
ADD_CUSTOM_COMMAND(
WORKING_DIRECTORY ${WVDIAL_BINARY_DIR}
OUTPUT ${WVDIAL_INSTALLED}
COMMAND env CXXFLAGS=${ROOTS_COMPILER_FLAGS} ./configure ${TARGET_FLAG} ${ROOTS_HOST_OPTION}
COMMAND make
COMMENT "Building wvdial"
VERBATIM
)
INSTALL(
FILES ${CMAKE_CURRENT_BINARY_DIR}/wvdial
DESTINATION usr/local/bin
COMPONENT ${COMPONENT_NAME}
PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ
)
DEFINE_DEBIAN_PACKAGE(
NAME ${COMPONENT_NAME}
CONTROL_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/debian/control
CHANGELOG_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/debian/changelog
)
Take a look at the ExternalProject module.
This will add a dummy target to your CMake project that is responsible for building the dependency. The command is quite complex and supports a lot of stuff that you probably won't need in your case. Kitware (the company behind CMake) did a nice post called Building External Projects with CMake 2.8 a while back explaining the basic use of that command.
Good day!
Let us have a source file main.cpp and a CMakeLists.txt file containing the next text:
cmake_minimum_required(VERSION 2.6)
project(tmp)
set(CMAKE_CXX_FLAGS "-Wall")
add_executable(tmp.elf main.cpp)
Let's say the main.cpp file contains a simple "Hello, World!" program:
#include <stdio.h>
int main()
{
printf("Hello, World!\n");
return 0;
}
We can build the project with cmake CMakeLists.txt && make. Then we'll just get the tmp.elf file which we can just run. Or we can get no tmp.elf file and assume that something is wrong with the main.cpp source file (assuming the compiler and cmake are installed properly on the building system).
So, the question is: how can we do the same on the Windows machine? E.g. we will get the tmp.vcproj file after running cmake CMakeLists.txt and then we need to build it somehow. How the build process can be performed using command-line? (Java's Process.start(), actually :-P )
You can start the build in a platform and CMake generator independent fashion by invoking cmake with the --build option:
cmake --build .
For multi-configuration generators, you can specify the configuration in the following way:
cmake --build . --config Release
Also see the documentation.