我有以下CMakeLists.txt
文件来生成基于Qt的项目:
cmake_minimum_required(VERSION 2.8.12)
project(MyProject)
find_package(Qt5Widgets)
set(MyProjectLib_src ${PROJECT_SOURCE_DIR}/gui.cpp)
set(MyProjectLib_hdr ${PROJECT_SOURCE_DIR}/gui.h)
set(MyProjectLib_ui ${PROJECT_SOURCE_DIR}/gui.ui)
set(MyProjectBin_src ${PROJECT_SOURCE_DIR}/main.cpp)
qt5_wrap_cpp(MyProjectLib_hdr_moc ${MyProjectLib_hdr})
qt5_wrap_ui (MyProjectLib_ui_moc ${MyProjectLib_ui})
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_BINARY_DIR})
add_library(MyProjectLib SHARED
${MyProjectLib_src}
${MyProjectLib_hdr_moc}
${MyProjectLib_ui_moc}
)
target_link_libraries(MyProjectLib Qt5::Widgets)
add_executable(MyProject ${MyProjectBin_src})
target_link_libraries(MyProject MyProjectLib)
当我尝试编译生成的项目时,我收到以下错误:
错误LNK1104:无法打开文件'Debug \ MyProjectLib.lib'
相应的目录Debug
包含:
MyPtojectLib.dll
MyProjectLib.ilk
MyProjectLib.pdb
您将MyProjectLib
声明为共享库,因此除非您导出库的全部或部分符号,否则您将只有一个.dll
设计为在运行时加载,并且在编译时没有.lib
链接,因为您正在尝试做。
一个快速的解决方案可能是将MyProjectLib
声明为静态库:
add_library(MyProjectLib STATIC ...)
另一个选择可能是使用“新”cmake功能导出所有符号(请参阅this article):
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
您还可以通过明确声明要导出的符号来使用“传统”方式,例如this answer(长答案)。您首先需要在代码中的某处声明一些API宏:
#ifdef MyProjectLib_EXPORTS
#define MyProjectLib_API __declspec(dllexport)
#else
#define MyProjectLib_API __declspec(dllimport)
#endif
请注意,cazke会自动为共享库生成MyProjectLib_EXPORTS
:您无需关心这一点。然后,对于代码中的每个类,请使用声明中的宏:
class MyProjectLib_API MyClass { /* ... */ };
编译MyClass
时,MyProjectLib
将是一个导出的符号,因为将定义MyProjectLib_EXPORTS
,MyProjectLib_API将扩展为__declspec(dllexport)
。因此它将以.lib
文件导出。
当它与MyProjectLib
连接时它将是一个导入的符号,因为MyProjectLib_EXPORTS
将是未定义的,而MyProjectLib_API
将扩展到__declspec(dllimport)
。
你也可以像这样改进你的cmake文件:
qt5_wrap_cpp(MyProjectLib_hdr_moc ${MyProjectLib_hdr})
qt5_wrap_ui (MyProjectLib_ui_moc ${MyProjectLib_ui})
您可以使用AUTOMOC
和AUTOUIC
来让cmake自动处理对Qt实用程序的调用。
include_directories (${PROJECT_SOURCE_DIR})
include_directories (${PROJECT_BINARY_DIR})
PROJECT_SOURCE_DIR
默认是一个包含目录,我不明白为什么你需要在这里添加PROJECT_BINARY_DIR
:只需删除这些行。
清理后,您的cmake文件可能会变成这样:
cmake_minimum_required(VERSION 2.8.12)
project(MyProject)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
find_package(Qt5Widgets)
set(MyProjectLib_src
${PROJECT_SOURCE_DIR}/gui.cpp
${PROJECT_SOURCE_DIR}/gui.h
${PROJECT_SOURCE_DIR}/gui.ui
)
add_library(MyProjectLib STATIC
${MyProjectLib_src}
)
target_link_libraries(MyProjectLib Qt5::Widgets)
set(MyProjectBin_src ${PROJECT_SOURCE_DIR}/main.cpp)
add_executable(MyProject
${MyProjectBin_src}
)
target_link_libraries (MyProject MyProjectLib)
TLDR:确保你有源文件,而不仅仅是标题!
对于到达这里并且可能没有OP问题的网络搜索者,我刚刚遇到了一个非常类似的链接错误,因为我有拆分库并且其中一个没有任何源文件,只有一个标题库:
add_library(hsm STATIC
StateAbstract.hpp # header-only
StateMachineAbstract.hpp # header-only
StateMachineBase.hpp # header-only
)
我的修复是插入一个cpp文件,等待恢复类实现文件:
add_library(hsm STATIC
Placeholder.cpp # this file causes hsm.lib to get generated on Windows
StateAbstract.hpp # header-only
StateMachineAbstract.hpp # header-only
StateMachineBase.hpp # header-only
)
这可能看起来很明显,但我在这个项目上进行Linux / QNX开发,gcc创建了一个几乎空的库:
$ wc -c build/lib/libhsm.a
8 build/lib/libhsm.a
$ strings build/lib/libhsm.a
!<arch>
那个图书馆很开心。直到项目在构建服务器上构建Windows版本时才看到错误:
[4/6] cmd.exe /C "cd . && C:\PROGRA~2\MICROS~2\2017\COMMUN~1\VC\Tools\MSVC\1413~1.261\bin\Hostx64\x64\link.exe /lib /nologo /machine:x64 /out:build\lib\hsm.lib && cd ."
[5/6] ...
[6/6] cmd.exe /C "cd . && "C:\Program Files\CMake\bin\cmake.exe" -E vs_link_exe ... /out:build\gtest\hsm_test.exe ... build\lib\hsm.lib ...
LINK : fatal error LNK1104: cannot open file 'build\lib\hsm.lib'
因为我看到了在构建服务器输出中创建lib文件的命令,所以我无法弄清楚为什么hsm.lib不会存在(并且我无法进入构建服务器)。幸运的是,当我阅读其他答案并三重检查它是静态链接时,我注意到它只是一个标题库 - 哇!我感觉很幸运!