CMake custom target doesn't build - cmake

I'm building two targets using:
add_library(tgt1 SHARED a.cpp)
add_library(tgt2 SHARED b.cpp)
After both are built, I need to run a post build step that depends on both targets. I tried many combinations of the following but with no success:
add_custom_target(final_tgt DEPENDS tgt1 tgt2)
add_custom_command(TARGET final_tgt POST_BUILD COMMAND <command> ARGS <args>)
The final target would simply not build, even though its build.make contains the custom command.
Tried to use ALL for the custom target, however make attempts to build it first while missing the first targets.
And I can't use an add_library or add_executable for the final target, since they require specifying source files.
What is the correct way to do it?
===================================
Edit: below is a minimal verifiable source code.
What it attempts to do is to compile code (for Mac) in two architectures and as a post-build to create a universal binary using lipo:
cmake_minimum_required(VERSION 2.8)
set(icpc_req_path "/usr/local/bin/icpc-16.0.146")
set(CMAKE_CXX_COMPILER "${icpc_req_path}")
project("CMakeTest")
set(SOURCE_FILES a.cpp)
set (TARGET_NAME "TGT")
set(TARGETS "")
set(ARCHITECTURES i386 x86_64)
foreach(ar ${ARCHITECTURES})
set(CMAKE_CXX_FLAGS_RELEASE "")
set(CMAKE_CXX_FLAGS_DEBUG "")
set(CMAKE_CXX_FLAGS "")
add_library(TGT_${ar} SHARED ${SOURCE_FILES})
set_target_properties(${TARGET_NAME}_${ar}
PROPERTIES COMPILE_FLAGS "-arch ${ar} -xSSE3")
set_target_properties(${TARGET_NAME}_${ar}
PROPERTIES LINK_FLAGS "-arch ${ar}")
set(TARGETS "${TARGETS};lib${TARGET_NAME}_${ar}.dylib")
endforeach(ar)
message("Targets: ${TARGETS}")
add_custom_target(${TARGET_NAME} DEPENDS ${TARGETS})
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND "lipo"
ARGS "-create" ${TARGETS} "-output" "${TARGET_NAME}.dylib")
And the contents of a.cpp is:
int main(){}

add_custom_command comes in two flavors: Producing new output, and acting on single targets. Docs
What is the command that you are calling doing? Is it in any way producing results (new files, etc)? If so, use add_custom_command like this:
add_custom_command(
OUTPUT <output-file>
DEPENDS tgt1 tgt2
COMMAND <command>
ARGS <args>
COMMENT "Running <command> on targets tgt1 and tgt2."
)
Using the second variant of add_custom_command which does not have an OUTPUT argument, because it changes a <target> as POST_BUILD (or pre-build, pre-link) step, needs a single target. So, which one of tgt1 and tgt2 gets modified by your <command>?
Let's assume that tgt1 gets modified in the POST_BUILD step and tgt2 is untouched. Then you can do it like this:
add_library(tgt2 SHARED b.cpp)
add_library(tgt1 SHARED a.cpp)
add_custom_command(
TARGET tgt1 POST_BUILD
COMMAND <command>
ARGS <args>
)
add_dependencies(tgt1 tgt2) # tgt1 depends on tgt2 because
# POST_BUILD-step is just the final step to build 'tgt1'
# NOTE: It is incorrect to modify 'tgt2' as POST_BUILD step for tgt1.
# So this example expects no changes to tgt2 in add_custom_command.
--
EDIT after more details given in question:
Working example
CMakeLists.txt
# I don't have 'icpc' and could not find it easily available for macOS.
# Instead, let's create a file "TGT" where contents are the two hashes of the two
# libraries, like done in 'Th.Thielemann's answer.
cmake_minimum_required(VERSION 3.10)
project(q50198141)
add_library(Big SHARED library1.cpp)
add_library(Foo SHARED library2.cpp)
add_custom_command(OUTPUT combined
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/combine.sh
ARGS $<TARGET_FILE:Big> $<TARGET_FILE:Foo> combined
DEPENDS Big Foo combine.sh
COMMENT Build output 'combined'
)
add_custom_target(run_combined ALL DEPENDS combined)
combined.sh (Make sure to be excecutable!)
#!/bin/bash
# Hardcoded for q50198141
# Args: In1 In2 Out
md5sum $1 $2 > $3

