CMake object files of executable in custom command - cmake

I have a custom command that is executed in the pre linking stage.
What I want to do is calculate a checksum of all parts that are going to be part of my executable. Then I want to link link this checksum as a global variable into my executable.
So far I can calculate the checksum of all libraries that are going to be linked into my executable. But I also need the checksum of the already existing (because its already been built) object file of the exe.
Is there a way to get access to this object file?
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/checksum.cpp
PRE_LINK
COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/checksum_generator.cmake" ${LIB_DEPENDENCIES} <object_file_of_executable_target>
DEPENDS ${LIB_DEPENDENCIES}
)
add_library(checksum STATIC ${CMAKE_CURRENT_BINARY_DIR}/checksum.cpp)
target_link_libraries(executable_target PUBLIC checksum)
So my question is: How can I get the object file of the executable target?
Every time I try to access some generator expression of the executable_target and pass it, CMake crashes because of cyclic dependencies (which is true for the output executable, but not for the object files since they already exists in the pre link stage).

Every time I try to access some generator expression of the executable_target and pass it, CMake crashes because of cyclic dependencies
I am assuming you've build your executable as an OBJECT library first, and then the actual executable after using it like so?
add_library(obj OBJECT ${...})
add_executable(exe $<TARGET_OBJECTS:obj>)
Have you tried the $<TARGET_OBJECTS:obj> generator expression in your custom command? If your checksum.cpp is only linked in the executable target (rather than the object library) then this should resolve your cyclic dependency.

Related

CMake how to get binary target complete directory and name on Windows

Is there a way in CMake to find a binary target complete name (mybin.exe) by inspecting target properties? Like
get_target_property(EXENAME targetname OUTPUT_NAME) (or RUNTIME_OUTPUT_NAME)
Or I have to use a custom command like in How to get library full-native name on cmake?
With get_target_property seems I'm only able to get the "logical" target name out of it (mybin), with no other information. Am I missing something?
Thank you
There's a reason this is not possible without generator expressions: There are multi configuration generators such as the Visual Studio generators that create a build system for multiple build configurations (Release, Debug, ...) in a single CMake configuration run (cmake -S ... -B ...). It's even the default to create binaries in a directory with a name matching the configuration built.
Depending on what you want to do with the information, there are some alternatives:
You may be able to use generator expressions, e.g. if you need the information as part of add_custom_command, add_custom_target, add_test or similar. Several target properties also allow for use of generator expressions.
You may be able to establish the desired directory structure during an install step, see the install() command.
You may be able to get the build system to generate the files in a specific location e.g. by setting the CMAKE_RUNTIME_OUTPUT_DIRECTORY variable in the toplevel CMakeLists.txt. Note that this will still result in configuration dependent subdirectories being created for multi configuration generators, unless the variable value contains a generator expression. (You could, simply be adding $<0:>, but this could easily result in binaries of different configurations overwriting one another.)
If you cannot specify this in the toplevel CMakeLists.txt, via command line or cmake presets, you could still use a path relative to CMAKE_BINARY_DIR; this should make the binaries easy to locate.
In the end that is a matter of doing:
add_custom_command(TARGET ${your_target}
POST_BUILD
WORKING_DIRECTORY ${your_dir}
COMMAND echo "$<TARGET_FILE:${your_target}>" > "exename.txt"
DEPENDS ${your_target} ${another_target}
VERBATIM
)
so that exename.txt contains the full path to the executable target
Didn't find a way to do st like:
set(EXENAME "$<TARGET_FILE:${your_target}>")
anyway...

CMake: static library ignored (objects compiled twice) [duplicate]

I'm trying to move my project to CMake, and at the same time have some optimization on the compilation process.
Here's the deal:
I have several subdirs that are (have to be) each compiled into a static library (this works).
I want to gather all the object files from each subdir into another bigger, complete, static library.
It looks like this:
.
libBig.a # made from object from subdir1 and subdir2
subdir1/
src/
libSubdir1.a
subdir2/
src/
libSubdir2.a
Today, I managed to use a global variable in which every subdir CMakeLists.txt will append its own source files. I use this variable as a "source" input in my big library:
# the big library depends on all the source files
# ${all_src} is automatically filled with each subdir's cpp file
get_property( BigLib_src GLOBAL PROPERTY all_src)
add_library( Big STATIC ${BigLib_src}) # recompiles all the sources
Now, this works, not too bad, but the thing is, all my source files get compiled twice: once for the subdir library, and once for the big library.
CMake seems to forget that it has already built them.
I have to keep the subdir libraries and ar can't merge two static libraries.
Do you know how to do that?
You can use the new OBJECT library feature introduced in CMake 2.8.8. The idea is explained here. Basically, the OBJECT library is a similar concept to the convenience library known from Autotools to group object files.
Check the complete CMake OBJECT library tutorial.
As of CMake 2.8.8, you can do this using the OBJECT library type. See mloksot's answer. The old situation was that each target had its own directory and CMake would build every dependent object for every target. This guards against a case where one source file could be used multiple times with different CFLAGS. (Note that by default CMake is more conservative than automake here: automake will stop reusing object files for different targets only if the targets are built with different CFLAGS (and probably CPPFLAGS, too).

