我相信这不是这篇文章的骗局,因为我的情况似乎与链接文章中描述的相反:OP的问题是链接他的调试版本时的链接错误(他们的发布版本很好) ;我的错误在于链接我的发布版本(我的调试版本没问题)。
我正在学习 CMake,在 Windows 环境中工作,我的学习材料让我下载 Google Test(至
C:\libs\googletest-release-1.11.0
)并按如下方式构建/安装它:
cmake -DCMAKE_INSTALL_PREFIX=build\install-dir -Dgtest_force_shared_crt=ON -S . -B build
cmake --build build
cmake --build build --target install
此过程显示成功:我没有看到任何错误,并且安装包已安装到
C:\libs\googletest-release-1.11.0\build\install-dir
我创建了(从学习材料下载)一个使用已安装的 Google Test 的 CMake 项目。
项目构建并通过调试构建成功运行其单元测试。
但是,当我尝试构建发布版本时,我遇到了链接错误,我无法识别这些链接错误是我的项目的一部分,而且我无法弄清楚问题是什么。
以下是我如何在调试配置中成功构建项目并运行单元测试:
cmake -DCMAKE_PREFIX_PATH=C:/libs/googletest-release-1.11.0/build/install-dir -S . -B build
cmake --build build --config Debug
.\build\out\Debug\CalculatorTests.exe
以下是我尝试在发布配置中构建项目的方法:
cmake -DCMAKE_PREFIX_PATH=C:/libs/googletest-release-1.11.0/build/install-dir -S . -B build
cmake --build build --config Release
第 2 步是我收到链接错误的地方,我根本不认识或不知道如何处理:
gmock_maind.lib(gtest-all.obj) : error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': value '2' doesn't match value '0' in CalculatorTests.obj [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gtest-all.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MDd_DynamicDebug' doesn't match value 'MD_DynamicRelease' in CalculatorTests.obj [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gmock_main.obj) : error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': value '2' doesn't match value '0' in CalculatorTests.obj [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gmock_main.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MDd_DynamicDebug' doesn't match value 'MD_DynamicRelease' in CalculatorTests.obj [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gmock-all.obj) : error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': value '2' doesn't match value '0' in CalculatorTests.obj [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gmock-all.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MDd_DynamicDebug' doesn't match value 'MD_DynamicRelease' in CalculatorTests.obj [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
LINK : warning LNK4098: defaultlib 'MSVCRTD' conflicts with use of other libs; use /NODEFAULTLIB:library [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gtest-all.obj) : error LNK2019: unresolved external symbol __imp__invalid_parameter referenced in function "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl std::operator+<char,struct std::char_traits<char>,class std::allocator<c
har> >(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &&,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &&)" (??$?HDU?$char_traits@D@std@@V?$allocator@D@1@@std@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$all
ocator@D@2@@0@$$QEAV10@0@Z) [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gmock-all.obj) : error LNK2001: unresolved external symbol __imp__invalid_parameter [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gtest-all.obj) : error LNK2019: unresolved external symbol __imp__CrtSetDbgFlag referenced in function "public: __cdecl testing::internal::`anonymous namespace'::MemoryIsNotDeallocated::MemoryIsNotDeallocated(void)" (??0MemoryIsNotDeallocated@?A0xd01e04df@internal@testing@@QE
AA@XZ) [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gtest-all.obj) : error LNK2019: unresolved external symbol __imp__calloc_dbg referenced in function "char * __cdecl std::_Maklocstr<char>(char const *,char *,struct _Cvtvec const &)" (??$_Maklocstr@D@std@@YAPEADPEBDPEADAEBU_Cvtvec@@@Z) [C:\linking_to_external_libraries\build\
src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gmock_main.obj) : error LNK2001: unresolved external symbol __imp__calloc_dbg [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gmock-all.obj) : error LNK2001: unresolved external symbol __imp__calloc_dbg [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gtest-all.obj) : error LNK2019: unresolved external symbol __imp__CrtDbgReport referenced in function "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl std::operator+<char,struct std::char_traits<char>,class std::allocator<char>
>(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &&,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &&)" (??$?HDU?$char_traits@D@std@@V?$allocator@D@1@@std@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocato
r@D@2@@0@$$QEAV10@0@Z) [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gmock-all.obj) : error LNK2001: unresolved external symbol __imp__CrtDbgReport [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gtest-all.obj) : error LNK2019: unresolved external symbol __imp__CrtSetReportFile referenced in function "public: int __cdecl testing::UnitTest::Run(void)" (?Run@UnitTest@testing@@QEAAHXZ) [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
gmock_maind.lib(gtest-all.obj) : error LNK2019: unresolved external symbol __imp__CrtSetReportMode referenced in function "public: int __cdecl testing::UnitTest::Run(void)" (?Run@UnitTest@testing@@QEAAHXZ) [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
C:\linking_to_external_libraries\build\out\Release\CalculatorTests.exe : fatal error LNK1120: 6 unresolved externals [C:\linking_to_external_libraries\build\src\calculator\test\CalculatorTests.vcxproj]
有什么问题吗?为什么使用 Release 配置构建项目失败?
我刚刚学习 CMake,所以我的理解可能不完整且不稳定,但我的印象是 CMake 应该抽象出链接到正确的构建配置特定版本的库的细节,以及在 CMake 配置之后/生成步骤,所期望的就是使用所需的配置运行
cmake --config ...
。
MCVE 所需的项目资源(计入此 udemy 课程):
(我认为项目源代码与该问题并不是非常相关,但我提供了完整性。我认为问题出在 CMake、Windows 共享库,也许还有多配置构建领域)
C:\linking_to_external_libraries>tree /f
Folder PATH listing for volume Windows
Volume serial number is 748B-8737
C:.
│ CMakeLists.txt
│
└───src
│ CMakeLists.txt
│
├───application
│ CMakeLists.txt
│ main.cpp
│
├───calculator
│ │ Calculator.cpp
│ │ Calculator.h
│ │ CMakeLists.txt
│ │
│ └───test
│ CalculatorTests.cpp
│ CMakeLists.txt
│
└───library
CMakeLists.txt
ServerProvider.cpp
ServerProvider.h
# ./CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(FindingExternalLibraries LANGUAGES CXX VERSION 2.5.0)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/out")
add_subdirectory(src)
# ./src/CMakeLists.txt
add_subdirectory(library)
add_subdirectory(calculator)
add_subdirectory(application)
# ./src/application/CMakeLists.txt
set(SOURCE_FILES main.cpp)
add_executable(Application ${SOURCE_FILES})
target_link_libraries(Application PUBLIC MyLibrary)
target_link_libraries(Application PUBLIC Calculator)
target_compile_definitions(Application PRIVATE APP_PROJECT_VERSION="${CMAKE_PROJECT_VERSION}")
// ./src/application.main.cpp
#include <iostream>
#include <ServerProvider.h>
#include <Calculator.h>
int main()
{
std::cout << "Application version: " << APP_PROJECT_VERSION << std::endl;
std::cout << "Connecting to " << ServerProvider::getHostName() << std::endl;
std::cout << "3 + 6 = " << Calculator::sum(3, 6) << std::endl;
return 0;
}
// ./src/calculator/Calculator.cpp
#include "Calculator.h"
namespace Calculator
{
int sum(int a, int b)
{
return a + b;
}
}
// ./src/calculator/Calculator.h
#pragma once
namespace Calculator
{
int sum(int a, int b);
};
# ./src/calculator/CMakeLists.txt
set(SOURCE_FILES Calculator.cpp)
add_library(Calculator STATIC ${SOURCE_FILES})
target_include_directories(Calculator INTERFACE .)
add_subdirectory(test)
// ./src/calculator/test/CalculatorTests.cpp
#include <gtest/gtest.h>
#include <Calculator.h>
TEST(SimpleTest, ExampleTestCase)
{
// given:
int a = 5;
int b = 10;
// when:
const auto result = Calculator::sum(a, b);
// expected:
EXPECT_EQ(result, 15);
}
# ./src/calculator/test/CMakeLists.txt
set(TEST_FILES CalculatorTests.cpp)
find_package(GTest CONFIG REQUIRED)
add_executable(CalculatorTests ${TEST_FILES})
target_link_libraries(CalculatorTests PRIVATE GTest::gmock_main)
target_link_libraries(CalculatorTests PRIVATE Calculator)
# ./src/library/CMakeLists.txt
set(SOURCE_FILES ServerProvider.cpp)
set(APP_CONFIGURATION_TYPE "Development" CACHE STRING "Configuration type")
set_property(CACHE APP_CONFIGURATION_TYPE PROPERTY STRINGS Development Test Production)
option(APP_BUILD_LIB_AS_SHARED "Decides if MyLibrary is build as shared lib" ON)
if ($CACHE{APP_BUILD_LIB_AS_SHARED})
add_library(MyLibrary SHARED ${SOURCE_FILES})
if (MSVC)
target_compile_definitions(MyLibrary PRIVATE "APP_LIBRARY_API=__declspec(dllexport)")
target_compile_definitions(MyLibrary INTERFACE "APP_LIBRARY_API=__declspec(dllimport)")
else ()
target_compile_definitions(MyLibrary PUBLIC "APP_LIBRARY_API=")
endif ()
else ()
add_library(MyLibrary STATIC ${SOURCE_FILES})
target_compile_definitions(MyLibrary PUBLIC "APP_LIBRARY_API=")
endif ()
target_include_directories(MyLibrary INTERFACE .)
if ($CACHE{APP_CONFIGURATION_TYPE} STREQUAL "Development")
target_compile_definitions(MyLibrary PRIVATE APP_HOSTNAME="http://127.0.0.1")
elseif($CACHE{APP_CONFIGURATION_TYPE} STREQUAL "Test")
target_compile_definitions(MyLibrary PRIVATE APP_HOSTNAME="http://test.com")
else()
target_compile_definitions(MyLibrary PRIVATE APP_HOSTNAME="http://clientdatabaseadress.com")
endif ()
// ./src/library/ServerProvider.cpp
#include "ServerProvider.h"
namespace ServerProvider
{
std::string getHostName()
{
return APP_HOSTNAME;
}
}// namespace ServerProvider
// ./src/library/ServerProvider.h
#pragma once
#include <string>
namespace ServerProvider
{
APP_LIBRARY_API std::string getHostName();
};
我通过实验偶然发现了这一点;在我的学习材料中没有明确指出这是必要的,但我通过将不同的想法放在一起来猜测它:
看起来当我为其发布配置构建项目时,它需要与 Google 测试发布配置共享库链接。 IE。我需要执行以下操作来构建 Google 测试:
cmake -DCMAKE_INSTALL_PREFIX=build\install-dir -Dgtest_force_shared_crt=ON -S . -B build
cmake --build build
cmake --build build --config Release --target install
我猜测这会构建并安装Google测试共享库的发布配置,这与调试配置共享库有显着不同;想必不仅仅是调试符号的存在/不存在。
我只是猜测这个联系;我不完全明白发生了什么,所以我希望另一个回答者能够出现并填补空白:我以前从未见过这个“符号不匹配”的问题(我主要在Linux上开发;Windows有点新)对我来说)。
我不明白为什么
gmock_maind.lib(gtest-all.obj)
和CalculatorTests.obj
都会有_ITERATOR_DEBUG_LEVEL
的定义:通常一段代码定义一个符号,而其他人使用它。我的项目源代码中没有明确使用 _ITERATOR_DEBUG_LEVEL
。