1# 2# Copyright 2017 The Abseil Authors. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# https://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# 16 17include(CMakeParseArguments) 18include(AbseilConfigureCopts) 19include(AbseilDll) 20 21# The IDE folder for Abseil that will be used if Abseil is included in a CMake 22# project that sets 23# set_property(GLOBAL PROPERTY USE_FOLDERS ON) 24# For example, Visual Studio supports folders. 25if(NOT DEFINED ABSL_IDE_FOLDER) 26 set(ABSL_IDE_FOLDER Abseil) 27endif() 28 29# absl_cc_library() 30# 31# CMake function to imitate Bazel's cc_library rule. 32# 33# Parameters: 34# NAME: name of target (see Note) 35# HDRS: List of public header files for the library 36# SRCS: List of source files for the library 37# DEPS: List of other libraries to be linked in to the binary targets 38# COPTS: List of private compile options 39# DEFINES: List of public defines 40# LINKOPTS: List of link options 41# PUBLIC: Add this so that this library will be exported under absl:: 42# Also in IDE, target will appear in Abseil folder while non PUBLIC will be in Abseil/internal. 43# TESTONLY: When added, this target will only be built if BUILD_TESTING=ON. 44# 45# Note: 46# By default, absl_cc_library will always create a library named absl_${NAME}, 47# and alias target absl::${NAME}. The absl:: form should always be used. 48# This is to reduce namespace pollution. 49# 50# absl_cc_library( 51# NAME 52# awesome 53# HDRS 54# "a.h" 55# SRCS 56# "a.cc" 57# ) 58# absl_cc_library( 59# NAME 60# fantastic_lib 61# SRCS 62# "b.cc" 63# DEPS 64# absl::awesome # not "awesome" ! 65# PUBLIC 66# ) 67# 68# absl_cc_library( 69# NAME 70# main_lib 71# ... 72# DEPS 73# absl::fantastic_lib 74# ) 75# 76# TODO: Implement "ALWAYSLINK" 77function(absl_cc_library) 78 cmake_parse_arguments(ABSL_CC_LIB 79 "DISABLE_INSTALL;PUBLIC;TESTONLY" 80 "NAME" 81 "HDRS;SRCS;COPTS;DEFINES;LINKOPTS;DEPS" 82 ${ARGN} 83 ) 84 85 if(ABSL_CC_LIB_TESTONLY AND NOT BUILD_TESTING) 86 return() 87 endif() 88 89 if(ABSL_ENABLE_INSTALL) 90 set(_NAME "${ABSL_CC_LIB_NAME}") 91 else() 92 set(_NAME "absl_${ABSL_CC_LIB_NAME}") 93 endif() 94 95 # Check if this is a header-only library 96 # Note that as of February 2019, many popular OS's (for example, Ubuntu 97 # 16.04 LTS) only come with cmake 3.5 by default. For this reason, we can't 98 # use list(FILTER...) 99 set(ABSL_CC_SRCS "${ABSL_CC_LIB_SRCS}") 100 foreach(src_file IN LISTS ABSL_CC_SRCS) 101 if(${src_file} MATCHES ".*\\.(h|inc)") 102 list(REMOVE_ITEM ABSL_CC_SRCS "${src_file}") 103 endif() 104 endforeach() 105 106 if(ABSL_CC_SRCS STREQUAL "") 107 set(ABSL_CC_LIB_IS_INTERFACE 1) 108 else() 109 set(ABSL_CC_LIB_IS_INTERFACE 0) 110 endif() 111 112 # Determine this build target's relationship to the DLL. It's one of four things: 113 # 1. "dll" -- This target is part of the DLL 114 # 2. "dll_dep" -- This target is not part of the DLL, but depends on the DLL. 115 # Note that we assume any target not in the DLL depends on the 116 # DLL. This is not a technical necessity but a convenience 117 # which happens to be true, because nearly every target is 118 # part of the DLL. 119 # 3. "shared" -- This is a shared library, perhaps on a non-windows platform 120 # where DLL doesn't make sense. 121 # 4. "static" -- This target does not depend on the DLL and should be built 122 # statically. 123 if (${ABSL_BUILD_DLL}) 124 if(ABSL_ENABLE_INSTALL) 125 absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll) 126 else() 127 absl_internal_dll_contains(TARGET ${ABSL_CC_LIB_NAME} OUTPUT _in_dll) 128 endif() 129 if (${_in_dll}) 130 # This target should be replaced by the DLL 131 set(_build_type "dll") 132 set(ABSL_CC_LIB_IS_INTERFACE 1) 133 else() 134 # Building a DLL, but this target is not part of the DLL 135 set(_build_type "dll_dep") 136 endif() 137 elseif(BUILD_SHARED_LIBS) 138 set(_build_type "shared") 139 else() 140 set(_build_type "static") 141 endif() 142 143 # Generate a pkg-config file for every library: 144 if((_build_type STREQUAL "static" OR _build_type STREQUAL "shared") 145 AND ABSL_ENABLE_INSTALL) 146 if(NOT ABSL_CC_LIB_TESTONLY) 147 if(absl_VERSION) 148 set(PC_VERSION "${absl_VERSION}") 149 else() 150 set(PC_VERSION "head") 151 endif() 152 foreach(dep ${ABSL_CC_LIB_DEPS}) 153 if(${dep} MATCHES "^absl::(.*)") 154 # Join deps with commas. 155 if(PC_DEPS) 156 set(PC_DEPS "${PC_DEPS},") 157 endif() 158 set(PC_DEPS "${PC_DEPS} absl_${CMAKE_MATCH_1} = ${PC_VERSION}") 159 endif() 160 endforeach() 161 foreach(cflag ${ABSL_CC_LIB_COPTS}) 162 if(${cflag} MATCHES "^(-Wno|/wd)") 163 # These flags are needed to suppress warnings that might fire in our headers. 164 set(PC_CFLAGS "${PC_CFLAGS} ${cflag}") 165 elseif(${cflag} MATCHES "^(-W|/w[1234eo])") 166 # Don't impose our warnings on others. 167 else() 168 set(PC_CFLAGS "${PC_CFLAGS} ${cflag}") 169 endif() 170 endforeach() 171 FILE(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc" CONTENT "\ 172prefix=${CMAKE_INSTALL_PREFIX}\n\ 173exec_prefix=\${prefix}\n\ 174libdir=${CMAKE_INSTALL_FULL_LIBDIR}\n\ 175includedir=${CMAKE_INSTALL_FULL_INCLUDEDIR}\n\ 176\n\ 177Name: absl_${_NAME}\n\ 178Description: Abseil ${_NAME} library\n\ 179URL: https://abseil.io/\n\ 180Version: ${PC_VERSION}\n\ 181Requires:${PC_DEPS}\n\ 182Libs: -L\${libdir} $<JOIN:${ABSL_CC_LIB_LINKOPTS}, > $<$<NOT:$<BOOL:${ABSL_CC_LIB_IS_INTERFACE}>>:-labsl_${_NAME}>\n\ 183Cflags: -I\${includedir}${PC_CFLAGS}\n") 184 INSTALL(FILES "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc" 185 DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") 186 endif() 187 endif() 188 189 if(NOT ABSL_CC_LIB_IS_INTERFACE) 190 if(_build_type STREQUAL "dll_dep") 191 # This target depends on the DLL. When adding dependencies to this target, 192 # any depended-on-target which is contained inside the DLL is replaced 193 # with a dependency on the DLL. 194 add_library(${_NAME} STATIC "") 195 target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS}) 196 absl_internal_dll_targets( 197 DEPS ${ABSL_CC_LIB_DEPS} 198 OUTPUT _dll_deps 199 ) 200 target_link_libraries(${_NAME} 201 PUBLIC ${_dll_deps} 202 PRIVATE 203 ${ABSL_CC_LIB_LINKOPTS} 204 ${ABSL_DEFAULT_LINKOPTS} 205 ) 206 207 if (ABSL_CC_LIB_TESTONLY) 208 set(_gtest_link_define "GTEST_LINKED_AS_SHARED_LIBRARY=1") 209 else() 210 set(_gtest_link_define) 211 endif() 212 213 target_compile_definitions(${_NAME} 214 PUBLIC 215 ABSL_CONSUME_DLL 216 "${_gtest_link_define}" 217 ) 218 219 elseif(_build_type STREQUAL "static" OR _build_type STREQUAL "shared") 220 add_library(${_NAME} "") 221 target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS}) 222 target_link_libraries(${_NAME} 223 PUBLIC ${ABSL_CC_LIB_DEPS} 224 PRIVATE 225 ${ABSL_CC_LIB_LINKOPTS} 226 ${ABSL_DEFAULT_LINKOPTS} 227 ) 228 else() 229 message(FATAL_ERROR "Invalid build type: ${_build_type}") 230 endif() 231 232 # Linker language can be inferred from sources, but in the case of DLLs we 233 # don't have any .cc files so it would be ambiguous. We could set it 234 # explicitly only in the case of DLLs but, because "CXX" is always the 235 # correct linker language for static or for shared libraries, we set it 236 # unconditionally. 237 set_property(TARGET ${_NAME} PROPERTY LINKER_LANGUAGE "CXX") 238 239 target_include_directories(${_NAME} 240 PUBLIC 241 "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>" 242 $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> 243 ) 244 target_compile_options(${_NAME} 245 PRIVATE ${ABSL_CC_LIB_COPTS}) 246 target_compile_definitions(${_NAME} PUBLIC ${ABSL_CC_LIB_DEFINES}) 247 248 # Add all Abseil targets to a a folder in the IDE for organization. 249 if(ABSL_CC_LIB_PUBLIC) 250 set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}) 251 elseif(ABSL_CC_LIB_TESTONLY) 252 set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test) 253 else() 254 set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/internal) 255 endif() 256 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() 274 275 # When being installed, we lose the absl_ prefix. We want to put it back 276 # to have properly named lib files. This is a no-op when we are not being 277 # installed. 278 if(ABSL_ENABLE_INSTALL) 279 set_target_properties(${_NAME} PROPERTIES 280 OUTPUT_NAME "absl_${_NAME}" 281 SOVERSION "2111.0.0" 282 ) 283 endif() 284 else() 285 # Generating header-only library 286 add_library(${_NAME} INTERFACE) 287 target_include_directories(${_NAME} 288 INTERFACE 289 "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>" 290 $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> 291 ) 292 293 if (_build_type STREQUAL "dll") 294 set(ABSL_CC_LIB_DEPS abseil_dll) 295 endif() 296 297 target_link_libraries(${_NAME} 298 INTERFACE 299 ${ABSL_CC_LIB_DEPS} 300 ${ABSL_CC_LIB_LINKOPTS} 301 ${ABSL_DEFAULT_LINKOPTS} 302 ) 303 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() 314 endif() 315 316 # TODO currently we don't install googletest alongside abseil sources, so 317 # installed abseil can't be tested. 318 if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL) 319 install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets 320 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 321 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 322 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 323 ) 324 endif() 325 326 add_library(absl::${ABSL_CC_LIB_NAME} ALIAS ${_NAME}) 327endfunction() 328 329# absl_cc_test() 330# 331# CMake function to imitate Bazel's cc_test rule. 332# 333# Parameters: 334# NAME: name of target (see Usage below) 335# SRCS: List of source files for the binary 336# DEPS: List of other libraries to be linked in to the binary targets 337# COPTS: List of private compile options 338# DEFINES: List of public defines 339# LINKOPTS: List of link options 340# 341# Note: 342# By default, absl_cc_test will always create a binary named absl_${NAME}. 343# This will also add it to ctest list as absl_${NAME}. 344# 345# Usage: 346# absl_cc_library( 347# NAME 348# awesome 349# HDRS 350# "a.h" 351# SRCS 352# "a.cc" 353# PUBLIC 354# ) 355# 356# absl_cc_test( 357# NAME 358# awesome_test 359# SRCS 360# "awesome_test.cc" 361# DEPS 362# absl::awesome 363# GTest::gmock 364# GTest::gtest_main 365# ) 366function(absl_cc_test) 367 if(NOT BUILD_TESTING) 368 return() 369 endif() 370 371 cmake_parse_arguments(ABSL_CC_TEST 372 "" 373 "NAME" 374 "SRCS;COPTS;DEFINES;LINKOPTS;DEPS" 375 ${ARGN} 376 ) 377 378 set(_NAME "absl_${ABSL_CC_TEST_NAME}") 379 380 add_executable(${_NAME} "") 381 target_sources(${_NAME} PRIVATE ${ABSL_CC_TEST_SRCS}) 382 target_include_directories(${_NAME} 383 PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} 384 PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS} 385 ) 386 387 if (${ABSL_BUILD_DLL}) 388 target_compile_definitions(${_NAME} 389 PUBLIC 390 ${ABSL_CC_TEST_DEFINES} 391 ABSL_CONSUME_DLL 392 GTEST_LINKED_AS_SHARED_LIBRARY=1 393 ) 394 395 # Replace dependencies on targets inside the DLL with abseil_dll itself. 396 absl_internal_dll_targets( 397 DEPS ${ABSL_CC_TEST_DEPS} 398 OUTPUT ABSL_CC_TEST_DEPS 399 ) 400 else() 401 target_compile_definitions(${_NAME} 402 PUBLIC 403 ${ABSL_CC_TEST_DEFINES} 404 ) 405 endif() 406 target_compile_options(${_NAME} 407 PRIVATE ${ABSL_CC_TEST_COPTS} 408 ) 409 410 target_link_libraries(${_NAME} 411 PUBLIC ${ABSL_CC_TEST_DEPS} 412 PRIVATE ${ABSL_CC_TEST_LINKOPTS} 413 ) 414 # Add all Abseil targets to a folder in the IDE for organization. 415 set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test) 416 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() 434 435 add_test(NAME ${_NAME} COMMAND ${_NAME}) 436endfunction() 437 438 439function(check_target my_target) 440 if(NOT TARGET ${my_target}) 441 message(FATAL_ERROR " ABSL: compiling absl requires a ${my_target} CMake target in your project, 442 see CMake/README.md for more details") 443 endif(NOT TARGET ${my_target}) 444endfunction() 445