mirror of
https://github.com/google/googletest.git
synced 2025-12-06 08:46:50 +08:00
With CMake 3.15, a new mechanism was added to control which CRT libraries link to. Because the minimum CMake version is above 3.15, googletest can leverage it in the implementation of gtest_force_shared_crt. If CMAKE_MSVC_RUNTIME_LIBRARY is already defined, googletest will respect its value rather than replace it, allowing for users to customize the exact CRT used by googletest.
338 lines
14 KiB
CMake
338 lines
14 KiB
CMake
# Defines functions and macros useful for building Google Test and
|
|
# Google Mock.
|
|
#
|
|
# Note:
|
|
#
|
|
# - This file will be run twice when building Google Mock (once via
|
|
# Google Test's CMakeLists.txt, and once via Google Mock's).
|
|
# Therefore it shouldn't have any side effects other than defining
|
|
# the functions and macros.
|
|
#
|
|
# - The functions/macros defined in this file may depend on Google
|
|
# Test and Google Mock's option() definitions, and thus must be
|
|
# called *after* the options have been defined.
|
|
|
|
# Tweaks CMake's default compiler/linker settings to suit Google Test's needs.
|
|
#
|
|
# This must be a macro(), as inside a function string() can only
|
|
# update variables in the function scope.
|
|
macro(fix_default_compiler_settings_)
|
|
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC|Clang")
|
|
# For MSVC and Clang, CMake sets certain flags to defaults we want to
|
|
# override.
|
|
# This replacement code is taken from sample in the CMake Wiki at
|
|
# https://gitlab.kitware.com/cmake/community/wikis/FAQ#dynamic-replace.
|
|
foreach (flag_var
|
|
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
|
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
|
|
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
|
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
|
if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt)
|
|
# When using Ninja with Clang, static builds pass -D_DLL on Windows.
|
|
# This is incorrect and should not happen, so we fix that here.
|
|
string(REPLACE "-D_DLL" "" ${flag_var} "${${flag_var}}")
|
|
endif()
|
|
|
|
# We prefer more strict warning checking for building Google Test.
|
|
# Replaces /W3 with /W4 in defaults.
|
|
string(REPLACE "/W3" "/W4" ${flag_var} "${${flag_var}}")
|
|
|
|
# Prevent D9025 warning for targets that have exception handling
|
|
# turned off (/EHs-c- flag). Where required, exceptions are explicitly
|
|
# re-enabled using the cxx_exception_flags variable.
|
|
string(REPLACE "/EHsc" "" ${flag_var} "${${flag_var}}")
|
|
endforeach()
|
|
endif()
|
|
endmacro()
|
|
|
|
# Defines the compiler/linker flags used to build Google Test and
|
|
# Google Mock. You can tweak these definitions to suit your need. A
|
|
# variable's value is empty before it's explicitly assigned to.
|
|
macro(config_compiler_and_linker)
|
|
# Note: pthreads on MinGW is not supported, even if available
|
|
# instead, we use windows threading primitives.
|
|
unset(GTEST_HAS_PTHREAD)
|
|
if (NOT gtest_disable_pthreads AND NOT MINGW)
|
|
# Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT.
|
|
find_package(Threads)
|
|
if (CMAKE_USE_PTHREADS_INIT)
|
|
set(GTEST_HAS_PTHREAD ON)
|
|
endif()
|
|
endif()
|
|
|
|
fix_default_compiler_settings_()
|
|
|
|
if (MSVC)
|
|
# When Google Test is built as a shared library, it should also use
|
|
# shared runtime libraries. Otherwise, it may end up with multiple
|
|
# copies of runtime library data in different modules, resulting in
|
|
# hard-to-find crashes. When it is built as a static library, it is
|
|
# preferable to use CRT as static libraries, as we don't have to rely
|
|
# on CRT DLLs being available. CMake defaults to using shared
|
|
# CRT libraries, so we change that here.
|
|
if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt AND NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
|
|
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
|
endif()
|
|
|
|
# Newlines inside flags variables break CMake's NMake generator.
|
|
# TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds.
|
|
set(cxx_base_flags "-GS -W4 -WX -wd4251 -wd4275 -nologo -J")
|
|
set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32")
|
|
set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN")
|
|
set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1")
|
|
set(cxx_no_exception_flags "-EHs-c- -D_HAS_EXCEPTIONS=0")
|
|
set(cxx_no_rtti_flags "-GR-")
|
|
# Suppress "unreachable code" warning,
|
|
# https://stackoverflow.com/questions/3232669 explains the issue.
|
|
set(cxx_base_flags "${cxx_base_flags} -wd4702")
|
|
# Ensure MSVC treats source files as UTF-8 encoded.
|
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
|
set(cxx_base_flags "${cxx_base_flags} -utf-8")
|
|
endif()
|
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
|
|
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")
|
|
endif()
|
|
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR
|
|
CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
|
|
set(cxx_base_flags "-Wall -Wshadow -Wconversion -Wundef")
|
|
set(cxx_exception_flags "-fexceptions")
|
|
set(cxx_no_exception_flags "-fno-exceptions")
|
|
set(cxx_strict_flags "-W -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wunused-parameter -Wcast-align -Winline -Wredundant-decls")
|
|
set(cxx_no_rtti_flags "-fno-rtti")
|
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
|
set(cxx_strict_flags "${cxx_strict_flags} -Wchar-subscripts")
|
|
endif()
|
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
|
|
set(cxx_base_flags "${cxx_base_flags} -Wno-implicit-float-size-conversion -ffp-model=precise")
|
|
endif()
|
|
elseif (CMAKE_COMPILER_IS_GNUCXX)
|
|
set(cxx_base_flags "-Wall -Wshadow -Wundef")
|
|
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0.0)
|
|
set(cxx_base_flags "${cxx_base_flags} -Wno-error=dangling-else")
|
|
endif()
|
|
set(cxx_exception_flags "-fexceptions")
|
|
set(cxx_no_exception_flags "-fno-exceptions")
|
|
# Until version 4.3.2, GCC doesn't define a macro to indicate
|
|
# whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI
|
|
# explicitly.
|
|
set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0")
|
|
set(cxx_strict_flags
|
|
"-Wextra -Wno-unused-parameter -Wno-missing-field-initializers")
|
|
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
|
|
set(cxx_exception_flags "-features=except")
|
|
# Sun Pro doesn't provide macros to indicate whether exceptions and
|
|
# RTTI are enabled, so we define GTEST_HAS_* explicitly.
|
|
set(cxx_no_exception_flags "-features=no%except -DGTEST_HAS_EXCEPTIONS=0")
|
|
set(cxx_no_rtti_flags "-features=no%rtti -DGTEST_HAS_RTTI=0")
|
|
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "VisualAge" OR
|
|
CMAKE_CXX_COMPILER_ID STREQUAL "XL")
|
|
# CMake 2.8 changes Visual Age's compiler ID to "XL".
|
|
set(cxx_exception_flags "-qeh")
|
|
set(cxx_no_exception_flags "-qnoeh")
|
|
# Until version 9.0, Visual Age doesn't define a macro to indicate
|
|
# whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI
|
|
# explicitly.
|
|
set(cxx_no_rtti_flags "-qnortti -DGTEST_HAS_RTTI=0")
|
|
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "HP")
|
|
set(cxx_base_flags "-AA -mt")
|
|
set(cxx_exception_flags "-DGTEST_HAS_EXCEPTIONS=1")
|
|
set(cxx_no_exception_flags "+noeh -DGTEST_HAS_EXCEPTIONS=0")
|
|
# RTTI can not be disabled in HP aCC compiler.
|
|
set(cxx_no_rtti_flags "")
|
|
endif()
|
|
|
|
# The pthreads library is available and allowed?
|
|
if (DEFINED GTEST_HAS_PTHREAD)
|
|
set(GTEST_HAS_PTHREAD_MACRO "-DGTEST_HAS_PTHREAD=1")
|
|
else()
|
|
set(GTEST_HAS_PTHREAD_MACRO "-DGTEST_HAS_PTHREAD=0")
|
|
endif()
|
|
set(cxx_base_flags "${cxx_base_flags} ${GTEST_HAS_PTHREAD_MACRO}")
|
|
|
|
# For building gtest's own tests and samples.
|
|
set(cxx_exception "${cxx_base_flags} ${cxx_exception_flags}")
|
|
set(cxx_no_exception
|
|
"${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}")
|
|
set(cxx_default "${cxx_exception}")
|
|
set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}")
|
|
|
|
# For building the gtest libraries.
|
|
set(cxx_strict "${cxx_default} ${cxx_strict_flags}")
|
|
endmacro()
|
|
|
|
# Defines the gtest & gtest_main libraries. User tests should link
|
|
# with one of them.
|
|
function(cxx_library_with_type name type cxx_flags)
|
|
# type can be either STATIC or SHARED to denote a static or shared library.
|
|
# ARGN refers to additional arguments after 'cxx_flags'.
|
|
add_library(${name} ${type} ${ARGN})
|
|
add_library(${cmake_package_name}::${name} ALIAS ${name})
|
|
set_target_properties(${name}
|
|
PROPERTIES
|
|
COMPILE_FLAGS "${cxx_flags}")
|
|
# Set the output directory for build artifacts.
|
|
set_target_properties(${name}
|
|
PROPERTIES
|
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
|
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
|
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
|
PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
|
COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
|
# Make PDBs match library name.
|
|
get_target_property(pdb_debug_postfix ${name} DEBUG_POSTFIX)
|
|
set_target_properties(${name}
|
|
PROPERTIES
|
|
PDB_NAME "${name}"
|
|
PDB_NAME_DEBUG "${name}${pdb_debug_postfix}"
|
|
COMPILE_PDB_NAME "${name}"
|
|
COMPILE_PDB_NAME_DEBUG "${name}${pdb_debug_postfix}")
|
|
|
|
if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED")
|
|
set_target_properties(${name}
|
|
PROPERTIES
|
|
COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1")
|
|
target_compile_definitions(${name} INTERFACE
|
|
$<INSTALL_INTERFACE:GTEST_LINKED_AS_SHARED_LIBRARY=1>)
|
|
endif()
|
|
if (DEFINED GTEST_HAS_PTHREAD)
|
|
target_link_libraries(${name} PUBLIC Threads::Threads)
|
|
endif()
|
|
|
|
target_compile_features(${name} PUBLIC cxx_std_17)
|
|
endfunction()
|
|
|
|
########################################################################
|
|
#
|
|
# Helper functions for creating build targets.
|
|
|
|
function(cxx_shared_library name cxx_flags)
|
|
cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN})
|
|
endfunction()
|
|
|
|
function(cxx_library name cxx_flags)
|
|
cxx_library_with_type(${name} "" "${cxx_flags}" ${ARGN})
|
|
endfunction()
|
|
|
|
# cxx_executable_with_flags(name cxx_flags libs srcs...)
|
|
#
|
|
# Creates a named C++ executable that depends on the given libraries and
|
|
# is built from the given source files with the given compiler flags.
|
|
function(cxx_executable_with_flags name cxx_flags libs)
|
|
add_executable(${name} ${ARGN})
|
|
if (MSVC)
|
|
# BigObj required for tests.
|
|
set(cxx_flags "${cxx_flags} -bigobj")
|
|
endif()
|
|
if (cxx_flags)
|
|
set_target_properties(${name}
|
|
PROPERTIES
|
|
COMPILE_FLAGS "${cxx_flags}")
|
|
endif()
|
|
if (BUILD_SHARED_LIBS)
|
|
set_target_properties(${name}
|
|
PROPERTIES
|
|
COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
|
|
endif()
|
|
# To support mixing linking in static and dynamic libraries, link each
|
|
# library in with an extra call to target_link_libraries.
|
|
foreach (lib "${libs}")
|
|
target_link_libraries(${name} ${lib})
|
|
endforeach()
|
|
endfunction()
|
|
|
|
# cxx_executable(name dir lib srcs...)
|
|
#
|
|
# Creates a named target that depends on the given libs and is built
|
|
# from the given source files. dir/name.cc is implicitly included in
|
|
# the source file list.
|
|
function(cxx_executable name dir libs)
|
|
cxx_executable_with_flags(
|
|
${name} "${cxx_default}" "${libs}" "${dir}/${name}.cc" ${ARGN})
|
|
endfunction()
|
|
|
|
if(gtest_build_tests)
|
|
find_package(Python3)
|
|
endif()
|
|
|
|
# cxx_test_with_flags(name cxx_flags libs srcs...)
|
|
#
|
|
# Creates a named C++ test that depends on the given libs and is built
|
|
# from the given source files with the given compiler flags.
|
|
function(cxx_test_with_flags name cxx_flags libs)
|
|
cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN})
|
|
add_test(NAME ${name} COMMAND "$<TARGET_FILE:${name}>")
|
|
endfunction()
|
|
|
|
# cxx_test(name libs srcs...)
|
|
#
|
|
# Creates a named test target that depends on the given libs and is
|
|
# built from the given source files. Unlike cxx_test_with_flags,
|
|
# test/name.cc is already implicitly included in the source file list.
|
|
function(cxx_test name libs)
|
|
cxx_test_with_flags("${name}" "${cxx_default}" "${libs}"
|
|
"test/${name}.cc" ${ARGN})
|
|
endfunction()
|
|
|
|
# py_test(name)
|
|
#
|
|
# Creates a Python test with the given name whose main module is in
|
|
# test/name.py. It does nothing if Python is not installed.
|
|
function(py_test name)
|
|
if (NOT Python3_Interpreter_FOUND)
|
|
return()
|
|
endif()
|
|
|
|
get_cmake_property(is_multi "GENERATOR_IS_MULTI_CONFIG")
|
|
set(build_dir "${CMAKE_CURRENT_BINARY_DIR}")
|
|
if (is_multi)
|
|
set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
|
|
endif()
|
|
|
|
add_test(NAME ${name}
|
|
COMMAND Python3::Interpreter ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py
|
|
--build_dir=${build_dir} ${ARGN})
|
|
|
|
# Make the Python import path consistent between Bazel and CMake.
|
|
set_tests_properties(${name} PROPERTIES ENVIRONMENT PYTHONPATH=${CMAKE_SOURCE_DIR})
|
|
endfunction()
|
|
|
|
# install_project(targets...)
|
|
#
|
|
# Installs the specified targets and configures the associated pkgconfig files.
|
|
function(install_project)
|
|
if(INSTALL_GTEST)
|
|
install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/"
|
|
COMPONENT "${PROJECT_NAME}"
|
|
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
|
# Install the project targets.
|
|
install(TARGETS ${ARGN}
|
|
EXPORT ${targets_export_name}
|
|
COMPONENT "${PROJECT_NAME}"
|
|
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
|
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
|
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
|
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
|
# Install PDBs.
|
|
foreach(t ${ARGN})
|
|
get_target_property(t_pdb_name ${t} COMPILE_PDB_NAME)
|
|
get_target_property(t_pdb_name_debug ${t} COMPILE_PDB_NAME_DEBUG)
|
|
get_target_property(t_pdb_output_directory ${t} PDB_OUTPUT_DIRECTORY)
|
|
install(FILES
|
|
"${t_pdb_output_directory}/\${CMAKE_INSTALL_CONFIG_NAME}/$<$<CONFIG:Debug>:${t_pdb_name_debug}>$<$<NOT:$<CONFIG:Debug>>:${t_pdb_name}>.pdb"
|
|
COMPONENT "${PROJECT_NAME}"
|
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
OPTIONAL)
|
|
endforeach()
|
|
endif()
|
|
# Configure and install pkgconfig files.
|
|
foreach(t ${ARGN})
|
|
set(configured_pc "${generated_dir}/${t}.pc")
|
|
configure_file("${PROJECT_SOURCE_DIR}/cmake/${t}.pc.in"
|
|
"${configured_pc}" @ONLY)
|
|
install(FILES "${configured_pc}"
|
|
COMPONENT "${PROJECT_NAME}"
|
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
|
endforeach()
|
|
endif()
|
|
endfunction()
|