我正在构建一个“框架”库,我正在尝试将其集成到 Google 测试中。这是一个非常小的库,最后给我一个 .so
或 .dll
文件。
当我开始测试我的库时,我发现一个配置(详情如下)在我的 linux 环境中的 CMakeFile
上运行良好。但是当我尝试使用 MSVC14
的 MSBuild
运行同一个项目时,它给了我一个链接错误
LINK: fatal error LNK1104:无法打开文件 '..\src\Debug\foobar.lib'
我认为我的 cmake 猜错了库名称(foobar.lib
而不是 foobar.dll
),但我找不到原因和方式修复它。
此外,我不知道这是否真的是我测试它的最佳方式。我想要的是一种无需 main.cpp
文件即可测试整个框架(初始化、创建内容、检查返回值等)的方法,同时开始创建单元测试。
所以,我的问题是.. 在 Windows 环境下,链接器找不到由 src/CMakeLists.txt
构建的 foobar
库,我做错了什么? (我检查过,lib 是在“src/Debug/foobar.dll”中创建的,与出现错误的目录相同,并且工作正常)
此外,我的方法是否错误到 Windows 不想处理?大声笑我的意思是,像我想做的那样做是错误的吗?并不是我不想做单元测试,我很快就会做,但我真的很喜欢在开始做之前不使用任何外部 exec 二进制文件来构建和尝试我的库。
谢谢!
OBS:
我的 google 测试在 linux 和 windows 上都运行良好;
如果删除链接到
foobar
库的 FooBar 测试,我可以运行测试 FooA。使用我的 linux 环境,此配置完美运行。
更新:
正如@vre 所建议的那样,我找到了宏 __declspec(dllexport)
并将其放在我的 FooBar
类名之前并且编译通过了,但是当我运行时它崩溃了并且编译时抛出此警告:
warning C4251: 'FooBar::_impl': class 'std::unique_ptr<FooBar::FooBarImpl,
std::default_delete<_Ty>>' needs to have dll-interface to be used by clients of class 'FooBar'
那是因为我有一个 FooBar
类的 PImp 实现。所以,我有这个:
class __declspec(dllexport) FooBar
{
...
private:
class FooBarImpl;
std::unique_ptr<FooBarImpl> _impl;
}
我还不知道它是什么意思。试图找出它崩溃的原因。
我的项目有这个文件树:
├── CMakeLists.txt
├── include
| ├── FooBar.hpp
├── src
│ ├── CMakeLists.txt
│ ├── FooBar.cpp
│ ├── FooA
│ │ └── CMakeLists.txt
│ ├── FooB
│ │ └── CMakeLists.txt
│ └── FooC
│ └── CMakeLists.txt
└── test
├── CMakeLists.txt
├── FooBar
│ └── FooBarTest.hpp
├── FooA
│ ├── FakeBar.hpp
│ ├── FooATest.hpp
│ └── mockObj.hpp
我的主要CMakeLists.txt
是这样的:
...
set(FOOBAR_INCLUDE "${PROJECT_SOURCE_DIR}/include/FooBar.hpp")
# Include src main CMakeLists
add_subdirectory("${PROJECT_SOURCE_DIR}/src")
# Include tests if enabled
if (test)
add_subdirectory("${PROJECT_SOURCE_DIR}/test")
endif ()
我的src/CMakeLists.txt
:
...
set(FOOBAR_SOURCES "FooBar.cpp")
# Build
add_library(foobar SHARED ${FOOBAR_SOURCES} ${FOOBAR_INCLUDE})
# Links the library with components.
target_link_libraries(foobar FooA FooB FooC)
我的test/CMakeLists.txt
是这样的:
enable_testing()
# Include directories used for testing.
include_directories("${CMAKE_SOURCE_DIR}/src"
"${CMAKE_SOURCE_DIR}/include"
"FooA/"
"FooBar/")
# Include the files for testing.
set(INCLUDE_TESTS "${CMAKE_SOURCE_DIR}/src/FooA/FooA.cpp"
"${CMAKE_SOURCE_DIR}/src/FooA/Bar.cpp")
# Include the test source files.
set(TEST_SOURCES "main.cpp"
"FooBar/JepluTest.hpp"
"FooA/FakeBar.hpp"
"FooA/FooATest.hpp")
# Build
add_executable(foobar-test ${TEST_SOURCES} ${INCLUDE_TESTS})
# Links the library with components. (HERE IS WHERE OCCURS THE PROBLEM)
target_link_libraries(foobar-test gtest foobar)
# Not really important right now
add_test(NAME foobar-test COMMAND foobar-test)
最佳答案
重新表述和增强我之前的评论:
您需要从 Windows 上的 DLL 导出符号,否则不会创建导入库,这就是 MSBuild 所提示的。
首先,您应该将以下结构添加到您的 FooBar.hpp header 中:
#ifdef WIN32
#ifdef FOOBARLIB_EXPORTS
#define FOOBARLIB_API __declspec(dllexport)
#else
#define FOOBARLIB_API __declspec(dllimport)
#endif
#else
#define FOOBARLIB_API
#endif
稍后将要导出的类、函数和符号标记如下:
void FOOBARLIB_API foobar(char*)
{
}
在您的 CMakeLists.txt
创建共享库目标 foobar
后添加行:
target_compile_definitions(foobar PRIVATE FOOBARLIB_EXPORTS)
编辑:
正如@vre 评论的那样,这些 CMake
属性也是必需的,因为 Windows 不会加载位于另一个文件夹中的 DLL
,从而在它尝试运行可执行文件时导致崩溃。因此,当生成 DLL
并设置 CMAKE_RUNTIME_OUTPUT_DIRECTORY
变量时,输出库将转到与测试 .exe
文件相同的目录。
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
关于c++ - 将我的主输出库与我的测试可执行文件链接时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50123302/