简体   繁体   English

无法在 CMake 中创建动态库并将其链接到另一个动态库?

[英]Unable to create a dynamic library in CMake and link it against another dynamic library?

I'm currently struggling in developing a small application under Windows 10 which uses different libraries.我目前正在努力在 Windows 10 下开发一个使用不同库的小型应用程序。 First of all I'd like to say that I've been a professional developer for quite a few years but I've always developed on different environments (mostly GNU/Linux and MacOS) and when it comes to Windows for me it has always been more of a gaming OS than a working one;首先,我想说我已经成为一名专业开发人员已有好几年了,但我总是在不同的环境(主要是 GNU/Linux 和 MacOS)上进行开发,对于我来说 Windows 一直都是更像是一个游戏操作系统而不是一个工作操作系统; now that Windows 10 seems to be more open-source friendly I'd like to give it a shot and see if by combining WSL-2 and vcpkg I can have something working.现在 Windows 10 似乎对开源更加友好,我想试一试,看看是否可以通过结合 WSL-2 和 vcpkg 来实现一些工作。 So I thought that developing a simple cross-platform 2D application using the allegro library could have been a good idea.所以我认为使用 allegro 库开发一个简单的跨平台 2D 应用程序可能是一个好主意。

I've created a new CMake project using Visual Studio 2019 Community Edition, and set-up a vcpkg clone inside the project itself (I don't feel like this is a good idea but I kind of liked the idea of having everything in a single place).我使用 Visual Studio 2019 社区版创建了一个新的 CMake 项目,并在项目本身内部设置了一个 vcpkg 克隆(我觉得这不是一个好主意,但我有点喜欢将所有东西都放在一个单处)。 Using vcpkg I installed the 2 libraries I'd wish to use: allegro and sqlite3.使用 vcpkg 我安装了我希望使用的 2 个库:allegro 和 sqlite3。 Both installations went fine and I'm actually quite surprised by vcpkg itself.两个安装都很好,我实际上对 vcpkg 本身感到非常惊讶。

I setup my project structure: since this will be a modular project I started creating a bunch of shared libraries in CMake via the add_library(lib_name SHARED sources) function and I ended up having a structure similar to the following one:我设置了我的项目结构:因为这将是一个模块化项目,我开始通过add_library(lib_name SHARED sources) function 在 CMake 中创建一堆共享库,最后我得到了一个类似于以下的结构:

project_root/CMakeLists.txt
project_root/src/main.cpp

project_root/core
project_root/core/CMakeLists.txt
project_root/core/include/core/bunch_of_headers.hpp
project_root/core/src/bunch_of_sources.cpp

project_root/model
project_root/model/CMakeLists.txt
project_root/model/include/model/bunch_of_headers.hpp
project_root/model/src/bunch_of_sources.cpp

and so on..等等..

Every folder within the project_root contains a module, and all the CMakeLists file look like the following one: project_root中的每个文件夹都包含一个模块,所有 CMakeLists 文件如下所示:

add_library(model SHARED all_the_source_files.cpp)

include(DeclareNewSharedLibrary)
declare_new_shared_library(model)

find_package(sqlite3 CONFIG REQUIRED)
target_link_libraries(model sqlite3)

where declare_new_shared_library() is defined as the following function in a separate cmake module其中declare_new_shared_library()在单独的 cmake 模块中定义为以下 function

function(declare_new_shared_library lib_name)
    message(STATUS "Declaring new library ${lib_name}")
    include(GenerateExportHeader)
    generate_export_header(${lib_name})

    target_include_directories(${lib_name}
        PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include"
        PUBLIC "${CMAKE_CURRENT_BINARY_DIR}"
    )

    set_target_properties(${lib_name} PROPERTIES
        IMPORTED_IMPLIB "${CMAKE_CURRENT_BINARY_DIR}/${lib_name}.lib"
        IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/${lib_name}.dll"
    )
endfunction(declare_new_shared_library)

Nothing fancy so far.到目前为止没有什么花哨的。

