From c476707e82f8db4974912594fbf419326973cb2a Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 5 May 2010 13:09:35 +0000 Subject: Improves support for building Google Test as Windows DLL. --- CMakeLists.txt | 133 +++++++++++++++++++++++---------------------- src/gtest-death-test.cc | 9 ++- src/gtest-internal-inl.h | 2 +- src/gtest_main.cc | 2 +- test/gtest_all_test.cc | 1 - test/gtest_output_test_.cc | 4 +- 6 files changed, 79 insertions(+), 72 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 159f072e..8b661223 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,14 +8,18 @@ # ctest. You can select which tests to run using 'ctest -R regex'. # For more options, run 'ctest --help'. -# For hermetic builds, we may need to tell CMake to use toolchain in a -# specific location. -string(REPLACE "\\" "/" CMAKE_RC_COMPILER "${CMAKE_RC_COMPILER}") -if (gtest_compiler) - string(REPLACE "\\" "/" gtest_compiler "${gtest_compiler}") - include(CMakeForceCompiler) - cmake_force_c_compiler("${gtest_compiler}" "") - cmake_force_cxx_compiler("${gtest_compiler}" "") +# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to +# make it prominent in the GUI. +option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) + +option(build_all_gtest_tests "Build all of gtest's own tests." OFF) + +option(build_gtest_samples "Build gtest's sample programs." OFF) + +include(cmake/hermetic_build.cmake OPTIONAL) + +if (COMMAND pre_project_set_up_hermetic_build) + pre_project_set_up_hermetic_build() endif() ######################################################################## @@ -29,7 +33,11 @@ endif() # ${gtest_BINARY_DIR}. # Language "C" is required for find_package(Threads). project(gtest CXX C) -cmake_minimum_required(VERSION 2.6.4) +cmake_minimum_required(VERSION 2.6.2) + +if (COMMAND set_up_hermetic_build) + set_up_hermetic_build() +endif() if (MSVC) # For MSVC, CMake sets certain flags to defaults we want to override. @@ -38,10 +46,17 @@ if (MSVC) foreach (flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) - # In hermetic build environments, tests may not have access to MS runtime - # DLLs, so this replaces /MD (CRT libraries in DLLs) with /MT (static CRT - # libraries). - string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}") + if (NOT BUILD_SHARED_LIBS) + # 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 always defaults to using shared + # CRT libraries, so we override that default here. + string(REPLACE "/MD" "-MT" ${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}}") @@ -66,7 +81,8 @@ find_package(Threads) if (MSVC) # Newlines inside flags variables break CMake's NMake generator. - set(cxx_base_flags "-GS -W4 -WX -wd4275 -nologo -J -Zi") + # TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds. + set(cxx_base_flags "-GS -W4 -WX -wd4251 -wd4275 -nologo -J -Zi") 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") @@ -124,13 +140,14 @@ function(cxx_library_with_type name type cxx_flags) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "${cxx_flags}") - if (CMAKE_USE_PTHREADS_INIT) - target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) - endif() -endfunction() - -function(cxx_static_library name cxx_flags) - cxx_library_with_type(${name} STATIC "${cxx_flags}" ${ARGN}) + if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED") + set_target_properties(${name} + PROPERTIES + COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1") + endif() + if (CMAKE_USE_PTHREADS_INIT) + target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) + endif() endfunction() function(cxx_shared_library name cxx_flags) @@ -138,15 +155,14 @@ function(cxx_shared_library name cxx_flags) endfunction() function(cxx_library name cxx_flags) - # TODO(vladl@google.com): Make static/shared a user option. - cxx_static_library(${name} "${cxx_flags}" ${ARGN}) + cxx_library_with_type(${name} "" "${cxx_flags}" ${ARGN}) endfunction() -# Static versions of Google Test libraries. We build them using more -# strict warnings than what are used for other targets, to ensure that -# gtest can be compiled by a user aggressive about warnings. -cxx_static_library(gtest "${cxx_strict}" src/gtest-all.cc) -cxx_static_library(gtest_main "${cxx_strict}" src/gtest_main.cc) +# Google Test libraries. We build them using more strict warnings than what +# are used for other targets, to ensure that gtest can be compiled by a user +# aggressive about warnings. +cxx_library(gtest "${cxx_strict}" src/gtest-all.cc) +cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc) target_link_libraries(gtest_main gtest) ######################################################################## @@ -157,30 +173,37 @@ target_link_libraries(gtest_main gtest) # build_gtest_samples option to ON. You can do it by running ccmake # or specifying the -Dbuild_gtest_samples=ON flag when running cmake. -option(build_gtest_samples "Build gtest's sample programs." OFF) - -# cxx_executable_with_flags(name cxx_flags lib srcs...) +# cxx_executable_with_flags(name cxx_flags libs srcs...) # -# creates a named C++ executable that depends on the given library and +# 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 lib) +function(cxx_executable_with_flags name cxx_flags libs) add_executable(${name} ${ARGN}) if (cxx_flags) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "${cxx_flags}") endif() - target_link_libraries(${name} ${lib}) + 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 lib and is built +# 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 lib) +function(cxx_executable name dir libs) cxx_executable_with_flags( - ${name} "${cxx_default}" ${lib} "${dir}/${name}.cc" ${ARGN}) + ${name} "${cxx_default}" "${libs}" "${dir}/${name}.cc" ${ARGN}) endfunction() if (build_gtest_samples) @@ -207,8 +230,6 @@ endif() # build_all_gtest_tests option to ON. You can do it by running ccmake # or specifying the -Dbuild_all_gtest_tests=ON flag when running cmake. -option(build_all_gtest_tests "Build all of gtest's own tests." OFF) - # This must be set in the root directory for the tests to be run by # 'make test' or ctest. enable_testing() @@ -224,15 +245,7 @@ find_package(PythonInterp) # 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) - add_executable(${name} ${ARGN}) - set_target_properties(${name} - PROPERTIES - COMPILE_FLAGS "${cxx_flags}") - # 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() + cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN}) add_test(${name} ${name}) endfunction() @@ -286,26 +299,16 @@ if (build_all_gtest_tests) cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}" gtest_main_no_rtti test/gtest_unittest.cc) - set(cxx_use_shared_gtest "${cxx_default} -DGTEST_LINKED_AS_SHARED_LIBRARY=1") - set(cxx_build_shared_gtest "${cxx_default} -DGTEST_CREATE_SHARED_LIBRARY=1") - if (MSVC) - # Disables the "class 'X' needs to have dll-interface to be used - # by clients of class 'Y'" warning. This particularly concerns generic - # classes like vector that MS doesn't mark as exported. - set(cxx_use_shared_gtest "${cxx_use_shared_gtest} -wd4251") - set(cxx_build_shared_gtest "${cxx_build_shared_gtest} -wd4251") - endif() - - cxx_shared_library(gtest_dll "${cxx_build_shared_gtest}" - src/gtest-all.cc) + cxx_shared_library(gtest_dll "${cxx_default}" + src/gtest-all.cc src/gtest_main.cc) - # TODO(vladl): This and the next tests may not run in the hermetic - # environment on Windows. Re-evaluate and possibly make them - # platform-conditional after implementing hermetic builds. - cxx_executable_with_flags(gtest_dll_test_ "${cxx_use_shared_gtest}" + cxx_executable_with_flags(gtest_dll_test_ "${cxx_default}" gtest_dll test/gtest_all_test.cc) + set_target_properties(gtest_dll_test_ + PROPERTIES + COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") - if (NOT(MSVC AND (MSVC_VERSION EQUAL 1600))) + if (NOT MSVC OR NOT MSVC_VERSION EQUAL 1600) # The C++ Standard specifies tuple_element. # Yet MSVC 10's declares tuple_element. # That declaration conflicts with our own standard-conforming diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 3b73b01d..66bf1898 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -418,7 +418,14 @@ void DeathTestImpl::Abort(AbortReason reason) { const char status_ch = reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd())); + // We are leaking the descriptor here because on some platforms (i.e., + // when built as Windows DLL), destructors of global objects will still + // run after calling _exit(). On such systems, write_fd_ will be + // indirectly closed from the destructor of UnitTestImpl, causing double + // close if it is also closed here. On debug configurations, double close + // may assert. As there are no in-process buffers to flush here, we are + // relying on the OS to close the descriptor after the process terminates + // when the destructors are not run. _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 855b2155..a3cda754 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -977,7 +977,7 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); // Returns the message describing the last system error, regardless of the // platform. -String GetLastErrnoDescription(); +GTEST_API_ String GetLastErrnoDescription(); #if GTEST_OS_WINDOWS // Provides leak-safe Windows kernel handle ownership. diff --git a/src/gtest_main.cc b/src/gtest_main.cc index d20c02fd..6d4d22d2 100644 --- a/src/gtest_main.cc +++ b/src/gtest_main.cc @@ -31,7 +31,7 @@ #include -int main(int argc, char **argv) { +GTEST_API_ int main(int argc, char **argv) { std::cout << "Running main() from gtest_main.cc\n"; testing::InitGoogleTest(&argc, argv); diff --git a/test/gtest_all_test.cc b/test/gtest_all_test.cc index e1edb08e..955aa628 100644 --- a/test/gtest_all_test.cc +++ b/test/gtest_all_test.cc @@ -45,4 +45,3 @@ #include "test/gtest-typed-test2_test.cc" #include "test/gtest_unittest.cc" #include "test/production.cc" -#include "src/gtest_main.cc" diff --git a/test/gtest_output_test_.cc b/test/gtest_output_test_.cc index 273e8e93..32fb49a9 100644 --- a/test/gtest_output_test_.cc +++ b/test/gtest_output_test_.cc @@ -1085,9 +1085,7 @@ class BarEnvironment : public testing::Environment { } }; -GTEST_DEFINE_bool_(internal_skip_environment_and_ad_hoc_tests, false, - "This flag causes the program to skip test environment " - "tests and ad hoc tests."); +bool GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests) = false; // The main function. // -- cgit v1.2.3