Skip to content

Commit ee0ebda

Browse files
authored
CMake: option to use cxx_std_11 (minimum) that propagates. (abseil#986)
See abseil#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.
1 parent 89c531c commit ee0ebda

File tree

4 files changed

+97
-9
lines changed

4 files changed

+97
-9
lines changed

CMake/AbseilHelpers.cmake

+44-5
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,23 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
254254
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/internal)
255255
endif()
256256

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

261275
# When being installed, we lose the absl_ prefix. We want to put it back
262276
# to have properly named lib files. This is a no-op when we are not being
@@ -287,6 +301,16 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
287301
${ABSL_DEFAULT_LINKOPTS}
288302
)
289303
target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES})
304+
305+
if(ABSL_PROPAGATE_CXX_STD)
306+
# Abseil libraries require C++11 as the current minimum standard.
307+
# Top-level application CMake projects should ensure a consistent C++
308+
# standard for all compiled sources by setting CMAKE_CXX_STANDARD.
309+
target_compile_features(${_NAME} INTERFACE cxx_std_11)
310+
311+
# (INTERFACE libraries can't have the CXX_STANDARD property set, so there
312+
# is no legacy behavior else case).
313+
endif()
290314
endif()
291315

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

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

396435
add_test(NAME ${_NAME} COMMAND ${_NAME})
397436
endfunction()

CMake/README.md

+42-3
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,61 @@ to include Abseil directly in your CMake project.
3434
4. Add the **absl::** target you wish to use to the
3535
[`target_link_libraries()`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html)
3636
section of your executable or of your library.<br>
37-
Here is a short CMakeLists.txt example of a project file using Abseil.
37+
Here is a short CMakeLists.txt example of an application project using Abseil.
3838

3939
```cmake
40-
cmake_minimum_required(VERSION 3.5)
41-
project(my_project)
40+
cmake_minimum_required(VERSION 3.8.2)
41+
project(my_app_project)
4242
4343
# Pick the C++ standard to compile with.
4444
# Abseil currently supports C++11, C++14, and C++17.
4545
set(CMAKE_CXX_STANDARD 11)
46+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
4647
4748
add_subdirectory(abseil-cpp)
4849
4950
add_executable(my_exe source.cpp)
5051
target_link_libraries(my_exe absl::base absl::synchronization absl::strings)
5152
```
5253

54+
Note that if you are developing a library designed for use by other clients, you
55+
should instead leave `CMAKE_CXX_STANDARD` unset (or only set if being built as
56+
the current top-level CMake project) and configure the minimum required C++
57+
standard at the target level. If you require a later minimum C++ standard than
58+
Abseil does, it's a good idea to also enforce that `CMAKE_CXX_STANDARD` (which
59+
will control Abseil library targets) is set to at least that minimum. For
60+
example:
61+
62+
```cmake
63+
cmake_minimum_required(VERSION 3.8.2)
64+
project(my_lib_project)
65+
66+
# Leave C++ standard up to the root application, so set it only if this is the
67+
# current top-level CMake project.
68+
if(CMAKE_SOURCE_DIR STREQUAL my_lib_project_SOURCE_DIR)
69+
set(CMAKE_CXX_STANDARD 17)
70+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
71+
endif()
72+
73+
add_subdirectory(abseil-cpp)
74+
75+
add_library(my_lib source.cpp)
76+
target_link_libraries(my_lib absl::base absl::synchronization absl::strings)
77+
78+
# Enforce that my_lib requires C++17. Important to document for clients that they
79+
# must set CMAKE_CXX_STANDARD to 17 or higher for proper Abseil ABI compatibility
80+
# (since otherwise, Abseil library targets could be compiled with a lower C++
81+
# standard than my_lib).
82+
target_compile_features(my_lib PUBLIC cxx_std_17)
83+
if(CMAKE_CXX_STANDARD LESS 17)
84+
message(FATAL_ERROR
85+
"my_lib_project requires CMAKE_CXX_STANDARD >= 17 (got: ${CMAKE_CXX_STANDARD})")
86+
endif()
87+
```
88+
89+
Then the top-level application project that uses your library is responsible for
90+
setting a consistent `CMAKE_CXX_STANDARD` that is sufficiently high.
91+
5392
### Running Abseil Tests with CMake
5493

5594
Use the `-DBUILD_TESTING=ON` flag to run Abseil tests.

CMakeLists.txt

+7
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ else()
6767
option(ABSL_ENABLE_INSTALL "Enable install rule" ON)
6868
endif()
6969

70+
option(ABSL_PROPAGATE_CXX_STD
71+
"Use CMake C++ standard meta features (e.g. cxx_std_11) that propagate to targets that link to Abseil"
72+
OFF) # TODO: Default to ON for CMake 3.8 and greater.
73+
if((${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.8) AND (NOT ABSL_PROPAGATE_CXX_STD))
74+
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.")
75+
endif()
76+
7077
list(APPEND CMAKE_MODULE_PATH
7178
${CMAKE_CURRENT_LIST_DIR}/CMake
7279
${CMAKE_CURRENT_LIST_DIR}/absl/copts

FAQ.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ compiler, there several ways to do this:
2727
file](https://docs.bazel.build/versions/master/guide.html#bazelrc)
2828

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

0 commit comments

Comments
 (0)