CMake add depedency to the install target - cmake

I've got the following problem using cmake. I use UseDoxygen from http://tobias.rautenkranz.ch/cmake/doxygen/ to generate the documentation for my library. This works fine, but know I want to realize the following:
When I call "make install" I want to build to Documentation and install it too. Therefore I add
install(DIRECTORY ${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_HTML_DIR} DESTINATION share/doc/mylib/)
add_dependencies(install doc)
to my CMakeLists.txt.
This results in an error:
CMake Error at CMakeModules/UseDoxygen.cmake:145 (add_dependencies):
add_dependencies Adding dependency to non-existent target: install
Call Stack (most recent call first):
CMakeLists.txt:141 (include)
Is it possible to get a easy workaround for this? Because if the targets are not connected the install step installs nothing unless "make doc" is done manually befor calling "make install".
regards
Grisu

We build our documentation by adding it with add_custom_target with the ALL option specified so it builds with the all target.
Then to install, it's just the install command. There is no need to add anything to the install target.
If you add the documentation to the all target, then doing make install will also build the documentation.

If you generate code documentation, isn't it a better idea to execute that command after the build command? In this way it will be available at install time.
You can add a custom command at POST_BUILD and execute the doxygen commands there. See more at http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:add_custom_command

Building documentation via add_custom_target( ALL ...) is not an ideal solution, as it means the documentation gets built redundantly for all configurations (Debug, Release, RelWithDebInfo, MinSizeRel).
I'd like to build the documentation once regardless of the build config, then use the CONFIGURATIONS option of the install() command to install it only for the Release and RelWithDebInfo configs. install() should depend on the documentation target but, as I said, only build it for one config. There doesn't appear to be an way to add a dependency from install() onto the documentation that meets these requirements.

Related

CMake - how to block executing installation scripts during packaging?

My CMakeLists.txt file contains commands, which should be executed by make install, and all this works fine. The sample CMakeLists.txt below is a short excerpt from my actual CMake file (the tm0001.cpp content is not important here - it might be any C++ program):
cmake_minimum_required(VERSION 3.12)
project(tm0001)
set(CMAKE_CXX_STANDARD 11)
add_executable(${PROJECT_NAME} tm0001.cpp)
install(
TARGETS ${PROJECT_NAME}
DESTINATION /usr/local/bin
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
)
install(CODE "message(\"-- This must be called during installation only\")")
set(CPACK_PACKAGE_CONTACT "HEKTO")
set(CPACK_GENERATOR "DEB")
include(CPack)
I see the message command is executed by make package as well, which is not I want.
How to tell CMake not to execute installation scripts by the make package command? I couldn't find any way to do that with the CMake if command.
As it already said in the comment, it's an extremely bad idea to "work w/ systemd" (and doing anything not related to build or packaging of your project) from install commands. The install command (even SCRIPT and CODE signatures) are intended to be used for install actions and not for any other side effects.
The correct way to act here is to produce a native package (DEB/RPM) w/ post-install script, where using the system-provided macros (like described here), you can install your package properly. Take a look to CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA for the way to provide package install actions.
The other bad thing is to use the hardcoded path (/usr/bin/). And BTW, a better place for the (pure) daemon app I suggest /usr/sbin/. Take a look to GNUInstallDirs module shipped w/ CMake for further references.
What I did was to specify install commands with CODE/SCRIPT as separate component e.g. install(CODE ... COMPONENT post-install).
Then also added other non-code install commands as a different component e.g. install(FILES ... COMPONENT files-install)
The CPack then needs to be configured to package only files-install component (solution to this can be found easily - hint: use CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE, CPACK_COMPONENTS_ALL and CPACK_(RPM/DEB/...)_COMPONENT_INSTALL variables).
Of course then the resulting package won't run these CODE components during installing the package - they need to be added separately as a post install script.
I'm answering my own question, because the existing answer doesn't address my main problem. I couldn't find any way (on the CMake level) to block install commands from running during make package - even the postinst script is called by this command.
Fortunately, I could modify the postinst script itself to do nothing in case it's called not by the dpkg:
if [ -z ${DPKG_ADMINDIR} ]; then
echo "postinst: missing 'dpkg' environment (not an error during packaging)"
exit 0
fi
It's a trick of course, but it worked for me.

Custom command / target run only for default build not install

