googletest icon indicating copy to clipboard operation
googletest copied to clipboard

"unresolved external symbol" using FLAGS_gtest_death_test_style on MS Windows

Open upnplib opened this issue 4 years ago • 4 comments

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).

upnplib avatar Sep 06 '21 13:09 upnplib

Please share your CMake files and details about how you are using GoogleTest (is it installed, etc...).

derekmauro avatar Sep 15 '21 13:09 derekmauro

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();
}

bcaddy avatar Sep 30 '21 15:09 bcaddy

//   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

dimhotepus avatar Oct 24 '24 21:10 dimhotepus

My 2 cents

We need to know:

  • Does the build use MSVC and has been compiled with BUILD_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 MACRO GTEST_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...

Mizux avatar Feb 05 '25 13:02 Mizux