В настоящее время я борюсь за разработку небольшого приложения под Windows 10, которое использует разные библиотеки.Прежде всего, я хотел бы сказать, что я был профессиональным разработчиком в течение нескольких лет, но я всегда разрабатывал в разных средах (в основном GNU / Linux и MacOS), и когда дело касается Windows, для меня это всегдабыла скорее игровой ОС, чем работающей;теперь, когда Windows 10 выглядит более дружественной к открытым исходным кодам, я хотел бы попробовать и посмотреть, смогу ли я что-то сработать, комбинируя WSL-2 и vcpkg.Поэтому я подумал, что разработка простого кроссплатформенного 2D-приложения с использованием библиотеки allegro могла бы быть хорошей идеей.
Я создал новый проект CMake с использованием Visual Studio 2019 Community Edition и настроил vcpkgклонирование внутри самого проекта (я не думаю, что это хорошая идея, но мне понравилась идея иметь все в одном месте).Используя vcpkg, я установил 2 библиотеки, которые хотел бы использовать: allegro и sqlite3.Обе установки прошли нормально, и я на самом деле весьма удивлен самим vcpkg.
Я настроил структуру своего проекта: так как это будет модульный проект, я начал создавать кучу общих библиотек в CMake с помощью функции add_library(lib_name SHARED sources)
и у меня получилась структура, подобная следующей:
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
и т. д.
Каждая папка в 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)
где declare_new_shared_library()
определена как следующая функция в отдельном модуле cmake
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)
Пока ничего сложного.
Сейчаскаждый модуль компилируется нормально, даже когда я связываю разделяемую библиотеку с библиотекой, которая была загружена через vcpkg (как это происходит в примере выше).ld
в Windows правильно выводит необходимые файлы (.lib
и .dll
) и копирует их в ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
, как и ожидалось.
Проблема, с которой я здесь сталкиваюсь, заключается в том, что есть одна библиотека, которая не компилируется.Файл CMake идентичен другим, за исключением того, что я ссылаюсь на библиотеку allegro (которая была установлена через vcpkg, как и все остальные).Вот файл 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)
Когда я пытаюсь скомпилировать эту цель (напрямую или через систему зависимостей), я получаю следующую ошибку
TL; DR:
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
Вот длинная версия для смельчаков:
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.
Теперь, насколько я понимаю, компоновщик пытается связать мою библиотеку как исполняемый файл, и так как он не может найти main
функция (да, это библиотека, дорогая ..) она жалуется и выдает ошибку.
Компиляция других библиотек в проекте имеет точно такую же команду link.exe
(за исключением того, что другие библиотеки другиечем системные), и это не дает сбоя ..
Теперь я хотел бы спросить: есть ли что-то, что я делаю ужасно неправильно, есть ли ошибка в allegro-5.2
(хотя я могу 'не понимаю, как библиотека может искать метод main и как компоновщик может .. ну, вы понимаете мою точку зрения) или я должен отказаться от всего?
Может ли это быть проблемой с файлами Allegro.cmake?Я должен признать, что я никогда не использовал CMake для профессиональных проектов (мы старая компания, все еще использующая GNU Autotools & Co.), Поэтому я мог что-то пропустить.Вот файлы, которые я создал (скопировал / вставил из других файлов cmake, которые я нашел в папках vcpkg)
### 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)
Так как это поведение сводило меня с ума в течение последних нескольких дней, я протестировалта же конфигурация в среде Linux (vcpkg, cmake, ...), и она работала как чудо, я скомпилировал все, и это сработало.Единственное отличие, которое я вижу, это то, что vcpkg в Linux использует только статические библиотеки, в то время как в Windows он использует dll.
Извините за стену текста!
Спасибо за вашу помощь!