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 targets:
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 exist yet when CMakeLists of Project B is run.
Is there a way to make the include dependent on the external project being built?
I think you're mixing up two different paradigms here.
As you noted, the highly flexible
ExternalProject
module runs its commands at build time, so you can't make direct use of Project A's import file since it's only created once Project A has been installed.If you want to
include
Project A's import file, you'll have to install Project A manually before invoking Project B's CMakeLists.txt - just like any other third-party dependency added this way or viafind_file
/find_library
/find_package
.If you want to make use of
ExternalProject_Add
, you'll need to add something like the following to your CMakeLists.txt:This post has a reasonable answer:
CMakeLists.txt.in
:CMakeLists.txt
:However it does seem quite hacky. I'd like to propose an alternative solution - use Git submodules.
Then in
MyProject/dependencies/gtest/CMakeList.txt
you can do something like:I haven't tried this extensively yet but it seems cleaner.
Edit: There is a downside to this approach: The subdirectory might run
install()
commands that you don't want. This post has an approach to disable them but it was buggy and didn't work for me.Edit 2: If you use
add_subdirectory("googletest" EXCLUDE_FROM_ALL)
it seems means theinstall()
commands in the subdirectory aren't used by default.You can also force the build of the dependent target in a secondary make process
See my answer on a related topic.
What you could try and do is use cmake's export command within your
project_a
. It works a little bit different then usinginstall
command with theEXPORT option
in that it produces your aproject_a-targets.cmake
file when running cmake. The generated import targets within theproject_a-targets.cmake
file point to initially the none existing library files within your project's binary directory that will be generated only after your run the build command.To better understand that I'm talking about, simply create a small cmake project that creates a simple library followed by the export command (the code below hasn't been tested):
After running the cmake command on your simple example, you should be able to find the
project_a-targets.cmake
inside your binary directory (or under one of its child folders). Inspecting the file, you might notice that it currently points to a none existing library file. Only after running the build command will the library be there.So going back to your problem, you will need to update the
project-a
'sCMakeLists.txt
to include theexport
command. Then you need to make sure that after theExternalProject_Add
is processed, it calls the configuration step, which will produce theproject_a-targets.cmake
, then you can invoke theinclude(.../project_a-targets.cmake)
which should work. Finally you will need to add a dependency betweenproject_b
andproject_a
so that it forcesproject_a
to be built before attempting to buildproject_b
.