Use RENAME in INSTALL(TARGETS ...) - cmake

I'm fairly new to CMake so please be gentle.
I have a two targets which both need to be called internal for further use on runtime. Now, when I call
set_target_properties(target1 PROPERTIES OUTPUT_NAME internal)
install(TARGETS target1 DESTINATION some/where/target1dir)
set_target_properties(target2 PROPERTIES OUTPUT_NAME internal)
install(TARGETS target2 DESTINATION some/where/target2dir)
one of the two targets will be overridden by the other one when invoking cmake, so when executing nmake in the build folder, the same file is copied to some/where/target1 and some/where/target2.
I considered using the RENAME option to change the temporary name of the built file to an arbitrary one, but this option is not allowed when using the TARGETS keyword.
Do you know how to solve this? Thank you!

I worked around this by adding a CMake file to the source directory which renames the files, configuring that file with the target's output name and the rename name, then adding a target property POST_INSTALL_SCRIPT which holds the path to the configured cmake file.
Due to a lack of knowledge about variables available to determine certain directories (such as the location of the devel folder) there is still much stuff inside that is hardcoded and the whole workaround seems like overkill and is ugly, so, if YOU know a better strategy, PLEASE tell me :)

Related

Getting environment variable during runtime from file in cmake [duplicate]

I have a project under CMake with some files generated with python generator from XML files. I cannot specify all files generated by this generator in CMakeLists.txt so I use file globbing for this.
The problem is that when I update my XML files or generator sources (which are in the same repository) I would like to have my build system reconfigured so changed files are taken into account when rebuilding the code (via make for example).
Is it possible to make CMake treat some files like it treats CMakeLists.txt files and to make it regenerate build system when those file are changed?
It doesn't require any kind of workarounds. The standard way is to use CMAKE_CONFIGURE_DEPENDS property:
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS <filename>)
Yes, you should be able to do that by (ab)using configure_file(). Configuring a file makes the source a dependency of the CMake run, so that any changes in it cause a reconfiguration. Simply like this:
configure_file(MyInputFile.xml DummyOutput.xml)
Since it has been a while I will add to #roolebo's answer.
There's actually a better command to add a dependency on a file:
set_directory_properties(PROPERTIES CMAKE_CONFIGURE_DEPENDS <relative_or_full_path_to_file>)
What might be confusing is that this command adds a property to the current directory. Well, it does not matter since you can set a full path to a file that resides outside of the current directory's scope, for instance: ../../config.json

CMake have a target depend on a generated file in a subdirectory

I have a scenario that I think is very similar to this one: CMake add_custom_command/_target in different directories for cross-compilation, however the solution for that issue isn't working for me.
In subdir/CMakeLists.txt I have:
add_custom_command(OUTPUT foo.h foo.cpp COMMAND ... DEPENDS foo.xml)
add_custom_target(generate_foo DEPENDS foo.h foo.cpp)
and then CMakeLists.txt:
add_executable(MyTarget
subdir/foo.h
subdir/foo.cpp
${OTHER_SOURCES})
add_dependencies(MyTarget generate_foo)
add_subdirectory(subdir)
This fails with "Cannot find source file: subdir/foo.h". The documentation for add_dependencies suggests that it will ensure that generate_foo builds before MyTarget, but if that's the case it looks like it's at least trying to access all source files before either target builds. Am I doing something wrong here? How can I compile source files that are generated by a custom target/command in a subdirectory?
The problem is that the GENERATED file property (that CMake uses to determine if it needs to check that a file exists at configure time) is not visible outside the directory in which the file is generated. The problem goes away in CMake 3.20. This is explained here.
I usually solve this problem by compiling generated source files into a static or object library in the subdirectory, then linking to that, since targets are globally visible. You can also explicitly set the GENERATED property on the generated files in the scope you wish to use them, but this hack breaks the encapsulation gained by using a subdirectory.
It's also worth noting that you can do away with the custom target and the call to add_dependencies because the generated files are already dependencies of the executable (this has always has been the case AFAIK).

How to pass variable to cpack?

