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 absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll) 126 if (${_in_dll}) 127 # This target should be replaced by the DLL 128 set(_build_type "dll") 129 set(ABSL_CC_LIB_IS_INTERFACE 1) 130 else() 131 # Building a DLL, but this target is not part of the DLL 132 set(_build_type "dll_dep") 133 endif() 134 elseif(BUILD_SHARED_LIBS) 135 set(_build_type "shared") 136 else() 137 set(_build_type "static") 138 endif() 139 140 if(NOT ABSL_CC_LIB_IS_INTERFACE) 141 if(${_build_type} STREQUAL "dll_dep") 142 # This target depends on the DLL. When adding dependencies to this target, 143 # any depended-on-target which is contained inside the DLL is replaced 144 # with a dependency on the DLL. 145 add_library(${_NAME} STATIC "") 146 target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS}) 147 absl_internal_dll_targets( 148 DEPS ${ABSL_CC_LIB_DEPS} 149 OUTPUT _dll_deps 150 ) 151 target_link_libraries(${_NAME} 152 PUBLIC ${_dll_deps} 153 PRIVATE 154 ${ABSL_CC_LIB_LINKOPTS} 155 ${ABSL_DEFAULT_LINKOPTS} 156 ) 157 158 if (ABSL_CC_LIB_TESTONLY) 159 set(_gtest_link_define "GTEST_LINKED_AS_SHARED_LIBRARY=1") 160 else() 161 set(_gtest_link_define) 162 endif() 163 164 target_compile_definitions(${_NAME} 165 PUBLIC 166 ABSL_CONSUME_DLL 167 "${_gtest_link_define}" 168 ) 169 170 elseif(${_build_type} STREQUAL "static" OR ${_build_type} STREQUAL "shared") 171 add_library(${_NAME} "") 172 target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS}) 173 target_link_libraries(${_NAME} 174 PUBLIC ${ABSL_CC_LIB_DEPS} 175 PRIVATE 176 ${ABSL_CC_LIB_LINKOPTS} 177 ${ABSL_DEFAULT_LINKOPTS} 178 ) 179 else() 180 message(FATAL_ERROR "Invalid build type: ${_build_type}") 181 endif() 182 183 # Linker language can be inferred from sources, but in the case of DLLs we 184 # don't have any .cc files so it would be ambiguous. We could set it 185 # explicitly only in the case of DLLs but, because "CXX" is always the 186 # correct linker language for static or for shared libraries, we set it 187 # unconditionally. 188 set_property(TARGET ${_NAME} PROPERTY LINKER_LANGUAGE "CXX") 189 190 target_include_directories(${_NAME} 191 PUBLIC 192 "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>" 193 $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}> 194 ) 195 target_compile_options(${_NAME} 196 PRIVATE ${ABSL_CC_LIB_COPTS}) 197 target_compile_definitions(${_NAME} PUBLIC ${ABSL_CC_LIB_DEFINES}) 198 199 # Add all Abseil targets to a a folder in the IDE for organization. 200 if(ABSL_CC_LIB_PUBLIC) 201 set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}) 202 elseif(ABSL_CC_LIB_TESTONLY) 203 set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test) 204 else() 205 set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/internal) 206 endif() 207 208 # INTERFACE libraries can't have the CXX_STANDARD property set 209 set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD}) 210 set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) 211 212 # When being installed, we lose the absl_ prefix. We want to put it back 213 # to have properly named lib files. This is a no-op when we are not being 214 # installed. 215 if(ABSL_ENABLE_INSTALL) 216 set_target_properties(${_NAME} PROPERTIES 217 OUTPUT_NAME "absl_${_NAME}" 218 ) 219 endif() 220 else() 221 # Generating header-only library 222 add_library(${_NAME} INTERFACE) 223 target_include_directories(${_NAME} 224 INTERFACE 225 "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>" 226 $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}> 227 ) 228 229 if (${_build_type} STREQUAL "dll") 230 set(ABSL_CC_LIB_DEPS abseil_dll) 231 endif() 232 233 target_link_libraries(${_NAME} 234 INTERFACE 235 ${ABSL_CC_LIB_DEPS} 236 ${ABSL_CC_LIB_LINKOPTS} 237 ${ABSL_DEFAULT_LINKOPTS} 238 ) 239 target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES}) 240 endif() 241 242 # TODO currently we don't install googletest alongside abseil sources, so 243 # installed abseil can't be tested. 244 if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL) 245 install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets 246 RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR} 247 LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR} 248 ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR} 249 ) 250 endif() 251 252 add_library(absl::${ABSL_CC_LIB_NAME} ALIAS ${_NAME}) 253endfunction() 254 255# absl_cc_test() 256# 257# CMake function to imitate Bazel's cc_test rule. 258# 259# Parameters: 260# NAME: name of target (see Usage below) 261# SRCS: List of source files for the binary 262# DEPS: List of other libraries to be linked in to the binary targets 263# COPTS: List of private compile options 264# DEFINES: List of public defines 265# LINKOPTS: List of link options 266# 267# Note: 268# By default, absl_cc_test will always create a binary named absl_${NAME}. 269# This will also add it to ctest list as absl_${NAME}. 270# 271# Usage: 272# absl_cc_library( 273# NAME 274# awesome 275# HDRS 276# "a.h" 277# SRCS 278# "a.cc" 279# PUBLIC 280# ) 281# 282# absl_cc_test( 283# NAME 284# awesome_test 285# SRCS 286# "awesome_test.cc" 287# DEPS 288# absl::awesome 289# gmock 290# gtest_main 291# ) 292function(absl_cc_test) 293 if(NOT ABSL_RUN_TESTS) 294 return() 295 endif() 296 297 cmake_parse_arguments(ABSL_CC_TEST 298 "" 299 "NAME" 300 "SRCS;COPTS;DEFINES;LINKOPTS;DEPS" 301 ${ARGN} 302 ) 303 304 set(_NAME "absl_${ABSL_CC_TEST_NAME}") 305 306 add_executable(${_NAME} "") 307 target_sources(${_NAME} PRIVATE ${ABSL_CC_TEST_SRCS}) 308 target_include_directories(${_NAME} 309 PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} 310 PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS} 311 ) 312 313 if (${ABSL_BUILD_DLL}) 314 target_compile_definitions(${_NAME} 315 PUBLIC 316 ${ABSL_CC_TEST_DEFINES} 317 ABSL_CONSUME_DLL 318 GTEST_LINKED_AS_SHARED_LIBRARY=1 319 ) 320 321 # Replace dependencies on targets inside the DLL with abseil_dll itself. 322 absl_internal_dll_targets( 323 DEPS ${ABSL_CC_TEST_DEPS} 324 OUTPUT ABSL_CC_TEST_DEPS 325 ) 326 else() 327 target_compile_definitions(${_NAME} 328 PUBLIC 329 ${ABSL_CC_TEST_DEFINES} 330 ) 331 endif() 332 target_compile_options(${_NAME} 333 PRIVATE ${ABSL_CC_TEST_COPTS} 334 ) 335 336 target_link_libraries(${_NAME} 337 PUBLIC ${ABSL_CC_TEST_DEPS} 338 PRIVATE ${ABSL_CC_TEST_LINKOPTS} 339 ) 340 # Add all Abseil targets to a folder in the IDE for organization. 341 set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test) 342 343 set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD}) 344 set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) 345 346 add_test(NAME ${_NAME} COMMAND ${_NAME}) 347endfunction() 348 349 350function(check_target my_target) 351 if(NOT TARGET ${my_target}) 352 message(FATAL_ERROR " ABSL: compiling absl requires a ${my_target} CMake target in your project, 353 see CMake/README.md for more details") 354 endif(NOT TARGET ${my_target}) 355endfunction() 356