I want to build my documentation (doxygen) alongside my project with CMake by default. I let CMake generate Makefiles. I know of these approaches so far:
1)
add_custom_target(doc ALL
COMMAND ${DOXYGEN_COMMAND})
2)
add_custom_command(
TARGET my-executable
POST_BUILD
COMMAND ${DOXYGEN_COMMAND})
The issue I have with the first approach is that the target is build both during build and install (i.e. when running make and when running make install). This is a no-go.
The issue with the second approach is that it is not actually correct: the documentation doesn't have to be built after the executable (in fact, it can be done in parallel even). Moreover I cannot build only the executable now.
Is there a way to create this custom command / target such that it is run only during make (building) and not during make install (installing) but independently from other targets such as executables?
Basically I'd need a "default target". Also I really want to avoid having to execute CMake recursively or make directly.
Just create a file, which existence means that documentation file have been built:
set(documentation_file ${CMAKE__BINARY_DIR}/docs_ready)
# Documentation target
add_custom_target(docs ALL DEPENDS ${documentation_file})
# Documentation command
add_custom_command(OUTPUT ${documentation_file}
COMMAND ${DOXYGEN_COMMAND}
# And mark that documentation is created
COMMAND ${CMAKE_COMMAND} -E touch ${documentation_file}
)
The solution given by #Tsyvarev works perfectly except for one issue:
Running make docs manually doesn't cause a re-build of the documentation because the "output file" ${documentation_file} is always considered up to date (there are no dependencies specified that could be newer).
Three workarounds I found:
Run make -B docs. The -B flags causes GNU Make to consider all targets out of date, and thus causes the documentation to be build.
Add a "manual docs" target which depends on first a docs-clean target which removes ${documentation_file} and then on docs itself (to build the documentation and the file), and run make docs-manual:
add_custom_target(docs-clean
COMMAND ${CMAKE_COMMAND} -E remove ${documentation_file})
add_custom_target(docs-manual)
add_dependencies(docs-manual docs-clean docs)
Note that I fear that this is just a dirty hack: AFAIK the order in which the dependencies (docs-clean and docs) are build isn't specified, and as they don't have a dependency between them, they could even be built in parallel.
Using add_custom_command with a TARGET docs-manual and PRE_BUILD (which runs the command before building dependencies) instead of the docs-clean target would've been perfect, but this only works for Visual Studio 7 or later.
Add a custom target that depends on docs but removes the generated ${documentation_file}:
add_custom_target(docs-manual
COMMAND ${CMAKE_COMMAND} -E remove ${documentation_file})
add_dependencies(docs-manual docs)
This works except for when running it the first time after a make docs, because then the generated file will still be there when docs is built.
edit: Use add_dependencies instead of DEPENDS of add_custom_target because the later is only intended for files, not for dependencies on targets.

Building a CMake library within a Bazel project

I've written a module on top of a private fork off of TensorFlow that uses nanomsg.
For my local development server, I used cmake install to install nanomsg (to /usr/local) and accessed the header files from their installed location. The project runs fine locally.
However, I now need to package nanomsg within my TensorFlow workspace. I've tried the following two approaches, and find neither satisfactory:
Similar to this answer for OpenCV, I precompiled nanomsg into a private repository, loaded it within my workspace (within tensorflow/workspace.bzl) using an http_archive directive then included the headers and libraries in the relevant build script. This runs fine, but is not a portable solution.
A more portable solution, I created a genrule to run a specific sequence of cmake commands that can be used to build nanomsg. This approach is neater, but the genrule cannot be reused to cmake other projects. (I referred to this discussion).
Clearly cmake is not supported as a first-class citizen in Bazel builds. Is there anyone who has faced this problem in your own projects created a generic, portable way to include libraries within Bazel projects that are built using cmake? If so, how did you approach it?
As Ulf wrote, I think your suggested option 2 should work fine.
Regarding "can I identify if the cmake fails", yes: cmake should return with an error exit code (!= 0) when it fails. This in turn will cause Bazel to automatically recognize the genrule action as failed and thus fail the build. Because Bazel sets "set -e -o pipefail" before running your command (cf. https://docs.bazel.build/versions/master/be/general.html#genrule-environment), it should also work if you chain multiple cmake commands in your genrule "cmd".
If you call out to a shell script in your "cmd" attribute that then actually runs the cmake commands, make sure to put "set -e -o pipefail" in the first line of your script yourself. Otherwise the script will not fail when cmake fails.
If I misunderstood your question "Can I identify if the cmake fails", please let me know. :)
This new project: https://github.com/bazelbuild/rules_foreign_cc seems like a solution(it build rules for cmake to build your project inside bazel).

Is it possible to alter CMAKE_MODULE_PATH from CMake commandline?

