将主输出库与测试可执行文件

时间:2018-05-01 20:23:01

标签: c++ visual-studio cmake msbuild

我正在建立一个“框架”库,我试图整合Google测试。它是一个非常小的库,最后给我一个.so.dll文件。

当我开始测试我的库时,我发现一个配置(下面的详细信息)在我的linux环境中的CMakeFile上工作正常。但是当我尝试使用MSBuild MSVC14运行同一项目时,它会给我一个链接错误 LINK : fatal error LNK1104: cannot open file '..\src\Debug\foobar.lib'

我认为我的cmake猜测lib名称错误(foobar.lib而不是foobar.dll),但我找不到原因,也找不到解决方法。

另外,我不知道这是否真的是我测试它的最佳方式。我想要的是一种在没有main.cpp文件的情况下测试整个框架(初始化,创建东西,检查返回等等)的方法,同时开始创建单元测试。

所以,我的问题是..我做错了,在Windows环境中,链接器找不到由foobar构建的src/CMakeLists.txt lib? (我检查过,lib是在“src / Debug / foobar.dll”中创建的,出现在错误中的同一目录,并且工作正常)

另外,我的方法是如此错误,以至于Windows不想处理?大声笑我的意思是,做我想做的事情是错误的?这不是我不想进行单元测试,我将很快做,但我真的想在开始这样做之前不使用任何外部exec二进制文件来构建和尝试我的lib。

谢谢!

OBS:

  • 我的谷歌测试在linux和windows中都运行良好;

  • 如果我删除了链接到foobar lib的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)

1 个答案:

答案 0 :(得分:1)

重新制定并加强我之前的评论:

您需要在Windows上从DLL导出符号,否则不会创建导入库,这就是MSBuild所抱怨的。

首先,您应该在FooBar.hpp标头中添加以下结构:

#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)