Reputation: 93
As a bit of background, I have a project that I have been developing with Visual Studio and VCPKG manifest mode for some time, it contains one static library project and one unit test project. Everything has been working correctly. I'm now trying to migrate this solution to use CMake, this is my first time using CMake.
With CMake the VCPKG dependencies install correctly, and both the static library and unit tests compile, however it fails on the linking step with a large number of linker errors all related to the GoogleTest library. Here is the first, as an example:
CppSlippiTest.obj : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl testing::internal::FormatMatcherDescription(bool,char const *,class std::vector<char const*,class std::allocator<char const *> > const &,class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > const &)" (?FormatMatcherDescription@internal@testing@@YA?AV$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_NPEBDAEBV?$vector@PEBDV$allocator@PEBD@std@@@4@AEBV?$vector@V?$basic_string@DU?$char_traits@D@std@@V$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@4@@Z) referenced in function "private: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl cpp_slippi::MatchOptionalMatcherP2<class testing::internal::Eq2Matcher,class std::optional<unsigned char> >::gmock_Impl<class std::optional<unsigned char> const &>::FormatDescription(bool)const " (?FormatDescription@$gmock_Impl@AEBV?$optional@E@std@@@$MatchOptionalMatcherP2@VEq2Matcher@internal@testing@@V?$optional@E@std@@@cpp_slippi@@AEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@_N@Z) [C:\Users\Derek\Projects\CppSlippi\build\Test.vcxproj]
There are 36 more of these.
Here is my CMakeLists.txt, slightly abridged for clarity:
cmake_minimum_required(VERSION 3.12...3.24)
# Must be before project()
set(VCPKG_TARGET_TRIPLET x64-windows-static)
project(CppSlippi
VERSION 1.0
DESCRIPTION "Slippi replay file parsing library for C++."
LANGUAGES CXX)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(GTest CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
add_library(CppSlippi STATIC
CppSlippi/src/CppSlippi.cpp
CppSlippi/src/CppSlippi.h
...)
target_include_directories(CppSlippi PUBLIC CppSlippi/src)
target_compile_features(CppSlippi PUBLIC cxx_std_20)
target_compile_options(CppSlippi PUBLIC /MTd)
set_target_properties(CppSlippi PROPERTIES CXX_EXTENSIONS OFF)
target_link_libraries(CppSlippi PUBLIC nlohmann_json::nlohmann_json)
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
include(CTest)
include(GoogleTest)
endif()
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING)
add_executable(Test
Test/src/CppSlippiTest.cpp
...)
target_include_directories(Test PUBLIC Test/src)
target_compile_features(Test PUBLIC cxx_std_20)
target_compile_options(Test PRIVATE /bigobj /MTd)
set_target_properties(Test PROPERTIES CXX_EXTENSIONS OFF)
target_link_libraries(Test PUBLIC
CppSlippi
nlohmann_json::nlohmann_json
GTest::gtest_main)
gtest_discover_tests(Test)
endif()
Here is my VCPKG manifest:
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
"name": "cpp-slippi",
"version": "1.0.0",
"description": "C++ Slippi replay parser.",
"builtin-baseline": "68b7fec22eb5fd9c0236b1e42b3c0deb8e771b37",
"dependencies": [
"gtest",
"nlohmann-json"
],
"supports": "windows"
}
And to build this I am running:
cmake --build build --target Test
I turned on --verbose
to get more information, and this is the link command that CMake is running:
Link:
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.34.31933\bin\HostX64\x64\link.exe /ERRORREPO
RT:QUEUE /OUT:"C:\Users\Derek\Projects\CppSlippi\build\Debug\Test.exe" /INCREMENTAL /ILK:"Test.dir\Debug\Test.ilk" /N
OLOGO /NATVIS:"C:\Users\Derek\Projects\CppSlippi\build\vcpkg_installed\x64-windows-static\share\nlohmann_json\nlohman
n_json.natvis" Debug\CppSlippi.lib "vcpkg_installed\x64-windows-static\debug\lib\manual-link\gtest_main.lib" "vcpkg_i
nstalled\x64-windows-static\debug\lib\gtest.lib" kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib
oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifes
t:embed /DEBUG /PDB:"C:/Users/Derek/Projects/CppSlippi/build/Debug/Test.pdb" /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE
/NXCOMPAT /IMPLIB:"C:/Users/Derek/Projects/CppSlippi/build/Debug/Test.lib" /MACHINE:X64 /machine:x64 Test.dir\Debug
\CppSlippiTest.obj ...
Note the presence of gtest_main.lib
and gtest.lib
, these are the libraries that I believe should include the missing functions. I have checked that these files are present at the locations shown.
I know that in Visual Studio using the GoogleTest main requires adding an AdditionalDependency manually, but from all the instructions I can find this should not be necessary in CMake and the .lib is already in the command line. I did try using target_link_directories
anyways, but this did not help.
At this point I am baffled and searching on Google and Stack Overflow has failed to turn up any help.
Upvotes: 0
Views: 1374
Reputation: 38863
You link only one of 4 GoogleTest libraries to your app
target_link_libraries(Test PUBLIC
CppSlippi
nlohmann_json::nlohmann_json
GTest::gtest_main)
Depending on the application needs, it should be linked to at least one more library
target_link_libraries(Test PUBLIC
CppSlippi
nlohmann_json::nlohmann_json
GTest::gtest_main
GTest::gtest)
Or
target_link_libraries(Test PUBLIC
CppSlippi
nlohmann_json::nlohmann_json
GTest::gmock_main
GTest::gmock
GTest::gtest)
Upvotes: 1