c++ - 将我的主输出库与我的测试可执行文件链接时出现问题

标签 c++ visual-studio cmake msbuild

我正在构建一个“框架”库,我正在尝试将其集成到 Google 测试中。这是一个非常小的库,最后给我一个 .so.dll 文件。

当我开始测试我的库时,我发现一个配置(详情如下)在我的 linux 环境中的 CMakeFile 上运行良好。但是当我尝试使用 MSVC14MSBuild 运行同一个项目时,它给了我一个链接错误 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/

相关文章:

c++ - 重新分配给尚未准备好的 future 时会发生什么

c++ - 在 vector 中存储模板化对象指针并通过基类指针访问

c++ - boost::asio::ip::tcp::socket - 如何绑定(bind)到特定的本地端口

c++ - C++/Qt 应用程序的跨平台持续集成管道

c++ - 增加计数器时避免竞争条件

visual-studio - 为什么我可以在没有管理员权限的情况下将 visual studio 附加到进程

asp.net - 设置 .net Web 应用程序的默认页面

c# - XamlParseException : Could not load file or assembly 'ResourceLibrary, ...' or one of its dependencies. 系统找不到指定的文件

c++ - 配置 C++ 应用程序构建的简单方法

cmake - CMAKE字符串比较失败