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