The following example works for me.
Two targets independent from each other. One custom target depending from both.
add_library(Big SHARED ${SOURCES_BIG})
add_library(Foo SHARED ${SOURCES_FOO})
add_custom_target(pack ALL
COMMAND ${CMAKE_COMMAND} -E md5sum ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}Big${CMAKE_SHARED_LIBRARY_SUFFIX}
COMMAND ${CMAKE_COMMAND} -E md5sum ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}Foo${CMAKE_SHARED_LIBRARY_SUFFIX}
DEPENDS Big Foo
COMMENT Build target pack
)
Note: Calculating the hash of the code is just to show whether targets are rebuild on changes or not.

Related

CMake: require building of files in addition to building targets

In this simple CMakefile, the first script list.sh outputs a list of 2 generated files file1.proto;file2.proto, instructing CMake that they can be built from source source.xml (using the second script gen.sh).
cmake_minimum_required(VERSION 3.13)
set(source "source.xml")
execute_process(
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/list.sh ${source}
OUTPUT_VARIABLE protos
)
message("${protos}: ${source}")
add_custom_command(
OUTPUT ${protos}
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/gen.sh ${source}
DEPENDS ${source}
)
add_custom_target(my_target DEPENDS ${protos})
Everything works well if I run:
$ cmake ..
file1.proto;file2.proto: source.xml
-- Configuring done
-- Generating done
-- Build files have been written to: /build
$ make my_target
[100%] Generating file1.proto, file2.proto
[100%] Built target my_target
What should I add to be able to also run the code generation with:
$ make file1.proto
[EDIT] autocomplete suggests only the following for command make:
$ make (TAB TAB)
all cmake_force edit_cache/ preinstall
clean default_target help preinstall/
clean/ depend my_target rebuild_cache
cmake_check_build_system edit_cache my_target/ rebuild_cache/
Solution from #KamilCuk :
Adding the following makes it possible to build each proto file individually
(it works, but then cmake complains about circular dependencies!)
foreach(p ${protos})
add_custom_target(${p} DEPENDS {CMAKE_CURRENT_BINARY_DIR}/${p})
endforeach()

How to combine multiple imported targets into one

Having been unable to find an answer to this question, I decided to post it here.
I'm trying to setup a small cmake-based build and am not sure how should I tackle it.
I realize the question addresses a "how" and not a "what" but I am open for any alternative solution that doesn't feel like a hack.
I need to add a post build command to copy some (imported) dlls to my target's output:
add_custom_command(TARGET MyTarget POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:MyImportedDlls::All>
$<TARGET_FILE_DIR:MyTarget>
)
I made a "find" script for the imported dlls that creates one target for each dll
set(LIB_FILES
"${PATH_TO_LIBS}/lib1.dll"
"${PATH_TO_LIBS}/lib2.dll"
"${PATH_TO_LIBS}/lib3.dll"
)
unset(TARGETS)
foreach(LIB_FILE ${LIB_FILES})
get_filename_component(FN ${LIB_FILE} NAME_WE)
add_library(MyImportedDlls::${FN} SHARED IMPORTED)
set_target_properties(MyImportedDlls::${FN} PROPERTIES IMPORTED_LOCATION "${LIB_FILE}")
list(APPEND TARGETS "MyImportedDlls::${FN}")
endforeach()
My problem is: how to create a "combined" target that I can use in my custom command?
Just have 3 post build commands, one for each target.
foreach(target IN LISTS TARGETS)
add_custom_command(TARGET MyTarget POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:${target}>
$<TARGET_FILE_DIR:MyTarget>
)
endforeach()

Random executable output with CMake

Can I have a random name for the executable file of each build?
Or, in another words, a different name for the executable of each build action?
I wonder if a random-variable could be inserted into the build-tool-chain.
The reason of such a name is that my company's virus-checking is quite slow -- it took a long long time checking each executable, even longer then the build.
I'm using CLion 2016.2 on Win7, tool-chain is MinGW_w64_5.0, bundled CMake 3.5.2
You could always define POST_BUILD steps that call another CMake script. The only downside in the following approach would be that you can't - since it's random - reuse the executable's output name in CMake itself:
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(RandomExeName)
file(WRITE main.cpp "int main() { return 0; }")
add_executable(${PROJECT_NAME} main.cpp)
add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -D _file:PATH="$<TARGET_FILE:${PROJECT_NAME}>"
-P ${CMAKE_SOURCE_DIR}/CopyToRandom.cmake
)
set_property(TARGET ${PROJECT_NAME} PROPERTY SUFFIX ".temp")
CopyToRandom.cmake
string(RANDOM _random)
file(GLOB _old_files RELATIVE "${CMAKE_BINARY_DIR}" "*.exe")
execute_process(
COMMAND "${CMAKE_COMMAND}" -E remove ${_old_files}
COMMAND "${CMAKE_COMMAND}" -E copy "${_file}" "${_random}.exe"
)
# generate shortcut
get_filename_component(_name "${_file}" NAME_WE)
file(
WRITE "${_name}.sh"
"#!/bin/bash\n"
"${_random}.exe"
)
No you can't. Or you have to reconfigure for every build.
Regarding your actual problem: Advice the virus checker to exclude your build directories.