Edit: The accepted answer actually shows that it is pretty normally possible to set CMAKE_MODULE_PATH as any other CMake variable e.g. via the -DCMAKE_MODULE_PATH path CLI parameter. It seems that in my case there is some included CMake script that calls set(CMAKE_MODULE_PATH /library_path), which erases all previous paths set to the variable. That's why I couldn't get the variable to do what I wanted it to do. I'll leave the question here in case anybody else faces this kind of situation.
I'm building a (3rd party) project that uses the Protobuf library (but this question is general). My system has a system-wide install of a newer version of Protobuf than the project is compatible with. So I've downloaded and compiled from source an older version of Protobuf.
The project uses CMake, and in its CMakeLists.txt, there is:
find_package(Protobuf REQUIRED)
Which, however, finds the (incompatible) system install. Of course, CMake doesn't know about my custom build of Protobuf. But how do I tell it?
I've created a FindProtobuf.cmake file in, say, ~/usr/share/cmake-3.0/Modules/ and want the build process to use this one for finding Protobuf. But I haven't succeeded forcing CMake to pick up this one and not the system one. I think the reason is quite obvious from the CMake docs of find_package:
The command has two modes by which it searches for packages: “Module” mode and “Config” mode. Module mode is available when the command is invoked with the above reduced signature. CMake searches for a file called Find<package>.cmake in the CMAKE_MODULE_PATH followed by the CMake installation. If the file is found, it is read and processed by CMake. ... If no module is found and the MODULE option is not given the command proceeds to Config mode.
So until I succeed to change CMAKE_MODULE_PATH, CMake will just pick up the FindProtobuf.cmake installed to the default system path and won't ever proceed to the "Config" mode where I could probably make use of CMAKE_PREFIX_PATH.
It's important for me to not edit the CMakeLists.txt since it belongs to a 3rd party project I don't maintain.
What I've tried (all without success):
calling CMAKE_MODULE_PATH=~/usr/share/cmake-3.0/Modules cmake ... (the env. variable is not "transferred" to the CMake variable with the same name)
calling cmake -DCMAKE_MODULE_PATH=~/usr/share/cmake-3.0/Modules ... (doesn't work, probably by design?)
calling Protobuf_DIR=path/to/my/protobuf cmake ... (the project doesn't support this kind of override for Protobuf)
It seems to me that, unfortunately, the only way to alter the CMAKE_MODULE_PATH used by find_package is to alter it from within CMakeLists.txt, which is exactly what I want to avoid.
Do you have any ideas/workarounds on how not to touch the CMakeLists.txt and still convince find_package to find my custom Protobuf?
For reference, the CMake part of this project is on github .
As a direct answer to your question, yes, you can set CMAKE_MODULE_PATH at the command line by running cmake -DCMAKE_MODULE_PATH=/some/path -S /path/to/src -B /path/to/build.
But that probably doesn't do what you want it to do; see below.
The Bitbucket link you supplied is dead, but here are a few suggestions that might help.
Avoid writing your own find modules, especially when the upstream supplies CMake config modules.
You can direct CMake to your custom Protobuf installation by setting one of CMAKE_PREFIX_PATH or Protobuf_ROOT (v3.12+) to the Protobuf install root.
You can tell find_package to try CONFIG mode first by setting CMAKE_FIND_PACKAGE_PREFER_CONFIG to true (v3.15+). Then set Protobuf_DIR to the directory containing ProtobufConfig.cmake.
Failing all else, you can manually set the variables documented in CMake's own FindProtobuf module, here: https://cmake.org/cmake/help/latest/module/FindProtobuf.html
All these variables can be set at the configure command line with the -D flag.
There are very few environment variables that populate CMake variables to start and I would avoid relying on them. There is an exhaustive list here: https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html. CMAKE_MODULE_PATH is not among them.

cmake exclude executable during install

How to configure/hack cmake to build particular executable added with add_executable() but do not install it?
The executable is a unit test and will eventually be handled with add_test but for now I just want to strip test binaries off the release touching as little as possible.
Thanks
Since EXCLUDE_FROM_ALL has undefined behavior if combined with INSTALL (cmake tries to warn you, it doesn't matter if OPTIONAL is set), a solution guaranteed to work is more complicated.
You should:
Remove dependency of "install" target to "all" target (once, in the main CMakeLists.txt):
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true)
Add OPTIONAL to the INSTALL statements in your test libraries. Be aware of the possible bug of CMake I reported here
Collect separately all the targets you want to include in a custom "all_but_tests"
CMake add_custom_target depending on whole project being built (most difficult step)
Create a custom all_but_tests target:
add_custom_target(all_but_tests DEPENDS <<list of targets>>)
Add a dependency of the target install to all_but_tests
add_dependency(install all_but_tests)
(Sorry, this I have never tried, feedback is welcome)
Create a custom tests target:
add_custom_target(my_tests DEPENDS <<list of tests>>)
Then (supposing you are using make, but will work also for ninja):
You can call make install, which triggers make all_but_tests, and installs once built is complete.
You can call make my_tests, and then make install, in this case it will install everything. You can concatenate the commands like this
make my_tests && make install
or, since there is not difference in this case:
make [all] && make install
I was attracted by this question because I recently had to face a similar problem: Installing only one target and its dependencies
Edit:
add_dependency(install all_but_tests) will probably not work.
So, either you use an adequate workaround, or you call
make all_but_tests && make install
everytime you want to install "all_but_tests"
CMake will only install an executable target if you apply the install function to it, i.e.:
install(TARGETS ExecutableTest RUNTIME DESTINATION "bin")
To prevent the installation of the ExecutableTest for a Release build, add a CONFIGURATIONS restriction:
install(TARGETS ExecutableTest RUNTIME DESTINATION "bin" CONFIGURATIONS Debug)
Alternatively, you can make ExecutableTest an optional target, which is not built by default:
add_executable(ExecutableTest EXCLUDE_FROM_ALL ${ExecutableTestFiles})
and then optionally only install the ExecutableTest if it has been built explicitly:
install(TARGETS ExecutableTest RUNTIME DESTINATION "bin" OPTIONAL)
All optional test targets can be pooled in a super target to allow for building them in one step:
add_custom_target(MyTests DEPENDS ExecutableTest ExecutableTest2 ExecutableTest3)