blob: e88507de562cec7d955b39473d5867aaa4c679ff [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001#
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)
Austin Schuhb4691e92020-12-31 12:37:18 -080019include(AbseilDll)
Austin Schuh36244a12019-09-21 17:52:38 -070020include(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.
Austin Schuhb4691e92020-12-31 12:37:18 -080026if(NOT DEFINED ABSL_IDE_FOLDER)
27 set(ABSL_IDE_FOLDER Abseil)
28endif()
Austin Schuh36244a12019-09-21 17:52:38 -070029
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
Austin Schuhb4691e92020-12-31 12:37:18 -080086 if(ABSL_CC_LIB_TESTONLY AND NOT ABSL_RUN_TESTS)
87 return()
88 endif()
Austin Schuh36244a12019-09-21 17:52:38 -070089
Austin Schuhb4691e92020-12-31 12:37:18 -080090 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")
Austin Schuh36244a12019-09-21 17:52:38 -0700133 set(ABSL_CC_LIB_IS_INTERFACE 1)
134 else()
Austin Schuhb4691e92020-12-31 12:37:18 -0800135 # Building a DLL, but this target is not part of the DLL
136 set(_build_type "dll_dep")
Austin Schuh36244a12019-09-21 17:52:38 -0700137 endif()
Austin Schuhb4691e92020-12-31 12:37:18 -0800138 elseif(BUILD_SHARED_LIBS)
139 set(_build_type "shared")
140 else()
141 set(_build_type "static")
142 endif()
Austin Schuh36244a12019-09-21 17:52:38 -0700143
Austin Schuhb4691e92020-12-31 12:37:18 -0800144 # 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.
Austin Schuh36244a12019-09-21 17:52:38 -0700190 add_library(${_NAME} STATIC "")
191 target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS})
Austin Schuhb4691e92020-12-31 12:37:18 -0800192 absl_internal_dll_targets(
193 DEPS ${ABSL_CC_LIB_DEPS}
194 OUTPUT _dll_deps
Austin Schuh36244a12019-09-21 17:52:38 -0700195 )
Austin Schuh36244a12019-09-21 17:52:38 -0700196 target_link_libraries(${_NAME}
Austin Schuhb4691e92020-12-31 12:37:18 -0800197 PUBLIC ${_dll_deps}
Austin Schuh36244a12019-09-21 17:52:38 -0700198 PRIVATE
199 ${ABSL_CC_LIB_LINKOPTS}
200 ${ABSL_DEFAULT_LINKOPTS}
201 )
Austin Schuh36244a12019-09-21 17:52:38 -0700202
Austin Schuhb4691e92020-12-31 12:37:18 -0800203 if (ABSL_CC_LIB_TESTONLY)
204 set(_gtest_link_define "GTEST_LINKED_AS_SHARED_LIBRARY=1")
Austin Schuh36244a12019-09-21 17:52:38 -0700205 else()
Austin Schuhb4691e92020-12-31 12:37:18 -0800206 set(_gtest_link_define)
Austin Schuh36244a12019-09-21 17:52:38 -0700207 endif()
208
Austin Schuhb4691e92020-12-31 12:37:18 -0800209 target_compile_definitions(${_NAME}
210 PUBLIC
211 ABSL_CONSUME_DLL
212 "${_gtest_link_define}"
213 )
Austin Schuh36244a12019-09-21 17:52:38 -0700214
Austin Schuhb4691e92020-12-31 12:37:18 -0800215 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}
Austin Schuh36244a12019-09-21 17:52:38 -0700223 )
224 else()
Austin Schuhb4691e92020-12-31 12:37:18 -0800225 message(FATAL_ERROR "Invalid build type: ${_build_type}")
Austin Schuh36244a12019-09-21 17:52:38 -0700226 endif()
227
Austin Schuhb4691e92020-12-31 12:37:18 -0800228 # 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
Austin Schuh36244a12019-09-21 17:52:38 -0700265 )
266 endif()
Austin Schuhb4691e92020-12-31 12:37:18 -0800267 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()
Austin Schuh36244a12019-09-21 17:52:38 -0700298
299 add_library(absl::${ABSL_CC_LIB_NAME} ALIAS ${_NAME})
Austin Schuh36244a12019-09-21 17:52:38 -0700300endfunction()
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}")
Austin Schuhb4691e92020-12-31 12:37:18 -0800352
Austin Schuh36244a12019-09-21 17:52:38 -0700353 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 )
Austin Schuhb4691e92020-12-31 12:37:18 -0800359
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()
Austin Schuh36244a12019-09-21 17:52:38 -0700379 target_compile_options(${_NAME}
380 PRIVATE ${ABSL_CC_TEST_COPTS}
381 )
Austin Schuhb4691e92020-12-31 12:37:18 -0800382
Austin Schuh36244a12019-09-21 17:52:38 -0700383 target_link_libraries(${_NAME}
384 PUBLIC ${ABSL_CC_TEST_DEPS}
385 PRIVATE ${ABSL_CC_TEST_LINKOPTS}
386 )
Austin Schuhb4691e92020-12-31 12:37:18 -0800387 # Add all Abseil targets to a folder in the IDE for organization.
Austin Schuh36244a12019-09-21 17:52:38 -0700388 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()