Skip to content

Commit

Permalink
CMake: option to use cxx_std_11 (minimum) that propagates. (#986)
Browse files Browse the repository at this point in the history
See #259 for context.

This change introduces the ABSL_PROPAGATE_CXX_STD option (default to OFF for now, though it prints a warning in CMake 2.8+ builds that a future Abseil release will default to ON). When enabled, all Abseil CMake targets will set the cxx_std_11 target meta feature (which will then propagate to targets that depend upon Abseil) rather than setting the target-level CXX_STANDARD property to CMAKE_CXX_STANDARD (which is the default value anyway), which doesn't propagate.

Updates README documentation to clarify behavior and with a different example recommendation for library projects (which should generally leave CMAKE_CXX_STANDARD to the root application project).

See https://crascit.com/2015/03/28/enabling-cxx11-in-cmake/ for a useful overview of these different CMake features surrounding C++ standard version configuration.
  • Loading branch information
Lindurion authored Jul 30, 2021
1 parent 89c531c commit ee0ebda
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 9 deletions.
49 changes: 44 additions & 5 deletions CMake/AbseilHelpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,23 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/internal)
endif()

# INTERFACE libraries can't have the CXX_STANDARD property set
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
if(ABSL_PROPAGATE_CXX_STD)
# Abseil libraries require C++11 as the current minimum standard.
# Top-level application CMake projects should ensure a consistent C++
# standard for all compiled sources by setting CMAKE_CXX_STANDARD.
target_compile_features(${_NAME} PUBLIC cxx_std_11)
else()
# Note: This is legacy (before CMake 3.8) behavior. Setting the
# target-level CXX_STANDARD property to ABSL_CXX_STANDARD (which is
# initialized by CMAKE_CXX_STANDARD) should have no real effect, since
# that is the default value anyway.
#
# CXX_STANDARD_REQUIRED does guard against the top-level CMake project
# not having enabled CMAKE_CXX_STANDARD_REQUIRED (which prevents
# "decaying" to an older standard if the requested one isn't available).
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
endif()

# When being installed, we lose the absl_ prefix. We want to put it back
# to have properly named lib files. This is a no-op when we are not being
Expand Down Expand Up @@ -287,6 +301,16 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
${ABSL_DEFAULT_LINKOPTS}
)
target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES})

if(ABSL_PROPAGATE_CXX_STD)
# Abseil libraries require C++11 as the current minimum standard.
# Top-level application CMake projects should ensure a consistent C++
# standard for all compiled sources by setting CMAKE_CXX_STANDARD.
target_compile_features(${_NAME} INTERFACE cxx_std_11)

# (INTERFACE libraries can't have the CXX_STANDARD property set, so there
# is no legacy behavior else case).
endif()
endif()

# TODO currently we don't install googletest alongside abseil sources, so
Expand Down Expand Up @@ -390,8 +414,23 @@ function(absl_cc_test)
# Add all Abseil targets to a folder in the IDE for organization.
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test)

set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
if(ABSL_PROPAGATE_CXX_STD)
# Abseil libraries require C++11 as the current minimum standard.
# Top-level application CMake projects should ensure a consistent C++
# standard for all compiled sources by setting CMAKE_CXX_STANDARD.
target_compile_features(${_NAME} PUBLIC cxx_std_11)
else()
# Note: This is legacy (before CMake 3.8) behavior. Setting the
# target-level CXX_STANDARD property to ABSL_CXX_STANDARD (which is
# initialized by CMAKE_CXX_STANDARD) should have no real effect, since
# that is the default value anyway.
#
# CXX_STANDARD_REQUIRED does guard against the top-level CMake project
# not having enabled CMAKE_CXX_STANDARD_REQUIRED (which prevents
# "decaying" to an older standard if the requested one isn't available).
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
endif()