cmake add_custom_command not working

I am trying to run gperf from a cmake file.
I created a very minimal CMakeLists.txt below.
When I run it by
$ cmake .
$ make
It does not create the example.hpp file
What could be problem with the below CMakeLists.txt?
cmake_minimum_required( VERSION 2.6 )
function(gperf_generate_new source target)
add_custom_target(${target} echo "Creating ${target}")
add_custom_command(
SOURCE ${source}
TARGET ${target}
COMMAND gperf -L c++ ${source} > ${target}
OUTPUTS ${target}
DEPENDS ${source}
)
endfunction()
gperf_generate_new(command_options.new.gperf example.hpp)
Files, produced by source-files generators(like gpref) are rarely needed as standalone. Instead, these source files are usually used for creating executables or libraries inside a project.
So, standard pattern of using source-file generators in the CMake looks like:
# Call add_custom_command() with appropriate arguments for generate output file
# Note, that *gperf* will work in the build tree,
# so for file in the source tree full path should be used.
function(gperf_generate_new input output)
add_custom_command(
OUTPUT ${output}
COMMAND gperf -L c++ ${input} > ${output}
DEPENDS ${input}
COMMENT "Generate ${output}" # Just for nice message during build
)
endfunction()
# Generate *example.hpp* file ...
gperf_generate_new(${CMAKE_CURRENT_SOURCE_DIR}/command_options.new.gperf example.hpp)
# ... for use it in executable
add_executable(my_program ${CMAKE_CURRENT_BINARY_DIR}/example.hpp <other sources>)
If you want only to test whether example.hpp is generating, instead of add_executable() use
add_custom_target(my_target
ALL # Force target to be built with default build target.
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/example.hpp
)
Note, that linkage between add_custom_command and add_custom_target is expressed using same filename in their OUTPUT and DEPENDS options correspondingly. With such link order of these commands is insignificant (but both commands should be called from the same CMakeLists.txt script).

Using cmake with a custom file generator

I'd like to use CMake to generate obfuscated lua files for delivery. For the life of me I cannot get add_custom_command + add_custom_target to build these files for me. There's something I'm missing.
ADD_CUSTOM_TARGET(LUABIND_COMPILED_FILES ALL)
FOREACH(F ${LUA_SCRIPT_FILES})
ADD_CUSTOM_COMMAND(
OUTPUT ${LUA_COMPILED_SCRIPTS}/${F}
COMMAND ${LUAC} -o ${LUA_COMPILED_SCRIPTS}/${F}
COMMENT "Compiling ${F} to binary"
ADD_DEPENDENCIES(LUABIND_COMPILED_FILES ${LUA_COMPILED_SCRIPTS}/${F})
ENDFOREACH()
For some reason when I run cmake + make the output tells me there's nothing to be done for target LUABIND_COMPILED_FILES. Am I missing something here? Thanks in advance.
The ADD_DEPENDENCIES command can only be used to add dependencies between top-level targets. The ADD_CUSTOM_COMMAND command however generates output files, but does not add new targets.
To make a custom target depend on generated files, use the DEPENDS options of the add_custom_target command:
set (LUA_COMPILED_FILES "")
foreach(F ${LUA_SCRIPT_FILES})
add_custom_command(
OUTPUT "${LUA_COMPILED_SCRIPTS}/${F}"
COMMAND ${LUAC} -o "${LUA_COMPILED_SCRIPTS}/${F}"
COMMENT "Compiling ${F} to binary")
list (APPEND LUA_COMPILED_FILES "${LUA_COMPILED_SCRIPTS}/${F}")
endforeach()
add_custom_target(LUABIND ALL DEPENDS ${LUA_COMPILED_FILES})