Visual Studio 2019 and googletest: Linker errors [duplicate] - c++

I am trying to integrate GTest with CMake as seamlessly as possible. But the default build type for my test projects are /MDd and GTest defaults to /MTd. I am manually changing GTest project properties to emit debug DLL.
But every time I make changes to my CMakeLists.txt, GTest defaults back to /MTd. How do I stop this?

You can define gtest_force_shared_crt to ON before including gtest to achieve this. You can either do this via the command line:
cmake . -Dgtest_force_shared_crt=ON
or in your CMakeLists.txt:
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)

I think a better option is #Fraser's answer - in that case, cmake + gtest 'just work'.
It's worth mentioning that in order to override the internal gtest option setting, you need to put the variable in the cmake cache:
set( gtest_force_shared_crt ON CACHE BOOL "Always use msvcrt.dll" )

If Ted Middleton's answer doesn't work, try to use FORCE:
set( gtest_force_shared_crt ON CACHE BOOL "Always use msvcrt.dll" FORCE)
It worked for me

We solved the problem by bypassing GTest's own build system and compiling GTest as a CMake object library from its unity build source file gtest-all.cc:
# compile Google Test as an object library
add_library(gtest OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/gtest-1.6.0/src/gtest-all.cc")
set_property(TARGET gtest PROPERTY INCLUDE_DIRECTORIES
"${CMAKE_CURRENT_SOURCE_DIR}/gtest-1.6.0"
"${CMAKE_CURRENT_SOURCE_DIR}/gtest-1.6.0/include")
That way GTest will always be compiled with the same options that we use for the project.
A test executable that uses GTest can then be built in the following way:
add_executable(test_executable ${TESTS_SRC} $<TARGET_OBJECTS:gtest>)
add_test(NAME test COMMAND test_executable)

Related

CMake command line define macro without value

I have the following line in my CMakeLists.txt
add_compile_definitions(DEBUG=$(DEBUG))
so when I compile my code with Makefile, I can do this
make DEBUG=1
But what I really want is to just define the DEBUG macro without setting any value to it.
Is there a way I can do this on a command line with cmake?
With CMake you can, at configuration time, add some CMake variables. For example you can do this cmake -S <src_folder> -B <build_folder> -DDEBUG=ON. This way you will have access to the variable DEBUG in your CMake.
In your CMake you will have this code
if(DEBUG)
add_compile_definition(DEBUG)
endif()
(Note that instead of add_compile_definitions, it is recommended to use target_compile_definitions which will set your DEBUG macro only for one target and not globally to your project.
Example:
add_executable(my_target main.cpp)
target_compile_definition(my_target PRIVATE DEBUG)
PRIVATE means that this compile_definition will only be used by the target my_target and will not be propagated to others.)
But if you're only concern of the building type, I suggest that you use CMake variables that are already present within CMake. You can use CMAKE_BUILD_TYPE which will contains Debug, Release or whatever depending on what type of build you want. Your code will now be this
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_compile_definition(DEBUG)
endif()
And you can use this command line cmake -S <src_folder> -B <build_folder> -DCMAKE_BUILD_TYPE=Debug
And here the documentation https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
Note that this solution will only works for Mono-config generators like Makefile or Ninja and will not works with Visual Studio or Xcode

Visual Studio 2019 Test Explorer did not find c++ google tests

I want the c++ unit test written in google test displayed in the VS 2019 test explorer.
The tests are setup correctly and can be executed. The results are shown in the VS debug console/commandline-like window. No error messages besides the test dependent messages are shown.
I want start the tests form the test explorer and want to create test play lists.
I installed the google test adapter provided by the VS Installer. I followed guidelines and the suggested troubleshooting at TestAdapterForGoogleTest.
Does another way exist to get the google test to be dispalyed in the test explorer?
What are other known incompatibilities with google test and the VS test explorer?
I had the same problem as you. I'm having a main CMakeLists.txt, and another two CMakeLists.txt files in the subdirectories: one for the static library I'm testing and one for the test project itself.
For making sure the tests appear in the Test Explorer I had to move enable_testing() from the test subdirectory into the main CMakeLists.txt.
option(MY_PROJECT_TESTS "Build unit tests" ON)
if(MY_PROJECT_TESTS)
enable_testing()
add_subdirectory("test")
endif()
Then in the test subdirectory, I'm setting up the GoogleTest environment, and adding test the following way:
set(GTEST_DIR "googletest/googletest" CACHE PATH "gtest directory")
include(GoogleTest)
set(gtest_force_shared_crt OFF CACHE BOOL "" FORCE)
add_subdirectory("googletest")
project(My_project_test)
if (WIN32)
add_library(qtpcre STATIC IMPORTED)
set_target_properties(qtpcre PROPERTIES
IMPORTED_LOCATION_DEBUG ${QT5_DIR}/lib/qtpcre2d.lib
IMPORTED_LOCATION_RELEASE ${QT5_DIR}/lib/qtpcre2.lib
)
endif()
set(CommonTestLib
Qt5::Core
My_project
gtest_main
)
if (WIN32)
list(APPEND CommonTestLib
Ws2_32.lib
version.lib
Netapi32.lib
Userenv.lib
Crypt32.lib
Winmm.lib
qtpcre
)
endif()
add_executable (My_project_test test_main.cpp test_cases.cpp)
target_precompile_headers(My_project_test REUSE_FROM My_project)
target_link_libraries(My_project_test ${CommonTestLib})
gtest_add_tests(TARGET My_project_test EXTRA_ARGS --arg1 "${CMAKE_CURRENT_SOURCE_DIR}/data")
The very last line is important. Instead of gtest_add_tests, you can also use add_test. It needs different parameters but that works too when your goal is showing test cases in VS2019's Test Explorer.
The reason the above solution helped:
When you add enable_testing() to your top-level CMakeLists.txt file, it will generate a top-level CTestTestfile.cmake file in your build directory. This is needed by the Test Explorer to roll up all the test cases generated during the build process. If you've got a certain CMake hierarchy within your code structure you should have a similar one for CTest.
My top-level CTestTestfile.cmake file content:
# CMake generated Testfile for
# Source directory: C:/Projects/myproject
# Build directory: C:/Projects/myproject/out/build/x86-Debug
#
# This file includes the relevant testing commands required for
# testing this directory and lists subdirectories to be tested as well.
subdirs("test")
The lower level CTestTestfile.cmake file content:
# CMake generated Testfile for
# Source directory: C:/Projects/MyProject/test
# Build directory: C:/Projects/MyProject/out/build/x86-Debug/test
#
# This file includes the relevant testing commands required for
# testing this directory and lists subdirectories to be tested as well.
add_test(Environment.TestCommandLineArgument "C:/Projects/MyProject/out/build/x86-Debug/test/MyProject_test.exe" "--gtest_filter=Environment.TestCommandLineArgument" "--arg1" "C:/Projects/MyProject/test/data/")
set_tests_properties(Environment.TestCommandLineArgument PROPERTIES _BACKTRACE_TRIPLES "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-3.19/Modules/GoogleTest.cmake;380;add_test;C:/Projects/MyProject/test/CMakeLists.txt;38;gtest_add_tests;C:/Projects/MyProject/test/CMakeLists.txt;0;")
add_test(MyProjectExampleCreatorDevice.TestCreateExampleImage "C:/Projects/MyProject/out/build/x86-Debug/test/MyProject_test.exe" "--gtest_filter=MyProjectExampleCreatorDevice.TestCreateExampleImage" "--arg1" "C:/Projects/MyProject/test/data/")
set_tests_properties(MyProjectExampleCreatorDevice.TestCreateExampleImage PROPERTIES _BACKTRACE_TRIPLES "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-3.19/Modules/GoogleTest.cmake;380;add_test;C:/Projects/MyProject/test/CMakeLists.txt;38;gtest_add_tests;C:/Projects/MyProject/test/CMakeLists.txt;0;")
...
for me upgrading from 1.8.1.3 to 1.8.1.4 using nuget broke my project.
It switched
Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.3
to
Microsoft.googletest.v140.windesktop.msvcstl.dyn.rt-dyn.1.8.1.3\build\native\Microsoft.googletest.v140.windesktop.msvcstl.dyn.rt-dyn.targets"
revert back to the previous worked for me. (test explorer is now back) I think just making sure you use the static version as opposed to the dynamic should work as well.
There are multiple extensions that seem like they should be used.
If you follow the advice of https://learn.microsoft.com/en-us/visualstudio/test/how-to-use-google-test-for-cpp?view=vs-2022
you use the TestAdapterForGoogleTest from microsoft ? ()
There is another from Google. (Google test adapter). I have a project that used old versions of gtest. I installed this extension and things stopped working.
uninstall it and restart. rebuild and things seemed to work again.

CMake post-build custom command on multiple targets?

I'm learning CMake through a C++ hobby project using Visual Studio 2017, and the way I have it set up, I have one folder for source code and one folder for test code. I build the source code as a static library, and build the test code as an executable (using Catch2). The problem I have now is that these are two separate targets, and whenever one or both of these targets are rebuilt I want to run the testing executable. Now I can find out how to run a post-build event using ADD_CUSTOM_COMMAND, but that only works for a single target. Putting multiple targets after "TARGET" leads to only the last target being used (I tested this), and duplicating the custom command can lead to the tests being run twice, and also it seems like poor code style. Is there any way to do this elegantly? My CMake file looks like this:
# CMakeList.txt : Top-level CMake project file, do global configuration
# and include sub-projects here.
#
cmake_minimum_required (VERSION 3.8)
project ("SheepyEngine")
set (CMAKE_CXX_STANDARD 17)
set (HEADER_FILES 3rdParty/CImg/CImg.h)
set (SOURCE_DIRECTORY Source)
set (TEST_DIRECTORY Test)
# Include sub-projects.
add_subdirectory ("Source")
add_subdirectory ("Test")
# Include libraries
include_directories (
"${CMAKE_CURRENT_LIST_DIR}/3rdParty/CImg"
"${CMAKE_CURRENT_LIST_DIR}/3rdParty/Catch2/single_include"
)
add_library (SheepyEngine STATIC
"${SOURCE_DIRECTORY}/Game.cpp"
"${SOURCE_DIRECTORY}/Game.h"
"${SOURCE_DIRECTORY}/GameObject.h"
${HEADER_FILES})
target_include_directories(SheepyEngine PRIVATE ${CMAKE_CURRENT_LIST_DIR}/3rdParty/CImg/)
add_executable(SheepyEngineTest "${TEST_DIRECTORY}/test.cpp" "3rdParty/Catch2/single_include/catch.hpp")
target_include_directories(SheepyEngineTest PRIVATE ${CMAKE_CURRENT_LIST_DIR}/3rdParty/Catch2/)
# TODO: Add tests and install targets if needed.
if(${RUN_TESTS})
ADD_CUSTOM_COMMAND(
TARGET SheepyEngineTest SheepyEngine
POST_BUILD
COMMAND ${CMAKE_CURRENT_LIST_DIR}/Build/Debug/SheepyEngineTest.exe
)
endif()
The SheepyTestProgram target needs to be dependent on SheepyEngine:
target_link_libraries(SheepyEngineTest SheepyEngine)
Then the target of add_custom_command will be just SheepyEngineTest (add_custom_command accepts only a single target).

One click building my project with Cmake & Msbuild (vs2010) with a batch file

I have to make a one click build of a projet made for Cmake ( already works on Linux) with a batch file that downloads all the 3rd party libraries and compiles them. (win64)
If posible i dont want to change projets CMakeLists.txt.
I already build the project in VS2010 GUI. and i had to change the folowing:
a. had to change Configuration properties-C++-Command line: added /DWNT /D "CAD_STATIC"
b. had to add a long list of libraries in Configuration properties- Linker input- additional dependencies.
c. add library directories for those libraries
d. add include directories.
The project compiled and worked ok.
Now i need to make the same with only batch commands.
I already build the project file with cmake with:
cmake ..\projectsource -G "Visual Studio 10 Win64" -DGLEW_LIBRARY:FILEPATH=%myroot%\glew\trunk\lib\Release\glew.lib -DGLUT_glut_LIBRARY:FILEPATH=%myroot%\freeglut\trunk\lib\Release\freeglut.lib -DMKL_LIBRARIES:FILEPATH=%myroot%\mkl\em64t\lib\mkl_core.lib -DOpenCascade_INCLUDE_DIR:PATH=%myroot%\OpenCascade
Now i need a command like "devenv project.sln /useenv " that does the same as the stuff i did under #2.
I tried with a env include & lib like:
set "include=%myroot%\glew\trunk\include;%myroot%\freeglut\trunk\include;%myroot%\mkl\include;%myroot%\qt\include;%myroot%\OpenCascade\include\oce;%myroot%\trimo\src\CadModel;%include%"
set "lib=%myroot%\glew\trunk\lib\Release\*.lib;%myroot%\freeglut\trunk\lib\Release\*.lib;%myroot%\mkl\em64t\lib\*.lib;%myroot%"\qt\lib\*.lib;%myroot%\OpenCascade\Win64\lib\*.lib;%lib%"
All the help is very much appreciated. I'm stuck. Thanks
Edit:
I got another problem:
How can i unlink a library that gets linked in a project.sln automaticly by cmake?
will "lib=%myroot%\glew\trunk\lib\Release*.lib; link all the .lib files like u would get if u put all the libs in a vs2010 gui -Linker input- additional dependencies?
If you're already setting the required include and lib variables, then probably all that's missing is:
set "cl=/DWNT /DCAD_STATIC"
then you should be able to use
devenv project.sln /useenv /build
Note, you've also got libpath available to set search paths for the libraries if required.
Answers to further questions
I don't know of a way to do that.
No. I hadn't noticed you were doing that in your original question - sorry! The LIB env var sets search paths in which libs could be found, it's not for the full path to the actual lib itself.
What you're trying to achieve is exactly the sort of scenario at which CMake excels. You're fighting CMake here when it's probably the solution to the problems :-)
If I were you, I'd edit the CMakeLists.txt to include things like:
SET(MY_ROOT <path to %myroot%>)
FIND_LIBRARY(GLEW_LIBRARY glew ${MY_ROOT}/glew/trunk/lib/Release)
IF(NOT GLEW_LIBRARY)
MESSAGE(FATAL_ERROR "glew.lib not found in ${MY_ROOT}/glew/trunk/lib/Release")
ENDIF()
FIND_LIBRARY(GLUT_glut_LIBRARY freeglut ${MY_ROOT}/freeglut/trunk/lib/Release)
IF(NOT GLUT_glut_LIBRARY)
MESSAGE(FATAL_ERROR "freeglut.lib not found in ${MY_ROOT}/freeglut/trunk/lib/Release")
ENDIF()
FIND_LIBRARY(MKL_LIBRARIES mkl_core ${MY_ROOT}/mkl/em64t/Release)
IF(NOT MKL_LIBRARIES)
MESSAGE(FATAL_ERROR "mkl_core.lib not found in ${MY_ROOT}/mkl/em64t/Release")
ENDIF()
INCLUDE_DIRECTORIES(${MY_ROOT}/OpenCascad)
ADD_DEFINITIONS(-DWNT -DCAD_STATIC)
TARGET_LINK_LIBRARIES(<your target>
${GLEW_LIBRARY}
${GLUT_glut_LIBRARY}
${MKL_LIBRARIES}
<any other libs...>
)
This is all Windows-specific, and Release-specific. You could adapt the FIND_LIBRARY calls to cater for Unix/OSX options too, or you could wrap this in IF(WIN32) ... ENDIF() blocks.
You could also do FIND_LIBRARY calls for the Debug versions too if required (giving them different variable names) and adding them like:
TARGET_LINK_LIBRARIES(<your target>
optimized ${GLEW_LIBRARY}
optimized ${GLUT_glut_LIBRARY}
optimized ${MKL_LIBRARIES}
debug ${GLEW_LIBRARY_DEBUG}
debug ${GLUT_glut_LIBRARY_DEBUG}
debug ${MKL_LIBRARIES_DEBUG}
<any other libs...>
)
You'll also be able to remove whatever libraries you want from whatever targets you want by modifying the list of libs passed in the TARGET_LINK_LIBRARIES call(s).
If you want to grab all *.lib files in a directory, add something like this:
FILE(GLOB ALL_GLEW_LIBS "${MY_ROOT}/glew/trunk/lib/Release/*.lib")
TARGET_LINK_LIBRARIES(<your target> ${ALL_GLEW_LIBS})
If you do use the GLOB call, and you also need Debug and Release, be sure to prefix each list item with debug or optimized as appropriate, e.g.
FOREACH(GLEW_ITR ${ALL_GLEW_LIBS_RELEASE})
SET(ALL_GLEW_LIBS ${ALL_GLEW_LIBS} optimized ${GLEW_ITR})
ENDFOREACH()
FOREACH(GLEW_ITR ${ALL_GLEW_LIBS_DEBUG})
SET(ALL_GLEW_LIBS ${ALL_GLEW_LIBS} debug ${GLEW_ITR})
ENDFOREACH()
TARGET_LINK_LIBRARIES(<your target> ${ALL_GLEW_LIBS})
If all this is then catered for by CMake, you don't need to set any env vars in the batch script; you just do:
devenv project.sln /build

Linking different libraries for Debug and Release builds in Cmake on windows?

So I've got a library I'm compiling and I need to link different third party things in depending on if it's the debug or release build (specifically the release or debug versions of those libraries). Is there an easy way to do this in Cmake?
Edit: I should note I'm using visual studio
According to the CMake documentation:
target_link_libraries(<target> [lib1 [lib2 [...]]] [[debug|optimized|general] <lib>] ...)
A "debug", "optimized", or "general"
keyword indicates that the library
immediately following it is to be used
only for the corresponding build
configuration.
So you should be able to do this:
add_executable( MyEXE ${SOURCES})
target_link_libraries( MyEXE debug 3PDebugLib)
target_link_libraries( MyEXE optimized 3PReleaseLib)
Somehow the answer from #Mike Willekes got CMake linking in the same target both release and debug for me :(
I only got this working by setting both configurations in one line, as suggested by #sakra in a related question - and doing so for every library that needed to be linked:
target_link_libraries ( app
debug ${Boost_FILESYSTEM_LIBRARY_DEBUG}
optimized ${Boost_FILESYSTEM_LIBRARY_RELEASE} )
target_link_libraries ( app
debug ${Boost_LOG_LIBRARY_DEBUG}
optimized ${Boost_LOG_LIBRARY_RELEASE} )
target_link_libraries ( app
debug ${Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG}
optimized ${Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE} )
# ...
I would like to add a few notes to the previous answers.
If you need to create a list of multiple files you want to link and store that in a cache variable then you need to add the optimized or debug specified before each and every library. This can be especially useful for larger makefiles/projects.
So for example you could do something like this:
set( MyFavLib_LIBRARIES
debug debug/module1.lib optimized release/module1.lib
debug debug/module2.lib optimized release/module2.lib )
target_link_libraries( app ${MyFavLib_LIBRARIES} )
What worked for me was to use $(Configuration) macro in a lib path provided to cmake.
So, assuming libs are stored in separate, correctly named folders, e.g.:
C:\boost\lib\Debug\libfoo.lib
C:\boost\lib\Release\libfoo.lib
You can then call cmake with:
cmake -G "Visual Studio 10 2010" -DBOOST_LIBRARYDIR=C:\boost\lib\$(Configuration)\libfoo.lib
That'll generate .vcxproj with Additional Dependencies including C:\boost\lib\$(Configuration)\libfoo.lib, what is evaluated to either C:\boost\lib\Release\libfoo.lib or C:\boost\lib\Debug\libfoo.lib depending on a chosen Configuration.
target_link_libraries with optimize and debug doesn't work for me. I follow the post of Mike Willekes, but release config also import debug library file in visual studio. Then, I use the following cmake code to solving this problem
add_library(BoostLib STATIC IMPORTED)
set_target_properties(BoostLib PROPERTIES
IMPORTED_LOCATION_DEBUG ${BoostLibPath}/debug/module1.lib
IMPORTED_LOCATION_RELEASE ${BoostLibPath}/release/module1.lib)
target_link_libraries(AppTarget BoostLib)