12

I'm using CMake for a project and googletest for my test cases. Looking around the internet, it seems to be common practise to just copy the googletest source into a subfolder of your repository and include it with "add_subdirectory(googletest)". I did that.

Now I'm using CPack to generate debian packages for my project. Unfortunately, the packages generated by CPack install googletest alongside with my project. This is of course not what I want.

Looking in the googletest directory, I found some INSTALL cmake commands there, so it is clear, why it happens. The question is now - how can I avoid it? I don't like modifying the CMakeLists.txt files from googletest, because I would have to remember re-applying my modifications on an update. Is there another way to disable these installs in CPack?

Heinzi
  • 5,793
  • 4
  • 40
  • 69

3 Answers3

16

So there is the macro option @Tsyvarev mentioned that was originally suggested here:

# overwrite install() command with a dummy macro that is a nop
macro (install)
endmacro ()

# configure build system for external libraries
add_subdirectory(external)

# replace install macro by one which simply invokes the CMake
install() function with the given arguments
macro (install)
  _install(${ARGV})
endmacro(install)

Note ${ARGV} and ${ARGN} are the same but the docs currently suggest using ${ARGN}. Also the fact that macro-overwriting prepends _ to the original macro name is not documented, but it is still the behaviour. See the code here.

However, I never got the above code to work properly. It does really weird things and often calls install() twice.

An alternative - also undocumented - is to use EXCLUDE_FROM_ALL:

add_subdirectory(external EXCLUDE_FROM_ALL)

According to some comment I found somewhere this disables install() for that subdirectory. I think what it actually does is set EXCLUDE_FROM_ALL by default for all the install() commands which also probably does what you want. I haven't really tested it, worth a shot though.

Timmmm
  • 88,195
  • 71
  • 364
  • 509
12

NOTE: Approach below is the last thing which you should try. While it works by itself, it prevents your project to be integrated with other projects, which redefines install command, and prevents your project to be configured with some toolchains, which do such redefinition.


The main idea: redefine install command so it will install things only when a specific variable is not TRUE. That variable could be set to TRUE when you want to include subdirectory and disable installation commands inside it.

In the top-level CMakeLists.txt place these commands. They doesn't disable installation, but allows further code to do that in a controllable manner.

# By using such 'if' we allow integration of our project
# with other projects, which use the **same approach**
# for disabling installation.
if(NOT DEFINED _DISABLE_INSTALLATION)
  # This variable is responsible for installation disabling.
  set(_DISABLE_INSTALLATION FALSE)

  # Replace install() with conditional installation.
  macro(install)
    if (NOT _DISABLE_INSTALLATION)
      _install(${ARGN})
    endif()
  endmacro()
endif()

When need to include googletest (or other project) with disabled installation, wrap it in the following manner:

# Store old value of flag for the case the external project already disables installation of current one.
set(_DISABLE_INSTALLATION_OLD ${_DISABLE_INSTALLATION})

set(_DISABLE_INSTALLATION TRUE)
add_subdirectory(googletest)
# Restore original install() behavior.
set(_DISABLE_INSTALLATION ${_DISABLE_INSTALLATION_OLD})

Approach with install redifinition has been suggested in CMake mailing. But the code above avoids double redefinition of install, in which case original install behavior will be lost (_install will refer to the first redefinition).

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
  • The second thing seems to disable my own install commands as well, although they're defined in a different (not sub-) directory. For which scope is the install function overwritten? Can I overwrite it for the current directory (including subdirectories) only? – Heinzi Feb 12 '16 at 13:29
  • `Can I overwrite it for the current directory (including subdirectories) only?` - Exactly so function's definition should work. I will test that later. – Tsyvarev Feb 12 '16 at 13:34
  • Well, actually function definition has a global scope. I have added the code for restoring `install()` behavior into the answer post. – Tsyvarev Feb 08 '17 at 19:40
  • 3
    This doesn't quite work. For some reason it makes one of my other `install(DIRECTORY ...)`'s in a different subdirectory not get installed. – Timmmm Feb 09 '17 at 11:23
  • I think the issue is with spaces and CMake's insane quoting system. Also if you define the `install` macro twice, both get called. Doesn't matter in this case but how weird is that? – Timmmm Feb 09 '17 at 11:36
  • Or perhaps not. It *looks* right and it seems to be calling `_install()` correctly but the component doesn't get added. By the way the `_` prefix thing (which is totally undocumented) happens [here](https://github.com/Kitware/CMake/blob/master/Source/cmMacroCommand.cxx#L192). – Timmmm Feb 09 '17 at 11:48
  • `Also if you define the install macro twice, both get called.` - Just checked, only the last macro definition is called for me. Can you provide example of `install(DIRECTORY)` which doesn't work with these tricks? `I think the issue is with spaces and CMake's insane quoting system.` - Yes, this is a possible reason. As far as I remember, macro call "consumes" one level of escaping. May be, replacing `macro` with `function` helps? – Tsyvarev Feb 09 '17 at 12:07
  • @Tsyvarev As other comments have eluded to I have done the following in my cmake file. But the components after "Restoring" the previous `install()` behavior do not get installed. Only the components before "Replacing" the `install()` work. You said that you would add the "code for restoring `install()` into the answer post." Where is this "answer" post? – Matthew Hoggan Apr 24 '19 at 03:38
  • I meant the code after "# Restore original install() behavior." comment. Not sure why it worked for me, but not for others... – Tsyvarev Apr 24 '19 at 08:31
  • I have redesigned the approach with `install` redefinition for avoid double redefinition of the function. It works for me with CMake 3.22. – Tsyvarev Apr 02 '23 at 12:39
7

A bit late reply, but I just spent too long a time figuring this out.

In the specific case of googletests, specifying this in your top level CMakeLists.txt does the trick.

option(INSTALL_GMOCK "Install Googletest's GMock?" OFF)
option(INSTALL_GTEST "Install Googletest's GTest?" OFF)
add_subdirectory(googletest)

I read on (I think) the CMake mailing list that making installation conditional on a INSTALL_<package name> inside your package is sort of a defacto standard (and one I'm certainly going to follow from now on!). But I can't find that link now.

user2365669
  • 145
  • 1
  • 5
  • `option(INSTALL_GTEST OFF)` works fine also when placed before `FetchContent_MakeAvailable(googletest)` – AntonK Sep 17 '22 at 23:57