How do I condition the build of one target on the execution of another target's binary product?

I have a test code for my c project, which is built as part of my cmake project.
In order to run properly, the SW needs an input binary file.
The binary file is created from a designated .json file (which is in the test's directory) using a separate executable which is also part of the same cmake project.
Before the test is run (i.e. when building it) I need the bin-building executable to be built (easy enough with target dependency), but I also need the resulting executable to run with my .json as input.
What cmake functions enable this?
I tried building a custom command with the binary as output, but the test target doesn't know it needs the binary in order to run, can't accept the binary as a source, and a simple "add_dependancy" resulted in errors.
function(create_binary input_json dst_bin)
if (IS_WINDOWS)
set(exe_path ${OUTPUT_BIN_DIR}/BinaryGenerator.exe)
elseif(IS_LINUX)
set(exe_path ${OUTPUT_BIN_DIR}/BinaryGenerator)
endif()
add_custom_command(OUTPUT ${dst_bin}
COMMAND ${exe_path} ${input_json} ${dst_bin}
DEPENDS ${exe_path} ${dst_bin}
COMMENT STATUS "Creating bin file ${dst_bin} from ${input_json}"
)
endfunction(create_binary)
create_binary(InputParams.json ${OUTPUT_BIN_DIR}/InputParams.bin)
add_executable(MySwTest TestFile.cpp TestFile.h)
add_dependencies(${OUTPUT_BIN_DIR}/InputParams.bin)
I expected cmake to place a target dependency between my test target and the bin creator target, and also on the existence of the test's bin file, thus running the custom command in order to create it.
The actual output from cmake is "The dependency target InputParams.bin doesn't exist". I assume this is because "add_dependency" is meant to work only with targets.
Would adding a custom target including my binary solve this?
This is indeed solvable by defining a custom target that depends on the resulting binary.
When adding a custom command, the actual command is only called if the command's OUTPUT file is needed for another target - so if it's a source file, it will be called.
My command's output is a generated binary, and therefore is not a source file for my target.
However, using add_custom_target() I can create a target dependent on said bin file, and create a dependency between the end target and my custom target.
The working code for the above looks like this:
set(PARAMS_NAME InputParams)
set(INPUT_JSON ${PARAMS_NAME}.json)
set(DST_BIN ${PARAMS_NAME}.bin)
if (IS_WINDOWS)
set(EXE_PATH ${OUTPUT_BIN_DIR}/BinaryGenerator.exe)
elseif(IS_LINUX)
set(EXE_PATH ${OUTPUT_BIN_DIR}/BinaryGenerator)
endif()
add_custom_command(OUTPUT ${DST_BIN}
COMMAND ${EXE_PATH} ${INPUT_JSON} ${DST_BIN}
DEPENDS BinaryGenerator ${INPUT_JSON}
COMMENT STATUS "Creating bin file ${DST_BIN} from ${INPUT_JSON}"
)
add_custom_target(${PARAMS_NAME}BinGenerated DEPENDS ${DST_BIN})
add_executable(MySwTest TestFile.cpp TestFile.h)
add_dependencies(MySwTest ${PARAMS_NAME}BinGenerated)
By adding a dependency between MySwTest and my custom target, I ensure that the command generating my binary is called for each build.

Add dependency to the CMake-generated build-system itself

In short: I know how to add dependencies to targets, in a CMake-generated build system. But I would like to add dependencies to the generated build-system itself.
Longer question: In the CMake-generated build process of cgal, we would like CMake to automatically re-run the configuration step, when certain files are modified. Unneeded details are hidden below:
As a matter of fact, we generate using CMake the build system for the CGAL libraries/examples/demos, but also at the same time the build system for our Doxygen-generated documentation. The Doxyfile is generated from multiple files.
When the CMake generator is "Makefile", there is a special target in the Makefile, that is named rebuild_cache, but that target (at the Makefile level) is not a CMake-target. And anyway, I look for a solution that is cross-platform, that is: usable with all CMake generators. I have the impression that what I want is not yet doable with CMake. Can you please confirm, so that I can fill a documented feature-request?
Since CMake 3.0, you can add such a file to the directory property CMAKE_CONFIGURE_DEPENDS. This property holds a list of files; if any of them changes, CMake will trigger re-configuration.
Here is a small example. Assuming your Doxyfile is generated from Doxyfile.in.1 and Doxyfile.in.2 in the current source directory, the property could be used like this:
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS
Doxyfile.in.1
Doxyfile.in.2
)
If you're using CMake 2.x, the property CMAKE_CONFIGURE_DEPENDS is not available, but you can use the following trick:
Pass the files through configure_file(), even if you just COPYONLY them someplace and don't use the resulting copies. configure_file() introduces precisely the buildsystem dependency you're looking for.
This works, but it adds the overhead of copying the file.
(Note: This trick was also the original content of this answer, since I was not aware of CMAKE_CONFIGURE_DEPENDS at time of answering).