I have a cmake project which one of the install targets is a collection of files. This files change depending on the configuration (Release, Debug...).
I would like to be able to install the files like so:
install(DIRECTORY $<TARGET_FILE_DIR:tgt>
DESTINATION bin
COMPONENT files)
But cmake does not support that. Generator variables do not apply to DIRECTORY. So I was wondering if there is a way to either save the directory somewhere. Either the cache or a file and then load it into cpack.
So I guess the question is how to pass a variable from cmake to cpack?
This is a rather late answer, but I happened upon this question trying to solve a somewhat different problem that could also be summarized as: "How do I pass a variable to CPack?" In my case, I was making this call from a customized version of CPackDeb.cmake copied to my workspace:
find_program(OPKG_CMD NAMES opkg-build HINTS "${OPKG_HINT}")
# ^^^^^^^^^^^^
# This is what I wanted to pass to CPack
I was setting OPKG_HINT in a file included from my top-level CMakeLists.txt, but it was not getting passed through to cpack; the above find_program() invocation was seeing an empty string for OPKG_HINT.
The solution turned out to be stupid simple: just prepend CPACK_ to the variable name!
If I do this in CMakeLists.txt:
set(CPACK_OPKG_HINT "${_sysroot_top}/aarch64-poky-linux/usr/bin")
then I can put this in my CPackDeb.cmake file and it works fine:
find_program(OPKG_CMD NAMES opkg-build HINTS "${CPACK_OPKG_HINT}")
Anyway, this wound up being a bit of an X-Y problem for the OP, but... if you really need to set a variable at CMake time in such a way that it's accessible to cpack, prefixing the variable name with CPACK_ seems to do the trick nicely...
The following setup work if you use a "single-configuration generators (such as make and Ninja)" and call CMake with
cmake -DCMAKE_BUILD_TYPE=Release <source_dir>
https://cmake.org/cmake/help/v3.0/variable/CMAKE_BUILD_TYPE.html
You can define the ${dir} variable in another way if you like.
IF (CMAKE_BUILD_TYPE STREQUAL "Release")
SET(dir release_dir)
ELSE()
SET(dir debug_dir)
ENDIF()
INSTALL(DIRECTORY ${dir} DESTINATION bin COMPONENT files)
Until now this seems to be the best answer (from someone on the cmake mail list)
install(DIRECTORY path/to/Debug/dir
DESTINATION bin
CONFIGURATIONS Debug
COMPONENT files
)
install(DIRECTORY path/to/Release/dir
DESTINATION bin
CONFIGURATIONS Release
COMPONENT files
)
CMake 3.5 supports generator expressions for the DIRECTORY arguments. See installing directories.

cmake use one cmakelist.txt for a project with subdirectories

i like to structure my code in multiple subdirs but i dont want to create a new cmakelist.txt in each new subdir.
my folder structure is something like this:
project
>cmakelist.txt
>build
>src
>main.cpp
>multiple_subdirs_or_(c|h)pp_files_with_more_subdirs_or_(c|h)pp_files
my cmakelist.txt looks like this:
...
file(GLOB_RECURSE cpps RELATIVE ${CMAKE_CURRENT_LIST_DIR} "src/*.cpp")
file(GLOB_RECURSE hpps RELATIVE ${CMAKE_CURRENT_LIST_DIR} "src/*.hpp")
#remove files with main
list(REMOVE_ITEM cpps "src/test.cpp")
#bins
add_executable(test src/test.cpp src/test.cpp ${hpps} ${cpps})
#same problem if this is used instead of the other add_executable
add_library(foo OBJECT ${cpps} ${hpps})
add_executable(test src/test.cpp $<TARGET_OBJECTS:foo>)
the problem with my file:
source files created after the execution of cmake are not compiled and the build fails if they are used.
as predicted by http://www.cmake.org/cmake/help/v3.0/command/file.html in section GLOB:
We do not recommend using GLOB to collect a list of source files from
your source tree. If no CMakeLists.txt file changes when a source is
added or removed then the generated build system cannot know when to
ask CMake to regenerate.
the question: is it possible to use a single cmakelist.txt for a project with multiple sub directories? (without the problems of file(GLOB ...) )
You have two totally unrelated things here.
First, can you use only a single CMakeLists.txt file for your whole project? Yes, of course you can (although I'd personally not go this way after a project has reached a certain size), and you're already doing this.
Second, the problem with GLOB. You already quoted the part of the documentation where it states what problems the use of GLOB has. This cannot really be avoided at the moment if you want to continue using GLOB, as this is part of the cmake design where they distinguish between what is done during configure and build time. The alternative is to list all files manually. Whether you do this in a single CMakeLists.txt file in your projects main directory, or in multiple files across your subdirectories does not matter.
To answer your question: yes, it is possible to handle a project with multiple sub-directories and one CMakeLists.txt. I have two considerations for you to take into account:
I strongly recommend you not using file(GLOB ...) for sources.
You have to list the files manually. For example (src/ is the source-subdirectory):
set(cpps src/file1.cpp src/file2.cpp src/file3.cpp)

Ignoring a single file when using include_directories with CMake

is there anyway to tell CMake to ignore one specific header file when using include_directories ?
Since the directories are not expanded into single files I can't just list(REMOVE_ITEM ..) the file out.
cheers Daniel
An include_directories call in CMakeLists does not result in a list of all available header-files. It simply passes those directories directly to the compiler as a search-dir for your "#include <...>" E.g. look at the documentation for the "-I" option of GCC 4.6.
In addition: I am not sure why you would want to exclude a single file. Very often you can work around a problematic header file, by creating your own header-file in your own project which includes everything except that single-file...
If you really, really want something like this and you insist on solving it with CMake, you will probably end up with file-globing all header-files, copying (without that one file of course) them manually to a new include-dir and then include that new dir.