Now, every module compiles fine, even when I link the shared library against a library which has been downloaded through vcpkg (as it happens in the example above).现在,每个模块都可以正常编译,即使我将共享库链接到通过 vcpkg 下载的库(如上面的示例中那样)。 The ld on Windows correctly outputs the needed files ( .lib and .dll ) and copies them in the ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} as expected. Windows 上的ld正确输出所需的文件( .lib.dll )并按预期将它们复制到${CMAKE_RUNTIME_OUTPUT_DIRECTORY}中。

The issue I'm having here, is that there is one library which doesn't compile.我在这里遇到的问题是有一个库无法编译。 The CMake file is identical to the other ones, except that I'm linking against the allegro library (which has been installed via vcpkg like all the others). CMake 文件与其他文件相同,除了我链接到 allegro 库(与所有其他库一样,它已通过 vcpkg 安装)。 Here's the CMake file for comparison:这是 CMake 文件进行比较:

add_library(core SHARED all_the_sources.cpp)

include(DeclareNewSharedLibrary)
declare_new_shared_library(core)

find_package(allegro CONFIG REQUIRED)
target_link_libraries(core allegro)

When I try to compile this target (either directly or via the dependencies system) I get the following error当我尝试编译此目标(直接或通过依赖系统)时,我收到以下错误

TL;DR: TL;博士:

C:\Dev\ConsultantLife\msvcrtd.lib(exe_main.obj) : error LNK2019: unresolved external symbol main referenced in function "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ)
C:\Dev\ConsultantLife\bin\core.dll : fatal error LNK1120: 1 unresolved externals

Here is the long version for the braves:这是勇敢者的长版本:

  Cleaning... 3 files.
  [1/2] C:\PROGRA~2\MICROS~1\2019\COMMUN~1\VC\Tools\Llvm\80D306~1.0\bin\clang-cl.exe  /nologo -TP -Dcore_EXPORTS -I..\..\..\core\include -Icore -I..\..\..\vcpkg\installed\x64-windows\include -m64 -fdiagnostics-absolute-paths  /DWIN32 /D_WINDOWS /W3 /GR /EHsc /MDd /Zi /Ob0 /Od /RTC1 /showIncludes /Focore\CMakeFiles\core.dir\Game.cpp.obj /Fdcore\CMakeFiles\core.dir\ -c ..\..\..\core\Game.cpp
  [2/2] cmd.exe /C "cd . && "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E vs_link_dll --intdir=core\CMakeFiles\core.dir --rc=C:\PROGRA~2\WI3CF2~1\10\bin\100183~1.0\x64\rc.exe --mt=C:\PROGRA~2\WI3CF2~1\10\bin\100183~1.0\x64\mt.exe --manifests  -- C:\PROGRA~2\MICROS~1\2019\COMMUN~1\VC\Tools\MSVC\1422~1.279\bin\Hostx64\x64\link.exe /nologo core\CMakeFiles\core.dir\Game.cpp.obj  /out:bin\core.dll /implib:core\core.lib /pdb:bin\core.pdb /dll /version:0.0 /machine:x64 /debug /INCREMENTAL  ..\..\..\vcpkg\installed\x64-windows\debug\lib\allegro-debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  && cmd.exe /C "cd /D C:\Dev\ConsultantLife\out\build\x64-Debug\core && powershell -noprofile -executionpolicy Bypass -file C:/Dev/ConsultantLife/vcpkg/scripts/buildsystems/msbuild/applocal.ps1 -targetBinary C:/Dev/ConsultantLife/out/build/x64-Debug/bin/core.dll -installedDir C:/Dev/ConsultantLife/vcpkg/installed/x64-windows/debug/bin -OutVariable out""
  FAILED: bin/core.dll core/core.lib 
  cmd.exe /C "cd . && "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E vs_link_dll --intdir=core\CMakeFiles\core.dir --rc=C:\PROGRA~2\WI3CF2~1\10\bin\100183~1.0\x64\rc.exe --mt=C:\PROGRA~2\WI3CF2~1\10\bin\100183~1.0\x64\mt.exe --manifests  -- C:\PROGRA~2\MICROS~1\2019\COMMUN~1\VC\Tools\MSVC\1422~1.279\bin\Hostx64\x64\link.exe /nologo core\CMakeFiles\core.dir\Game.cpp.obj  /out:bin\core.dll /implib:core\core.lib /pdb:bin\core.pdb /dll /version:0.0 /machine:x64 /debug /INCREMENTAL  ..\..\..\vcpkg\installed\x64-windows\debug\lib\allegro-debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib  && cmd.exe /C "cd /D C:\Dev\ConsultantLife\out\build\x64-Debug\core && powershell -noprofile -executionpolicy Bypass -file C:/Dev/ConsultantLife/vcpkg/scripts/buildsystems/msbuild/applocal.ps1 -targetBinary C:/Dev/ConsultantLife/out/build/x64-Debug/bin/core.dll -installedDir C:/Dev/ConsultantLife/vcpkg/installed/x64-windows/debug/bin -OutVariable out""
  LINK Pass 1: command "C:\PROGRA~2\MICROS~1\2019\COMMUN~1\VC\Tools\MSVC\1422~1.279\bin\Hostx64\x64\link.exe /nologo core\CMakeFiles\core.dir\Game.cpp.obj /out:bin\core.dll /implib:core\core.lib /pdb:bin\core.pdb /dll /version:0.0 /machine:x64 /debug /INCREMENTAL ..\..\..\vcpkg\installed\x64-windows\debug\lib\allegro-debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTFILE:core\CMakeFiles\core.dir/intermediate.manifest core\CMakeFiles\core.dir/manifest.res" failed (exit code 1120) with the following output:
     Creating library core\core.lib and object core\core.exp