CMake find_package dependency on subproject

I have the following directory layout:
main_folder
+ static_lib1
+ executable
Both 'static_lib1' and 'executable' have a full CMakeLists so that they can be
built independently.
The 'executable' depends on 'static_lib1'. It uses find_package() to locate 'static_lib1'.
The main_folder contains a CMakeLists that includes both 'static_lib1' and 'executable' via add_subdirectory for conveniently building the whole project in one go.
Everything works fine if I manually build 'static_lib1' and then 'executable'. But when running the CMakeLists from the main folder, I get an error because find_package is unable to find the library files from 'static_lib1' which have not yet been built.
How can I resolve this while keeping the CMakeLists files separate (i.e. without including the static_lib's CMakeLists from the executable's CMakeLists)?
In executable's CMakeLists.txt you can check if you are building stand-alone or as part of project:
if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
# stand-alone build
find_package(static_lib1)
else()
include_directories(../static_lib1)
link_directories(../static_lib1)
...
target_link_libraries(executable static_lib1)
endif()
Switch from a file-based approach to a target-based approach for handling the dependency from executable to static_lib1.
The original problem occurred because executable called find_package for locating static_lib1, which then attempted to fill a variable like STATIC_LIB1_LIBRARY with the paths to the library files by calling find_library. executable then consumes the content of that variable in a target_link_libraries(executable ${STATIC_LIB1_LIBRARY}) call. The problem here is, since those library files only get generated as part of the build, that call to find_library will not be able to find anything.
Building executable needs to support two scenarios here:
Building standalone, where a pre-compiled version of static_lib1 is located somewhere on the disc.
Building from main_folder, where both executable and static_lib1 are part of the same build.
The approach from the question supports scenario 1, but not scenario 2.
Instead of using using a variable to communicate a dependency between the two builds, use a target. The CMakeLists.txt for static_lib1 likely creates a library target like add_library(static_lib1 [...]). In executable we now simply do target_link_libraries(executable PUBLIC static_lib1). This is sufficient to support scenario 2.
To also allow for scenario 1 at the same time, we look at the call to find_package(static_lib1) in the CMakeLists.txt for executable. Instead of providing a variable like before, this call now needs to provide a target static_lib1 for consumption.
So we adapt the find script for static_lib1 to the following behavior:
If a target static_lib1 already exists, there's nothing to be done and the find script can just return (this is scenario 2).
Otherwise, we call find_library to locate the library file on disc (as before in the original approach) and then create a new imported target: add_library(static_lib1 STATIC IMPORTED). We then configure all relevant properties of the static library to that target. For instance, to add the location of the library file, we could do
set_target_properties(static_lib1 PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
IMPORTED_LOCATION ${STATIC_LIB1_LIBRARY}
)
To support multi-config generators like MSVC, instead of setting IMPORTED_LOCATION and IMPORTED_LINK_INTERFACE_LANGUAGES, you will want to set the configuration specific properties like IMPORTED_LOCATION_DEBUG and IMPORTED_LOCATION_RELEASE instead. Since this can get quite tedious to do manually, you can have CMake generate this information (and a bunch of other convenient stuff) for you in a package script. The find mechanism for package scripts works slightly different under the hood, but the code in the CMakeLists.txt for executable will look just the same, a simple call to find_package(static_lib1). The main difference is that this call will then not dispatch to a hand-written find script, but to a package script that was automatically generated by CMake as part of the build process of static_lib1.
I guess I will leave this answer for posterity since only recently I have searched for a solution to this problem and found out that...
Since CMake 3.24 it is possible!
It is possible to override subsequent calls to find_package() with FetchContent_Declare() flag OVERRIDE_FIND_PACKAGE.
Your
add_subdirectory("path/to/static_lib1")
call has to be replaced in main_folder/CMakeLists.txt with:
include(FetchContent)
FetchContent_Declare(
static_lib1
SOURCE_DIR "path/to/static_lib1"
OVERRIDE_FIND_PACKAGE
)
Any calls to find_package(static_lib1) will call FetchContent_MakeAvailable() for you, virtually making it identical to add_subdirectory() call.
You can read more about OVERRIDE_FIND_PACKAGE in CMake documentation.