0

I have the following reduced CMake code for using Abseil in a library: (minimal repository to reproduce)

cmake_minimum_required(VERSION 3.20)

project(MyProject)

set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")

set(ABSL_PROPAGATE_CXX_STD ON)
find_package(absl REQUIRED)

add_library(MyStaticLibTarget STATIC MyStaticLib.cpp)
target_link_libraries(MyStaticLibTarget absl::strings)

install(TARGETS MyStaticLibTarget EXPORT MyProjectTargets)
install(TARGETS strings EXPORT MyProjectTargets)

if(EXPORT_MYSTATICLIB)
  export(TARGETS MyStaticLibTarget FILE lib/cmake/MyProject/MyProjectTargets.cmake)
endif()

# Setup for downstream clients of MyProject?
install(EXPORT MyProjectTargets DESTINATION lib/cmake/MyProject COMPONENT cmake-exports)

However, I run into an error as shown if I try to use the export code path, when running CMake with:

cmake -G Ninja -S . -B build -DABSL_ENABLE_INSTALL=ON -DEXPORT_MYSTATICLIB=ON

# CMake Error in CMakeLists.txt:
# export called with target "MyStaticLibTarget" which requires target
#   "strings" that is not in any export set.

I don't understand the error message; it seems to me that strings is already part of MyProjectTargets (which I think is an export set?), so there shouldn't be any error.

That said, based on the error message, I tried adding an export line for strings, and transitively fixed all the errors, and I ended up with

export(TARGETS
  strings
  strings_internal
  type_traits
  base
  config
  throw_delegate
  dynamic_annotations
  log_severity
  base_internal
  raw_logging_internal
  atomic_hook
  core_headers
  spinlock_wait
  endian
  bits
  int128
  memory
  errno_saver
  meta
  APPEND FILE lib/cmake/MyProject/MyProjectTargets.cmake)

That does fix all errors! In practice, this would be very painful to do by hand for a larger library. It also seems like the "wrong" solution, because I am naming lots of internal details of Abseil by hand.

  1. Is manually adding the targets as above the "right" solution?
  2. Is there a better way to achieve the same result as above?

I have the following constraints:

  • I need to export MyStaticLibTarget so it can be used by downstream clients.
  • I'm pretty sure the dependency (in target_link_libraries) needs to be public, as in the actual case (this is a minimal example), Abseil headers will be included in the library's public headers.
typesanitizer
  • 2,505
  • 1
  • 20
  • 44
  • "it seems to me that `strings` is already part of `MyProjectTargets`" - `strings` is **linked** to `MyStaticLibTarget` but it is **not a part** of it."... because I am naming lots of internal details of Abseil by hand." - Because you include Abseil via `add_subdirectory`, Abseil internals becomes **internals of your project**. Do not be confused with using `find_package(absl)`: it executes **your script** [Findabsl.cmake](https://github.com/typesanitizer/mwe-abseil-export/blob/main/cmake/modules/Findabsl.cmake) which internally includes Abseil via `FetchContent_Add`/`add_subdirectory`. – Tsyvarev Nov 05 '21 at 09:23
  • If you want to truly abstract from the Abseil internals, then **install** Abseil first. After that `find_package(absl)` will be able to find Abseil without handy-written scripts. When export your project, you will be able to just add `find_dependency(absl)` call into your export script. – Tsyvarev Nov 05 '21 at 10:01

1 Answers1

0

TLDR: Follow the Conan docs, especially the cmake_find_package docs and skim the cheatsheet.

Following @Tsyvarev's advice in the comments, I used a different setup and made this work, you can see the final result in conan branch.

The steps are as follows:

  1. Use Conan to download and install Abseil, using a project-local conanfile.txt. Now, "install" is a scary word (I did not want to modify global state), but Conan essentially just caches sources and build artifacts, which means that you can have multiple versions of the same libraries in different directories, and different projects can use these different versions, and it should "just work". (At least, that's my basic understanding so far.)
    [requires]         # Which 3rd party conan packages we are using
    abseil/20210324.2
    
    [generators]       # How to create build system files that capture the dependency information
    cmake_find_package
    cmake_paths
    
    With the above configuration, Conan can be run:
    conan install . --install-folder build/conan
    # Bunch of CMake files will be available under build/conan
    
  2. Point CMake to Conan-generated files by adding a line to CMakeLists.txt.
    include("${CMAKE_BINARY_DIR}/conan/conan_paths.cmake")
    
  3. Configure normally using CMake.
    cmake -G Ninja -S . -B build -DEXPORT_MYSTATICLIB=ON
    
    (The ABSL_ENABLE_INSTALL option is handled by Conan and is no longer needed.)
typesanitizer
  • 2,505
  • 1
  • 20
  • 44