Error LNK1104: cannot open file 'Debug\\MyProj

2019-05-07 13:23发布

问题:

I have the following CMakeLists.txt file to generate my project based on 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)

When I try to compile the generated project, I got the following error:

error LNK1104: cannot open file 'Debug\MyProjectLib.lib'

The corresponding directory Debug contains:

MyPtojectLib.dll
MyProjectLib.ilk
MyProjectLib.pdb

回答1:

You declared MyProjectLib as a shared library, so unless you exported all or part of the symbols of the library, you will only have a .dll designed to be loaded at runtime, and no .lib to link against at compile time as you're trying to do.

A quick solution may be to declare MyProjectLib as a static library:

add_library(MyProjectLib STATIC ...)

Another option could be to use "new" cmake features to export all symbols (see this article):

set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

You can also use the "traditional" way by explicitly declaring the symbols to be exported, like in this answer (the long answer). You will first need to declare some API macro somewhere in your code:

#ifdef MyProjectLib_EXPORTS
#define MyProjectLib_API __declspec(dllexport)
#else
#define MyProjectLib_API __declspec(dllimport)
#endif

Note that MyProjectLib_EXPORTS is automatically generated by cmake for shared libraries: you don't need to care about this. Then for each of your class in your code, use the macro in the declaration:

class MyProjectLib_API MyClass { /* ... */ };

MyClass will be an exported symbol when compiling MyProjectLib because MyProjectLib_EXPORTS will be defined, and MyProjectLib_API will expand to __declspec(dllexport). So it will be exported in a .lib file.

It will be an imported symbol when linking against MyProjectLib because MyProjectLib_EXPORTS will be undefined, and MyProjectLib_API will expand to __declspec(dllimport).


You may also improve your cmake file like this:

qt5_wrap_cpp(MyProjectLib_hdr_moc ${MyProjectLib_hdr})
qt5_wrap_ui (MyProjectLib_ui_moc  ${MyProjectLib_ui})

You may use AUTOMOC and AUTOUIC instead to let cmake automatically handle the call to Qt's utilities.

include_directories (${PROJECT_SOURCE_DIR})
include_directories (${PROJECT_BINARY_DIR})

PROJECT_SOURCE_DIR is an include directory by default, and I can't see why you need to add PROJECT_BINARY_DIR here: just remove these lines.

Once cleaned, your cmake file may become something like this:

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)


回答2:

TLDR: Make sure you have source files, not just headers!

For web searchers who arrive here and may not have the OP's problem, I just encountered a very similar linking error that occurred because I had split libraries and left one of them without any source files, a header-only library:

add_library(hsm STATIC
  StateAbstract.hpp        # header-only
  StateMachineAbstract.hpp # header-only
  StateMachineBase.hpp     # header-only
)

My fix was to insert a cpp file pending restoration of class implementation files:

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
)

This may seem like it would be obvious, but I'm doing Linux/QNX development on this project and gcc creates a nearly empty library:

$ wc -c build/lib/libhsm.a 
8 build/lib/libhsm.a
$ strings build/lib/libhsm.a
!<arch>

That library links quite happily. It was only later when the project was building the Windows version on a build server that I saw the error:

[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'

Since I saw the command to create the lib file in the build server output, I could not initially figure out why hsm.lib would not be there (and I cannot get on the build server). Fortunately, as I read the other answer and triple-checked that it was statically linked, I noticed it was a header-only library - whew! I feel lucky!



标签: c++ qt cmake qt5