• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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