1# Defines functions and macros useful for building Google Test and
2# Google Mock.
3#
4# Note:
5#
6# - This file will be run twice when building Google Mock (once via
7#   Google Test's CMakeLists.txt, and once via Google Mock's).
8#   Therefore it shouldn't have any side effects other than defining
9#   the functions and macros.
10#
11# - The functions/macros defined in this file may depend on Google
12#   Test and Google Mock's option() definitions, and thus must be
13#   called *after* the options have been defined.
14
15# Tweaks CMake's default compiler/linker settings to suit Google Test's needs.
16#
17# This must be a macro(), as inside a function string() can only
18# update variables in the function scope.
19macro(fix_default_compiler_settings_)
20  if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC|Clang")
21    # For MSVC and Clang, CMake sets certain flags to defaults we want to
22    # override.
23    # This replacement code is taken from sample in the CMake Wiki at
24    # https://gitlab.kitware.com/cmake/community/wikis/FAQ#dynamic-replace.
25    foreach (flag_var
26             CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
27             CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
28             CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
29             CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
30      if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt)
31        # When Google Test is built as a shared library, it should also use
32        # shared runtime libraries.  Otherwise, it may end up with multiple
33        # copies of runtime library data in different modules, resulting in
34        # hard-to-find crashes. When it is built as a static library, it is
35        # preferable to use CRT as static libraries, as we don't have to rely
36        # on CRT DLLs being available. CMake always defaults to using shared
37        # CRT libraries, so we override that default here.
38        string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}")
39
40        # When using Ninja with Clang, static builds pass -D_DLL on Windows.
41        # This is incorrect and should not happen, so we fix that here.
42        string(REPLACE "-D_DLL" "" ${flag_var} "${${flag_var}}")
43      endif()
44
45      # We prefer more strict warning checking for building Google Test.
46      # Replaces /W3 with /W4 in defaults.
47      string(REPLACE "/W3" "/W4" ${flag_var} "${${flag_var}}")
48
49      # Prevent D9025 warning for targets that have exception handling
50      # turned off (/EHs-c- flag). Where required, exceptions are explicitly
51      # re-enabled using the cxx_exception_flags variable.
52      string(REPLACE "/EHsc" "" ${flag_var} "${${flag_var}}")
53    endforeach()
54  endif()
55endmacro()
56
57# Defines the compiler/linker flags used to build Google Test and
58# Google Mock.  You can tweak these definitions to suit your need.  A
59# variable's value is empty before it's explicitly assigned to.
60macro(config_compiler_and_linker)
61  # Note: pthreads on MinGW is not supported, even if available
62  # instead, we use windows threading primitives
63  unset(GTEST_HAS_PTHREAD)
64  if (NOT gtest_disable_pthreads AND NOT MINGW)
65    # Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT.
66    find_package(Threads)
67    if (CMAKE_USE_PTHREADS_INIT)
68      set(GTEST_HAS_PTHREAD ON)
69    endif()
70  endif()
71
72  fix_default_compiler_settings_()
73  if (MSVC)
74    # Newlines inside flags variables break CMake's NMake generator.
75    # TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds.
76    set(cxx_base_flags "-GS -W4 -WX -wd4251 -wd4275 -nologo -J")
77    set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32")
78    set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN")
79    set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1")
80    set(cxx_no_exception_flags "-EHs-c- -D_HAS_EXCEPTIONS=0")
81    set(cxx_no_rtti_flags "-GR-")
82    # Suppress "unreachable code" warning
83    # http://stackoverflow.com/questions/3232669 explains the issue.
84    set(cxx_base_flags "${cxx_base_flags} -wd4702")
85    # Ensure MSVC treats source files as UTF-8 encoded.
86    if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
87      set(cxx_base_flags "${cxx_base_flags} -utf-8")
88    endif()
89    if (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
90      set(cxx_base_flags "${cxx_base_flags} /fp:precise -Wno-inconsistent-missing-override -Wno-microsoft-exception-spec -Wno-unused-function -Wno-unused-but-set-variable")
91    endif()
92  elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR
93      CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
94    set(cxx_base_flags "-Wall -Wshadow -Wconversion -Wundef")
95    set(cxx_exception_flags "-fexceptions")
96    set(cxx_no_exception_flags "-fno-exceptions")
97    set(cxx_strict_flags "-W -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wunused-parameter -Wcast-align -Winline -Wredundant-decls")
98    set(cxx_no_rtti_flags "-fno-rtti")
99    if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
100      set(cxx_strict_flags "${cxx_strict_flags} -Wchar-subscripts")
101    endif()
102    if (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
103      set(cxx_base_flags "${cxx_base_flags} -Wno-implicit-float-size-conversion -ffp-model=precise")
104    endif()
105  elseif (CMAKE_COMPILER_IS_GNUCXX)
106    set(cxx_base_flags "-Wall -Wshadow -Wundef")
107    if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0.0)
108      set(cxx_base_flags "${cxx_base_flags} -Wno-error=dangling-else")
109    endif()
110    set(cxx_exception_flags "-fexceptions")
111    set(cxx_no_exception_flags "-fno-exceptions")
112    # Until version 4.3.2, GCC doesn't define a macro to indicate
113    # whether RTTI is enabled.  Therefore we define GTEST_HAS_RTTI
114    # explicitly.
115    set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0")
116    set(cxx_strict_flags
117      "-Wextra -Wno-unused-parameter -Wno-missing-field-initializers")
118  elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
119    set(cxx_exception_flags "-features=except")
120    # Sun Pro doesn't provide macros to indicate whether exceptions and
121    # RTTI are enabled, so we define GTEST_HAS_* explicitly.
122    set(cxx_no_exception_flags "-features=no%except -DGTEST_HAS_EXCEPTIONS=0")
123    set(cxx_no_rtti_flags "-features=no%rtti -DGTEST_HAS_RTTI=0")
124  elseif (CMAKE_CXX_COMPILER_ID STREQUAL "VisualAge" OR
125      CMAKE_CXX_COMPILER_ID STREQUAL "XL")
126    # CMake 2.8 changes Visual Age's compiler ID to "XL".
127    set(cxx_exception_flags "-qeh")
128    set(cxx_no_exception_flags "-qnoeh")
129    # Until version 9.0, Visual Age doesn't define a macro to indicate
130    # whether RTTI is enabled.  Therefore we define GTEST_HAS_RTTI
131    # explicitly.
132    set(cxx_no_rtti_flags "-qnortti -DGTEST_HAS_RTTI=0")
133  elseif (CMAKE_CXX_COMPILER_ID STREQUAL "HP")
134    set(cxx_base_flags "-AA -mt")
135    set(cxx_exception_flags "-DGTEST_HAS_EXCEPTIONS=1")
136    set(cxx_no_exception_flags "+noeh -DGTEST_HAS_EXCEPTIONS=0")
137    # RTTI can not be disabled in HP aCC compiler.
138    set(cxx_no_rtti_flags "")
139  endif()
140
141  # The pthreads library is available and allowed?
142  if (DEFINED GTEST_HAS_PTHREAD)
143    set(GTEST_HAS_PTHREAD_MACRO "-DGTEST_HAS_PTHREAD=1")
144  else()
145    set(GTEST_HAS_PTHREAD_MACRO "-DGTEST_HAS_PTHREAD=0")
146  endif()
147  set(cxx_base_flags "${cxx_base_flags} ${GTEST_HAS_PTHREAD_MACRO}")
148
149  # For building gtest's own tests and samples.
150  set(cxx_exception "${cxx_base_flags} ${cxx_exception_flags}")
151  set(cxx_no_exception
152    "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}")
153  set(cxx_default "${cxx_exception}")
154  set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}")
155
156  # For building the gtest libraries.
157  set(cxx_strict "${cxx_default} ${cxx_strict_flags}")
158endmacro()
159
160# Defines the gtest & gtest_main libraries.  User tests should link
161# with one of them.
162function(cxx_library_with_type name type cxx_flags)
163  # type can be either STATIC or SHARED to denote a static or shared library.
164  # ARGN refers to additional arguments after 'cxx_flags'.
165  add_library(${name} ${type} ${ARGN})
166  add_library(${cmake_package_name}::${name} ALIAS ${name})
167  set_target_properties(${name}
168    PROPERTIES
169    COMPILE_FLAGS "${cxx_flags}")
170  # Set the output directory for build artifacts
171  set_target_properties(${name}
172    PROPERTIES
173    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
174    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
175    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
176    PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
177    COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
178  # make PDBs match library name
179  get_target_property(pdb_debug_postfix ${name} DEBUG_POSTFIX)
180  set_target_properties(${name}
181    PROPERTIES
182    PDB_NAME "${name}"
183    PDB_NAME_DEBUG "${name}${pdb_debug_postfix}"
184    COMPILE_PDB_NAME "${name}"
185    COMPILE_PDB_NAME_DEBUG "${name}${pdb_debug_postfix}")
186
187  if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED")
188    set_target_properties(${name}
189      PROPERTIES
190      COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1")
191    target_compile_definitions(${name} INTERFACE
192      $<INSTALL_INTERFACE:GTEST_LINKED_AS_SHARED_LIBRARY=1>)
193  endif()
194  if (DEFINED GTEST_HAS_PTHREAD)
195    target_link_libraries(${name} PUBLIC Threads::Threads)
196  endif()
197
198  target_compile_features(${name} PUBLIC cxx_std_14)
199endfunction()
200
201########################################################################
202#
203# Helper functions for creating build targets.
204
205function(cxx_shared_library name cxx_flags)
206  cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN})
207endfunction()
208
209function(cxx_library name cxx_flags)
210  cxx_library_with_type(${name} "" "${cxx_flags}" ${ARGN})
211endfunction()
212
213# cxx_executable_with_flags(name cxx_flags libs srcs...)
214#
215# creates a named C++ executable that depends on the given libraries and
216# is built from the given source files with the given compiler flags.
217function(cxx_executable_with_flags name cxx_flags libs)
218  add_executable(${name} ${ARGN})
219  if (MSVC)
220    # BigObj required for tests.
221    set(cxx_flags "${cxx_flags} -bigobj")
222  endif()
223  if (cxx_flags)
224    set_target_properties(${name}
225      PROPERTIES
226      COMPILE_FLAGS "${cxx_flags}")
227  endif()
228  if (BUILD_SHARED_LIBS)
229    set_target_properties(${name}
230      PROPERTIES
231      COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
232  endif()
233  # To support mixing linking in static and dynamic libraries, link each
234  # library in with an extra call to target_link_libraries.
235  foreach (lib "${libs}")
236    target_link_libraries(${name} ${lib})
237  endforeach()
238endfunction()
239
240# cxx_executable(name dir lib srcs...)
241#
242# creates a named target that depends on the given libs and is built
243# from the given source files.  dir/name.cc is implicitly included in
244# the source file list.
245function(cxx_executable name dir libs)
246  cxx_executable_with_flags(
247    ${name} "${cxx_default}" "${libs}" "${dir}/${name}.cc" ${ARGN})
248endfunction()
249
250find_package(Python3)
251
252# cxx_test_with_flags(name cxx_flags libs srcs...)
253#
254# creates a named C++ test that depends on the given libs and is built
255# from the given source files with the given compiler flags.
256function(cxx_test_with_flags name cxx_flags libs)
257  cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN})
258    add_test(NAME ${name} COMMAND "$<TARGET_FILE:${name}>")
259endfunction()
260
261# cxx_test(name libs srcs...)
262#
263# creates a named test target that depends on the given libs and is
264# built from the given source files.  Unlike cxx_test_with_flags,
265# test/name.cc is already implicitly included in the source file list.
266function(cxx_test name libs)
267  cxx_test_with_flags("${name}" "${cxx_default}" "${libs}"
268    "test/${name}.cc" ${ARGN})
269endfunction()
270
271# py_test(name)
272#
273# creates a Python test with the given name whose main module is in
274# test/name.py.  It does nothing if Python is not installed.
275function(py_test name)
276  if (NOT Python3_Interpreter_FOUND)
277    return()
278  endif()
279
280  get_cmake_property(is_multi "GENERATOR_IS_MULTI_CONFIG")
281  set(build_dir "${CMAKE_CURRENT_BINARY_DIR}")
282  if (is_multi)
283    set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
284  endif()
285
286  add_test(NAME ${name}
287      COMMAND Python3::Interpreter ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py
288          --build_dir=${build_dir} ${ARGN})
289
290  # Make the Python import path consistent between Bazel and CMake.
291  set_tests_properties(${name} PROPERTIES ENVIRONMENT PYTHONPATH=${CMAKE_SOURCE_DIR})
292endfunction()
293
294# install_project(targets...)
295#
296# Installs the specified targets and configures the associated pkgconfig files.
297function(install_project)
298  if(INSTALL_GTEST)
299    install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/"
300      COMPONENT "${PROJECT_NAME}"
301      DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
302    # Install the project targets.
303    install(TARGETS ${ARGN}
304      EXPORT ${targets_export_name}
305      COMPONENT "${PROJECT_NAME}"
306      RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
307      ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
308      LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
309    if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
310      # Install PDBs
311      foreach(t ${ARGN})
312        get_target_property(t_pdb_name ${t} COMPILE_PDB_NAME)
313        get_target_property(t_pdb_name_debug ${t} COMPILE_PDB_NAME_DEBUG)
314        get_target_property(t_pdb_output_directory ${t} PDB_OUTPUT_DIRECTORY)
315        install(FILES
316          "${t_pdb_output_directory}/\${CMAKE_INSTALL_CONFIG_NAME}/$<$<CONFIG:Debug>:${t_pdb_name_debug}>$<$<NOT:$<CONFIG:Debug>>:${t_pdb_name}>.pdb"
317          COMPONENT "${PROJECT_NAME}"
318          DESTINATION ${CMAKE_INSTALL_LIBDIR}
319          OPTIONAL)
320      endforeach()
321    endif()
322    # Configure and install pkgconfig files.
323    foreach(t ${ARGN})
324      set(configured_pc "${generated_dir}/${t}.pc")
325      configure_file("${PROJECT_SOURCE_DIR}/cmake/${t}.pc.in"
326        "${configured_pc}" @ONLY)
327      install(FILES "${configured_pc}"
328        COMPONENT "${PROJECT_NAME}"
329        DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
330    endforeach()
331  endif()
332endfunction()
333