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