c++makefilecmakecmake-modules

Shared CMake scripts between multiple projects


I'm looking for a way to share CMake scripts between multiple projects.

In a repo called somelib I have a cmake folder, and from the other projects I want to include the scripts in it. In the CMakeLists.txt of somelib I include many files from the cmake folder.

My projects declare "somelib" as an external dependency like so :

include(FetchContent)                                                                   
FetchContent_Declare(                                                                   
    somelib                                                                              
    GIT_REPOSITORY git@git.somewhere.com:somewhere/somelib.git                             
    GIT_TAG        origin/master                                                        
)                                                                                       
                                                                                        
FetchContent_MakeAvailable(somelib)          

I'm not sure this is a good practice so feel free to correct me, but I'm willing to include the CMakeLists.txt of somelib so that my project include all the files that somelib includes.

So after the FetchContent_MakeAvailable I did :

include(${somelib_SOURCE_DIR}/CMakeLists.txt)

This include by itself works just fine, but the issue lies in the CMakeLists.txt of somelib. Indeed, the includes it does are not relative to its location resulting in errors like :

CMake Error at _build/_deps/somelib-src/CMakeLists.txt:26 (include):
  include could not find load file:

    cmake/Cache.cmake
Call Stack (most recent call first):
  CMakeLists.txt:47 (include)


CMake Error at _build/_deps/somelib-src/CMakeLists.txt:29 (include):
  include could not find load file:

    cmake/Linker.cmake
Call Stack (most recent call first):
  CMakeLists.txt:47 (include)


CMake Error at _build/_deps/somelib-src/CMakeLists.txt:33 (include):
  include could not find load file:

    cmake/CompilerWarnings.cmake
Call Stack (most recent call first):
  CMakeLists.txt:47 (include)

I do realize that instead of including the CMakeLists.txt I could simply do :

include(${somelib_SOURCE_DIR}/cmake/Cache.cmake)
include(${somelib_SOURCE_DIR}/cmake/Linker.cmake)
include(${somelib_SOURCE_DIR}/cmake/CompilerWarnings.cmake)

But this will become quite big as the time goes by (plus it will be duplicated between all my projects), so I would like to have a single entry point, a single thing I can include to have everything at hand in my CMakeLists. Is it possible ?


Solution

  • Don't do include(${somelib_SOURCE_DIR}/CMakeLists.txt) since FetchContent_MakeAvailable(somelib) already calls add_subdirectory on that same file.

    If you want access to its scripts, then just run:

    list(APPEND CMAKE_MODULE_PATH "${somelib_SOURCE_DIR}/cmake")
    include(Cache)
    include(Linker)
    include(CompilerWarnings)
    

    But this will become quite big as the time goes by (plus it will be duplicated between all my projects), so I would like to have a single entry point, a single thing I can include to have everything at hand in my CMakeLists. Is it possible?

    You could also move these helpers to their own repository and have every project FetchContent that. Then its CMakeLists.txt would just have this:

    list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
    set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" PARENT_SCOPE)
    

    And you would run:

    FetchContent_MakeAvailable(my_helpers)
    include(MyHelpers)
    

    where MyHelpers.cmake simply include()s all the other helpers.