"unresolved external symbol" using FLAGS_gtest_death_test_style on MS Windows
Describe the bug
I add GTEST_FLAG_SET(death_test_style, "threadsafe"); to main() of a gtest as shown at Death Test Styles:
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
GTEST_FLAG_SET(death_test_style, "threadsafe");
return RUN_ALL_TESTS();
}
This compiles on Linux (Debian Bullseye) without any errors. On Microsoft Windows I get:
test_UpnpString.obj : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > testing::FLAGS_gtest_death_test_style" (?FLAGS_gtest_death_test_style@testing@@3V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A) referenced in function main [C:\Users\ingo\devel\upnplib-dev\upnplib\gtests\build\test_UpnpStri
ng_old.vcxproj]
C:\Users\ingo\devel\upnplib-dev\upnplib\gtests\build\Release\test_UpnpString_old.exe : fatal error LNK1120: 1 unresolved externals
[C:\Users\ingo\devel\upnplib-dev\upnplib\gtests\build\test_UpnpString_old.vcxproj]
I expect it to compiles without errors, like it does on Linux.
Steps to reproduce the bug
On MS Windows 10 add the line GTEST_FLAG_SET(death_test_style, "threadsafe"); to main() as shown above to an existing gtest that compiles before without errors.
Does the bug persist in the most recent commit? Yes.
What operating system and version are you using? i use Microsoft Windows 10 with Microsoft Visual Studio 2019 Community version and selected the default development command line environment
ingo@WIN10-DEVEL C:\Users\ingo> "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64
**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.9.5
** Copyright (c) 2021 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'
as described at https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-160#use-the-developer-tools-in-an-existing-command-window
What compiler and version are you using?
PS> cl.exe
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29915 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
usage: cl [ option... ] filename... [ /link linkoption... ]
What build system are you using?
PS> cmake --version
cmake version 3.19.20122902-MSVC_2
CMake suite maintained and supported by Kitware (kitware.com/cmake).
Please share your CMake files and details about how you are using GoogleTest (is it installed, etc...).
I think I might be running into this same issue, on Linux though. I'm getting this error
src/main_tests.cpp:32:18: error: use of undeclared identifier 'death_test_style'
GTEST_FLAG_SET(death_test_style, "threadsafe");
^
1 error generated.
make: *** [Makefile:165: src/main_tests.o] Error 1
Here's the compile command that was used
CC -lgtest -I/sw/spock/spack-envs/base/opt/linux-sles15-x86_64/gcc-7.5.0/googletest-1.11.0-xgcobwe63kttlqkm3z6ujt5faiooviqf/include -L/sw/spock/spack-envs/base/opt/linux-sles15-x86_64/gcc-7.5.0/googletest-1.11.0-xgcobwe63kttlqkm3z6ujt5faiooviqf/lib64 -lpthread -lhdf5_cpp -Ofast -std=c++11 -fopenmp -DHYDRO_GPU -DCUDA -DMPI_CHOLLA -DBLOCK -DPRECISION=2 -DPPMP -DHLLC -DVL -DDENSITY_FLOOR -DTEMPERATURE_FLOOR -DDE -DCPU_TIME -DOUTPUT -DHDF5 -DMPI_GPU -DPARALLEL_OMP -DN_OMP_THREADS=8 -DO_HIP -Isrc -I/opt/cray/pe/hdf5/1.12.0.6/crayclang/10.0/include -fopenmp -D__HIP_PLATFORM_HCC__= -D__HIP_PLATFORM_AMD__= -I"/opt/rocm-4.2.0/hip/include" -I"/opt/rocm-4.2.0/llvm/bin/../lib/clang/12.0.0" -I/opt/rocm-4.2.0/include -c src/main_tests.cpp -o src/main_tests.o
Googletest is installed as a module on a HPC cluster, I don't know any details about how it was installed unfortunately.
Here's the entirety of my main tests function. What other information do you require?
// External Libraries and Headers
#include <gtest/gtest.h>
// Local includes
#include "utils/testing_utilities.h"
/// This is the global variable to store the path to the root of Cholla
testingUtilities::GlobalString globalChollaRoot;
testingUtilities::GlobalString globalChollaBuild;
testingUtilities::GlobalString globalChollaMachine;
/*!
* \brief The main function for testing
*
* \param argc The number of CLI arguments
* \param argv A list of the CLI arguments
* \return int
*/
int main(int argc, char **argv) {
// First we initialize Googletest. Note, this removes all gtest related
// arguments from argv and argc
::testing::InitGoogleTest(&argc, argv);
GTEST_FLAG_SET(death_test_style, "threadsafe");
// Initialize the global cholla root path variable
globalChollaRoot.initPath("/ccs/home/rcaddy/Code/cholla");
globalChollaBuild.initPath("hydro");
globalChollaMachine.initPath("spock");
// Run test and return result
return RUN_ALL_TESTS();
}
// GTEST_LINKED_AS_SHARED_LIBRARY
// - Define to 1 when compiling tests that use
// Google Test as a shared library (known as
// DLL on Windows).
Need to define on dependent target to import symbols defined in gtest and link successfully.
See https://github.com/google/googletest/blob/df1544bcee0c7ce35cd5ea0b3eb8cc81855a4140/googletest/include/gtest/internal/gtest-port.h#L95
My 2 cents
We need to know:
- Does the build use
MSVCand has been compiled withBUILD_SHARED_LIBS=ON? ie. need some declspec dllimport/dllimport ref: https://learn.microsoft.com/en-us/cpp/cpp/dllexport-dllimport?view=msvc-170 - Does googletest has been compiled with
GTEST_HAS_ABSL=ON? note: needed to know which version of the MACROGTEST_DECLARE_..._is in use
if both are yes then this is the issue (with a fix) describe in:
- #4718 ...
DevNote on Super build integration
If googletest is not consumed through an installed version but integrated to the user build using FetchContent or add_subdirectory() (aka is in a "super build")...
Then you'll need this patch since current CMake stuff only set/use generator expression $<INSTALL_INTERFACE:> and not $<BUILD_INTERFACE:> for its compile definition related to dllexport/dllimport stuff
diff --git a/googletest/cmake/internal_utils.cmake b/googletest/cmake/internal_utils.cmake
index 580ac1c..b338398 100644
--- a/googletest/cmake/internal_utils.cmake
+++ b/googletest/cmake/internal_utils.cmake
@@ -185,11 +186,19 @@ function(cxx_library_with_type name type cxx_flags)
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} PRIVATE
+ "GTEST_CREATE_SHARED_LIBRARY=1")
target_compile_definitions(${name} INTERFACE
- $<INSTALL_INTERFACE:GTEST_LINKED_AS_SHARED_LIBRARY=1>)
+ $<BUILD_INTERFACE:GTEST_LINKED_AS_SHARED_LIBRARY=1>
+ $<INSTALL_INTERFACE:GTEST_LINKED_AS_SHARED_LIBRARY=1>
+ )
+ if(APPLE)
+ set_target_properties(${name} PROPERTIES
+ INSTALL_RPATH "@loader_path")
+ elseif(UNIX)
+ set_target_properties(${name} PROPERTIES
+ INSTALL_RPATH "$ORIGIN")
+ endif()
endif()
if (DEFINED GTEST_HAS_PTHREAD)
target_link_libraries(${name} PUBLIC Threads::Threads)
@@ -226,9 +235,8 @@ function(cxx_executable_with_flags name cxx_flags libs)
COMPILE_FLAGS "${cxx_flags}")
endif()
if (BUILD_SHARED_LIBS)
- set_target_properties(${name}
- PROPERTIES
- COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
+ target_compile_definitions(${name} PRIVATE
+ "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.
diff --git a/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h
index 8d27c2c..890c953 100644
--- a/googletest/include/gtest/internal/gtest-port.h
+++ b/googletest/include/gtest/internal/gtest-port.h
@@ -867,10 +867,10 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
#ifndef GTEST_API_
#ifdef _MSC_VER
-#if defined(GTEST_LINKED_AS_SHARED_LIBRARY) && GTEST_LINKED_AS_SHARED_LIBRARY
-#define GTEST_API_ __declspec(dllimport)
-#elif defined(GTEST_CREATE_SHARED_LIBRARY) && GTEST_CREATE_SHARED_LIBRARY
+#if defined(GTEST_CREATE_SHARED_LIBRARY) && GTEST_CREATE_SHARED_LIBRARY
#define GTEST_API_ __declspec(dllexport)
+#elif defined(GTEST_LINKED_AS_SHARED_LIBRARY) && GTEST_LINKED_AS_SHARED_LIBRARY
+#define GTEST_API_ __declspec(dllimport)
#endif
#elif GTEST_HAVE_ATTRIBUTE_(visibility)
#define GTEST_API_ __attribute__((visibility("default")))
note: When adding $<BUILD_INTERFACE:GTEST_LINKED_AS_SHARED_LIBRARY=1> to cxx_library(), since
gtest_main depends on gtest thus gtest_main will use the INTERFACE compile definition of gtest (aka GTEST_LINKED_AS_SHARED_LIBRARY=1) BUT we don't want to compile gtest_main with GTEST_LINKED_AS_SHARED_LIBRARY=1 or at least don't pass in the dllimport path, so a way to fix that is to change the preprocessor order to have GTEST_CREATE_SHARED_LIBRARY=1 (which is always a PRIVATE compile definition in cxx_library()) to be prefered when both are specified so gtest and gtest_main will be compiled using dllexport while target consumer will use dllimport by simply target_link_libraries to gtest or gtest_main without to manually set the compile definition...