cmake exclude executable during install - cmake

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)

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.

How to specify target with ExternalProject_Add?

Is it possible to build only a specific target when using ExternalProject? In particular, I need to download and build only the MPI version of the OpenCoarrays library. I tried
ExternalProject_Add(
OpenCoarrays-fallback
EXCLUDE_FROM_ALL 1
URL https://github.com/sourceryinstitute/opencoarrays/archive/1.0.1.tar.gz
BUILD_COMMAND make caf_mpi
)
but it builds both serial and MPI versions. If it is not possible, any hack is also welcome.
make install installs all flows of OpenCoarrays, so even you build only caf_mpi at build stage, caf_single is built automatically on install stage.
For install only caf_mpi library flow you can try to modify package sources using PATCH_COMMAND argument of ExternalProject_add command.
E.g, you may replace content of src/CMakeLists.txt file to this one:
add_subdirectory(mpi)
Probably, this will work.

Installing only one target (and its dependencies) out of a complex project with cmake (open to better solutions)

Let's say I have a project made of several subprojects A, B, C, D...
All subprojects depends on A, which changes rather frequently.
Plus, there might be some further dependencies:
in this example, D depends on B.
Now: many people are working on these projects. The main CMakeLists.txt file should include all directories, so that the build all builds everything. But people would like also to be able to work only on one of these projects, and not having to build/install everything everytime.
If I am working on D, I can easily build "only" D by calling
cmake --build . --target D -- -j7
or
ninja -j7 D
This will also build A and B if something for them has changed. Perfect.
But how can I call install only for D without triggering build all?
I would like that if I call:
ninja -j7 D install
it only built D (and dependencies) and then installed only D and its dependencies (A and B).
Instead, it builds the target all and install all.
I would like to keep that the target all keep building everything. So EXCLUDE_FROM_ALL wouldn't be an option. But going in that direction I couldn't find any solution.
So I am thinking of the following strategy:
Apart from subproject A, all other targets are set to EXCLUDE_FROM_ALL, and OPTIONAL at installation.
I add one extra subproject that simply depends from all other sub-projects (maybe I make each target publish its name by using some variable set at PARENT_SCOPE), and people will have to call that when they want to build and install everything.
Is it going to work? Is there any better solution?
We would like to avoid that everybody has to edit the main CMakeLists.txt file to exclude projects he is not interested in. The solution should be portable to different OSs.
Edit:
I tried the strategy I proposed, but it didn't work: in my case, putting an install statement for a target (even if specified as OPTIONAL) will make ineffective EXCLUDE_FROM_ALL. Reading better in the documentation I found out that:
Installing a target with EXCLUDE_FROM_ALL set to true has undefined behavior.
I also get this warning:
Target <targetname> has EXCLUDE_FROM_ALL set and will not be built by default but an install rule has been provided for it. CMake does not define behavior for this case.
Edit 2:
I tried putting EXCLUDE_FROM_ALL as an option of add_subdirectory (instead of add_library/add_executable), but then all the install statements in those sub-directory seem to be ignored: only install statements in non excluded-from-all subdirectories will be installed.
Edit 3:
Even if I activate CMAKE_SKIP_INSTALL_ALL_DEPENDENCY:
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true)
in the main CMakeLists.txt file, and I omit all EXCLUDE_FROM_ALL, put installation of as many targets as I want optional (in my case, all but A), and if building of specific targets precede installation, yet the command:
ninja -j7 D && ninja install
for some reason will fail, stating that C (whose installation was set to OPTIONAL) does not exist (it was not created because D depended only on A and B)...
file INSTALL cannot find "<name of dll file for C>"
Edit 4:
It looks like a cmake bug to me. (I am using 2.8.11 under Windows, also tested 2.8.10)
This INSTALL command
install(TARGETS ${targetname} RUNTIME DESTINATION . LIBRARY DESTINATION . OPTIONAL)
is converted in the cmake_install.cmake as:
IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified")
FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/." TYPE SHARED_LIBRARY FILES *path_to_dll*)
IF(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/./" AND NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/./*dll_name*")
IF(CMAKE_INSTALL_DO_STRIP)
EXECUTE_PROCESS(COMMAND "C:/Programs/MinGW/bin/strip.exe" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/./*dll_name*")
ENDIF(CMAKE_INSTALL_DO_STRIP) ENDIF() ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified")
with the command FILE missing OPTIONAL! If I add OPTIONAL manually, it works!
(note: I have edited here to put *dll_name* and *path_to_dll* placeholders)
Edit 5:
I confirm it's a bug of cmake, or at least wrong documentation. I will report this.
The situation solved either putting a more simple
install(TARGETS ${targetname} DESTINATION . OPTIONAL)
(but this in my case will also install .lib.a files that I don't want)
or moving in front the OPTIONAL flag:
install(TARGETS ${targetname} OPTIONAL RUNTIME DESTINATION . LIBRARY DESTINATION .)
What one understands from the cmake documentation is that OPTIONAL should be put as last option.
What works:
Remove dependency of "install" target to "all" target (once, in the main CMakeLists.txt):
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true)
Set to OPTIONAL installation of all targets you do not want to always build:
install(TARGETS <<targetname>> DESTINATION . OPTIONAL)
Build the targets you want to install
ninja -j7 <<list of targets>>, or more generally:
<<your builder>> <<your options>> <<list of targets>>
This will build all the targets listed and their dependencies
Call the installer
ninja install. This will install all the libraries you have built, those you mentioned explicitly and those to which they depended. This solves the problem of installing a specific target together with its dependencies!
To concatenate the commands, both on Unix and Windows you can use
ninja -j7 <<list of targets>> && ninja install
Note that, at least for ninja, you cannot simply prepend "install" to the list of targets, as the target "install" does not depend anymore on any target and ninja in parallelizing the job will run install while you are still building your targets. A replacement to the old ninja -j7 install is
ninja -j7 && ninja install.
The target "all" is still available (and it is still the default target).
If you need to create a list of targets you want to build together, you can define a custom target:
add_custom_target(<<collective target name>> DEPENDS <<list of targets>>)
This will not be included in the target all. Adding also a COMMAND would also allow to create an install target for as many as target as we want, for example ninja -j7 install_D, but I think now we are beyond the scope of this question.
Further considerations:
(Note, July 2018: This might be outdated) If you use RUNTIME DESTINATION, LIBRARY DESTINATION etc., most likely because of a CMake bug the OPTIONAL keyword should be put exactly in the position indicated below:
install(TARGETS <<targetname>> OPTIONAL RUNTIME DESTINATION <<some dir>> LIBRARY DESTINATION <<some (other) dir>>)
This contradicts what written in the documentation, and I will proceed to report it as a bug to the CMake developers.
Using EXCLUDE_FROM_ALL in combination with INSTALL + OPTIONAL is a bad idea
Installing a target with EXCLUDE_FROM_ALL set to true has undefined behavior.
(and cmake tries to warn you when it parses the code)
As I answered here,
recent versions of Ninja provide the option to build only targets in a subdirectory.
The same feature holds for installs. So if your target D from your question were in a subdirectory D you can run this command:
ninja D/install
Find more info at the CMake documentation to the Ninja Generator here.
If you have used add_subdirectory to add your sub-projects to your CMakeLists.txt you will see, that in your build-directory you have subdirectories for all your subprojects.
If you only want to install the targets from D just do:
cd build-dir/D
make install
this will only install the D-targets.
Of course you have to have built your project before in build-dir. I'm using it is this way using gnu-make. I don't know if it works with Ninja.
As mentioned by unapiedra the ninja build file generated by cmake includes rules for building/testing/installing/packaging what's inside a particular directory.
This is fine but you cannot do:
ninja <targetName>/install
You can only do
ninja path/where/targetName/is/install
If you don't know where the targetName is you may use:
ninja -t query <targetName>
to see outputs.

How to build and install cmake targets only if the other targets depend on them?

My application consists of the core, many shared libraries and many plugins that use these shared libraries. I'm using cmake option() command to enable / disable each plugin.
What I'd like to do is to build and install the shared library only if it's required by one of the enabled plugins.
I tried using the following in the directories of the shared libraries:
set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL true)
However, the targets are still being built in Visual Studio. GNU make in Linux correctly avoids building them. However, the required libraries are no longer installed using install() in either
system.
I also tried adding EXCLUDE_FROM_DEFAULT_BUILD false to the library targets,
but cmake complained about the undefined behavior of install() with disabled targets.
It sounds like you have something like this:
OPTION( BUILD_OPTIONAL_PLUGINS "Build plugins that are not required for core install" FALSE)
IF(${BUILD_OPTIONAL_PLUGINS})
ADD_SUBDIRECTORY( Plugins/Optional) # Whatever it really is.
ENDIF()
So far so good. However, you now can have a library like "libCommon" that nobody needs if all those option flags are false.
So, your simplest solution is this: Treat the library as optional TOO!
After all, you don't need to even build it if none of the consuming projects themselves are going to be built. So have an ordinary 'SET' variable like 'BUILD_COMMON' in that same top-level CMakeLists.txt, defaulted to TRUE. Then just do this:
SET( BUILD_COMMON 0)
IF(${BUILD_OPTIONAL_1} OR ...) # Detect if you need to build the lib
SET( BUILD_COMMON 1)
ENDIF()
IF(${BUILD_COMMON})
ADD_SUBDIRECTORY( common)
ENDIF()
Then when you eventually do 'make install' on this build, everything works as expected. If turned off all the optional plugins, the library that was only being used by them never got built either. Since it was never in the build, you don't need to try and make its install logic aware of whether it is needed or not.
You should also add a line like this to the INSTALL() command for the library as well as every optional plugin:
INSTALL( TARGETS <plugin> .... OPTIONAL)
That tells 'make install' to not try and build or install the target if it doesn't see its binaries.

CMake add depedency to the install target

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.