add_test(NAME ${_NAME} COMMAND ${_NAME})
endfunction()
Expand Down
45 changes: 42 additions & 3 deletions CMake/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,61 @@ to include Abseil directly in your CMake project.
4. Add the **absl::** target you wish to use to the
[`target_link_libraries()`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html)
section of your executable or of your library.<br>
Here is a short CMakeLists.txt example of a project file using Abseil.
Here is a short CMakeLists.txt example of an application project using Abseil.

```cmake
cmake_minimum_required(VERSION 3.5)
project(my_project)
cmake_minimum_required(VERSION 3.8.2)
project(my_app_project)
# Pick the C++ standard to compile with.
# Abseil currently supports C++11, C++14, and C++17.
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(abseil-cpp)
add_executable(my_exe source.cpp)
target_link_libraries(my_exe absl::base absl::synchronization absl::strings)
```

Note that if you are developing a library designed for use by other clients, you
should instead leave `CMAKE_CXX_STANDARD` unset (or only set if being built as
the current top-level CMake project) and configure the minimum required C++
standard at the target level. If you require a later minimum C++ standard than
Abseil does, it's a good idea to also enforce that `CMAKE_CXX_STANDARD` (which
will control Abseil library targets) is set to at least that minimum. For
example:

```cmake
cmake_minimum_required(VERSION 3.8.2)
project(my_lib_project)
# Leave C++ standard up to the root application, so set it only if this is the
# current top-level CMake project.
if(CMAKE_SOURCE_DIR STREQUAL my_lib_project_SOURCE_DIR)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
add_subdirectory(abseil-cpp)
add_library(my_lib source.cpp)
target_link_libraries(my_lib absl::base absl::synchronization absl::strings)
# Enforce that my_lib requires C++17. Important to document for clients that they
# must set CMAKE_CXX_STANDARD to 17 or higher for proper Abseil ABI compatibility
# (since otherwise, Abseil library targets could be compiled with a lower C++
# standard than my_lib).
target_compile_features(my_lib PUBLIC cxx_std_17)
if(CMAKE_CXX_STANDARD LESS 17)
message(FATAL_ERROR
"my_lib_project requires CMAKE_CXX_STANDARD >= 17 (got: ${CMAKE_CXX_STANDARD})")
endif()
```

Then the top-level application project that uses your library is responsible for
setting a consistent `CMAKE_CXX_STANDARD` that is sufficiently high.

### Running Abseil Tests with CMake

Use the `-DBUILD_TESTING=ON` flag to run Abseil tests.
Expand Down
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ else()
option(ABSL_ENABLE_INSTALL "Enable install rule" ON)
endif()

option(ABSL_PROPAGATE_CXX_STD
"Use CMake C++ standard meta features (e.g. cxx_std_11) that propagate to targets that link to Abseil"
OFF) # TODO: Default to ON for CMake 3.8 and greater.
if((${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.8) AND (NOT ABSL_PROPAGATE_CXX_STD))
message(WARNING "A future Abseil release will default ABSL_PROPAGATE_CXX_STD to ON for CMake 3.8 and up. We recommend enabling this option to ensure your project still builds correctly.")
endif()

list(APPEND CMAKE_MODULE_PATH
${CMAKE_CURRENT_LIST_DIR}/CMake
${CMAKE_CURRENT_LIST_DIR}/absl/copts
Expand Down
5 changes: 4 additions & 1 deletion FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ compiler, there several ways to do this:
file](https://docs.bazel.build/versions/master/guide.html#bazelrc)

If you are using CMake as the build system, you'll need to add a line like
`set(CMAKE_CXX_STANDARD 17)` to your top level `CMakeLists.txt` file. See the
`set(CMAKE_CXX_STANDARD 17)` to your top level `CMakeLists.txt` file. If you
are developing a library designed to be used by other clients, you should
instead leave `CMAKE_CXX_STANDARD` unset and configure the minimum C++ standard
required by each of your library targets via `target_compile_features`. See the
[CMake build
instructions](https://github.com/abseil/abseil-cpp/blob/master/CMake/README.md)
for more information.
Expand Down

0 comments on commit ee0ebda

Please sign in to comment.