5

I have a CMake Project Foobar that contains a subdirectory examples that can also be used as a stand-alone CMake build. To do that this sub-directory performs a find_package(Foobar) and uses the exported targets. Foobar provides a FoobarConfig.cmake, FoobarConfigVersion.cmake, and a FoobarExports.cmake and can be used without a FindModule.

The code roughly looks like this:

### Top-Level CMakeLists.txt ###
cmake_minimum_required(VERSION 3.0.0)
project(Foobar)

add_library(X SHARED ${my_sources})
install(TARGETS X EXPORT FoobarExports
  LIBRARY DESTINATION ${my_install_destination})
install(EXPORT FoobarExports DESTINATION ${my_install_destination})
# Create the FoobarExports.cmake for the local build tree
export(EXPORT FoobarExports) # the problematic command

# Setup FoobarConfig.cmake etc
# FoobarConfig.cmake includes FoobarExports.cmake
# ...

# Force find_package to FOOBAR_DIR
option(BUILD_EXAMPLES "Build examples" ON)
if(BUILD_EXAMPLES)
  set(FOOBAR_DIR "${CMAKE_BINARY_DIR}")
  add_subdirectory(examples)
endif()

### examples/CMakeLists.txt ###
cmake_minimum_required(VERSION 3.0.0)
project(FoobarExamples)
# Uses FOOBAR_DIR set above
find_package(Foobar NO_MODULE REQUIRED)

add_executable(my_exe ${some_sources})
# Use X from Foobar
target_link_library(my_exe X)

The problem is that export(EXPORT FoobarExports) will only create the FoobarExports.cmake file at the end of generation time to make sure it has the complete FoobarExports export set.

So this will fail:

cmake . -DBUILD_EXAMPLES=ON
# Error: FoobarExports.cmake not found

What works, however, is:

cmake .
cmake . -DBUILD_EXAMPLES=ON # rerun cmake with changed cache variable

How can I either force the FoobarExports.cmake file to be written at the time of the call to export or force CMake to run twice, if the file has not been created yet?

pmr
  • 58,701
  • 10
  • 113
  • 156

1 Answers1

4

You don't need to find anything if you're building your project as a subproject. Just check the target exists and if not, try to find it. Something like that:

### examples/CMakeLists.txt ###
cmake_minimum_required(VERSION 3.0.0)
project(FoobarExamples)

if(NOT TARGET X)
  find_package(Foobar CONFIG REQUIRED)
endif()

# Use X from Foobar
target_link_library(my_exe X)
  • I see where you are coming from. This has two side problems: it makes the CMakeLists.txt unnecessarily messy and I cannot just use `X` because I export targets with a namespace. And then the code would become even messier. – pmr Jul 10 '14 at 13:36
  • 3
    ALIAS targets are designed to solve that problem (since CMake 2.8.12). http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html#alias-targets – steveire Jul 10 '14 at 13:50
  • 1
    `it makes the CMakeLists.txt unnecessarily messy` IMHO one `if` command is not messy –  Jul 10 '14 at 14:14
  • @steveire I completely forgot about `ALIAS` targets. Thanks. – pmr Jul 10 '14 at 15:30