C:\Dev\ConsultantLife\msvcrtd.lib(exe_main.obj) : error LNK2019: unresolved external symbol main referenced in function "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ)
C:\Dev\ConsultantLife\bin\core.dll : fatal error LNK1120: 1 unresolved externals
  ninja: build stopped: subcommand failed.

Now, from what I understand, the linker is trying to link my library as an executable and since it's unable to find a main function (yep, that's a library, darling..) it complains and gives an error.现在,据我了解,linker 正在尝试将我的库链接为可执行文件,并且由于它无法找到main的 function(是的,这是一个库,亲爱的..)它会抱怨并给出错误。

The compilation of the other libraries in the project has exactly the same link.exe command (except, different libraries other than the system ones) and it doesn't fail..项目中其他库的编译有完全相同的link.exe命令(除了系统库之外的不同库)并且它不会失败..

Now I would like to ask: is there something I'm doing terribly wrong, is there a bug in allegro-5.2 (even though I can't see how a library could look for a main method and how the linker could.. well, you see my point) or should I give up everything?现在我想问一下:我做错了什么, allegro-5.2中是否存在错误(即使我看不到库如何寻找主要方法以及 linker 可以如何......好吧,你明白我的意思)还是我应该放弃一切?

Could it be an issue on the Allegro.cmake files?会不会是 Allegro.cmake 文件的问题? I have to admit I've never used CMake for professional projects (we're a bunch of oldies still using GNU Autotools&Co.) so I might have missed something.我不得不承认我从未将 CMake 用于专业项目(我们是一群仍在使用 GNU Autotools&Co. 的老手),所以我可能错过了一些东西。 Here is the files I've created (copied/pasted from the other cmake files I found in the vcpkg folders)这是我创建的文件(从我在 vcpkg 文件夹中找到的其他 cmake 文件复制/粘贴)

### Allegro-config.cmake
include(${CMAKE_CURRENT_LIST_DIR}/Allegro-targets.cmake)


### Allegro-targets.cmake
# Generated by CMake

if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
   message(FATAL_ERROR "CMake >= 2.6.0 required")
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 2.6)
#----------------------------------------------------------------
# Generated CMake target import file.
#----------------------------------------------------------------

# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)

# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_targetsDefined)
set(_targetsNotDefined)
set(_expectedTargets)
foreach(_expectedTarget sqlite3)
  list(APPEND _expectedTargets ${_expectedTarget})
  if(NOT TARGET ${_expectedTarget})
    list(APPEND _targetsNotDefined ${_expectedTarget})
  endif()
  if(TARGET ${_expectedTarget})
    list(APPEND _targetsDefined ${_expectedTarget})
  endif()
endforeach()
if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
  unset(_targetsDefined)
  unset(_targetsNotDefined)
  unset(_expectedTargets)
  set(CMAKE_IMPORT_FILE_VERSION)
  cmake_policy(POP)
  return()
endif()
if(NOT "${_targetsDefined}" STREQUAL "")
  message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
endif()
unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)


# Compute the installation prefix relative to this file.
set(_IMPORT_PREFIX "${PROJECT_SOURCE_DIR}/vcpkg/installed/${VCPKG_TARGET_TRIPLET}")

# Create imported target allegro
add_library(allegro SHARED IMPORTED)

set_target_properties(allegro PROPERTIES
  INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
)

# Load information for each installed configuration.
file(GLOB CONFIG_FILES "${CMAKE_CURRENT_LIST_DIR}/Allegro-targets-*.cmake")
foreach(f ${CONFIG_FILES})
  include(${f})
endforeach()

# Cleanup temporary variables.
set(_IMPORT_PREFIX)

# Loop over all imported files and verify that they actually exist
foreach(target ${_IMPORT_CHECK_TARGETS} )
  foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
    if(NOT EXISTS "${file}" )
      message(FATAL_ERROR "The imported target \"${target}\" references the file
   \"${file}\"
but this file does not exist.  Possible reasons include:
* The file was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and contained
   \"${CMAKE_CURRENT_LIST_FILE}\"
but not all the files it references.
")
    endif()
  endforeach()
  unset(_IMPORT_CHECK_FILES_FOR_${target})
endforeach()
unset(_IMPORT_CHECK_TARGETS)

# This file does not depend on other imported targets which have
# been exported from the same project but in a separate export set.

# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)



### Allegro-targets-debug.cmake
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Debug".
#----------------------------------------------------------------

# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)

# Import target "allegro" for configuration "Debug"
set_property(TARGET allegro APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(allegro PROPERTIES
    IMPORTED_IMPLIB_DEBUG "${_IMPORT_PREFIX}/debug/lib/allegro-debug.lib"
    IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/debug/bin/allegro-debug-5.2.dll"
  )

list(APPEND _IMPORT_CHECK_TARGETS allegro )
list(APPEND _IMPORT_CHECK_FILES_FOR_allegro 
    "${_IMPORT_PREFIX}/debug/lib/allegro-debug.lib" 
    "${_IMPORT_PREFIX}/debug/bin/allegro-debug-5.2.dll"
)

# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)

Since this behaviour has been driving me crazy for the last few days, I tested the same configuration on a Linux environment (vcpkg, cmake, ...) and it worked like a charm, I compiled everything and it worked.由于过去几天这种行为让我发疯,我在 Linux 环境(vcpkg,cmake,...)上测试了相同的配置,它就像一个魅力,我编译了所有东西,它工作了。 The only difference I see is that vcpkg on Linux uses only static libraries, while it uses dll on Windows.我看到的唯一区别是 Linux 上的 vcpkg 仅使用 static 库,而它使用 dll 上 ZAEA23489CEE3AA97Z 库

Sorry for the wall of text!对不起文字墙!

Thank you for your help!谢谢您的帮助!

And as it usually happens, I've been able to find the answer by myself just a couple of minutes after asking for help.而且通常情况下,在寻求帮助后几分钟,我就可以自己找到答案。

It seems like the liballegro tries to find a main method, which is the reason why the linking was failing.似乎 liballegro 试图找到一个主要方法,这就是链接失败的原因。

The solution was to add the following line to the Allegro-config.cmake file解决方案是将以下行添加到Allegro-config.cmake文件中

target_compile_definitions(allegro INTERFACE ALLEGRO_NO_MAGIC_MAIN)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM