CMake: how to create external projects and include their goals

I have a project A that exports a static library as a target:

install(TARGETS alib DESTINATION lib EXPORT project_a-targets) install(EXPORT project_a-targets DESTINATION lib/alib) 

Now I want to use Project A as an external project from Project B and include its built-in goals:

 ExternalProject_Add(project_a URL ...project_a.tar.gz PREFIX ${CMAKE_CURRENT_BINARY_DIR}/project_a CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> ) include(${CMAKE_CURRENT_BINARY_DIR}/lib/project_a/project_a-targets.cmake) 

The problem is that the include file does not yet exist when you start CMakeLists in project B.

Is there a way to make inclusion dependent on an external project?

Update : I wrote a quick tutorial on CMake by Example, based on this and other common issues I encountered.

+93
cmake external-project
Mar 02 '13 at 13:59 on
source share
4 answers

I think you are mixing two different paradigms.

As you noted, the ExternalProject flexible module runs its commands during build, so you cannot directly use the Import file project, since it was created only after Project A was installed.

If you want to include the Project A Project File, you will need to install Project A manually before calling Project B CMakeLists.txt - like any other third-party dependency added this way, or through find_file / find_library / find_package .

If you want to use ExternalProject_Add , you need to add something like the following to your CMakeLists.txt:

 ExternalProject_Add(project_a URL ...project_a.tar.gz PREFIX ${CMAKE_CURRENT_BINARY_DIR}/project_a CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> ) include(${CMAKE_CURRENT_BINARY_DIR}/lib/project_a/project_a-targets.cmake) ExternalProject_Get_Property(project_a install_dir) include_directories(${install_dir}/include) add_dependencies(project_b_exe project_a) target_link_libraries(project_b_exe ${install_dir}/lib/alib.lib) 
+58
Mar 02 '13 at 15:22
source share

This post has a reasonable answer:

CMakeLists.txt.in :

 cmake_minimum_required(VERSION 2.8.2) project(googletest-download NONE) include(ExternalProject) ExternalProject_Add(googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG master SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src" BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "" ) 

CMakeLists.txt :

 # Download and unpack googletest at configure time configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) # Prevent GoogleTest from overriding our compiler/linker options # when building with Visual Studio set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) # Add googletest directly to our build. This adds # the following targets: gtest, gtest_main, gmock # and gmock_main add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src ${CMAKE_BINARY_DIR}/googletest-build) # The gtest/gmock targets carry header search path # dependencies automatically when using CMake 2.8.11 or # later. Otherwise we have to add them here ourselves. if (CMAKE_VERSION VERSION_LESS 2.8.11) include_directories("${gtest_SOURCE_DIR}/include" "${gmock_SOURCE_DIR}/include") endif() # Now simply link your own targets against gtest, gmock, # etc. as appropriate 

However, this seems rather hacky. I would like to suggest an alternative solution - use Git submodules.

 cd MyProject/dependencies/gtest git submodule add https://github.com/google/googletest.git cd googletest git checkout release-1.8.0 cd ../../.. git add * git commit -m "Add googletest" 

Then in MyProject/dependencies/gtest/CMakeList.txt you can do something like:

 cmake_minimum_required(VERSION 3.3) if(TARGET gtest) # To avoid diamond dependencies; may not be necessary depending on you project. return() endif() add_subdirectory("googletest") 

I haven't tried it extensively yet, but it seems cleaner.

Change: this approach has a downside: a subdirectory can run install() commands that you don’t need. There is an approach to disabling them in this post, but it was buggy and did not work for me.

Edit 2: If you use add_subdirectory("googletest" EXCLUDE_FROM_ALL) this means that the install() commands in the subdirectory are not used by default.

+17
Jan 23 '17 at 11:42 on
source share

You can also force build a dependent target in a secondary make process

See my answer on the topic.

+4
May 9 '14 at 20:09
source share

What you can try to do is use the cmake export command inside your project_a . It works a little differently than the install command with the EXPORT option in that project_a-targets.cmake when cmake starts, it creates your project_a-targets.cmake target.cmake file. The generated import targets in the project_a-targets.cmake initially point to non-existent library files in the binary directory of your project, which will be generated only after the build command is executed.

To better understand what I'm talking about, just create a small cmake project that creates a simple library and then an export command (the code below has not been tested):

 add_library (project_a lib.cpp) export ( TARGETS project_a FILE project_a-targets.cmake ) 

After running the cmake command in your simple example, you can find project_a-targets.cmake inside your binary directory (or in one of its child folders). Looking around the file, you may notice that at the moment it points to a nonexistent library file. Only after running the build command will there be a library.

So, getting back to your problem, you need to update project-a CMakeLists.txt include the export command in it. Then you need to make sure that after processing ExternalProject_Add it calls the configuration step that will create project_a-targets.cmake , then you can call include(.../project_a-targets.cmake) which should work. Finally, you will need to add a dependency between project_b and project_a so that it has project_a build project_b before trying to build project_b .

0
Nov 15 '18 at 23:45
source share



All Articles