使用CMake和Visual Studio 2019生成器创建共享库时缺少.lib文件

8

我创建了一个个人的C++库,并尝试在另一个程序中使用它。为了创建和编译我的库,我使用以下命令:

cmake -G "Visual Studio 16 2019" -A x64 ..
cmake --build . --config Release --target INSTALL

我对编译和安装没有问题,但在Target-release.cmake中的安装看起来像这样:

#----------------------------------------------------------------
# Generated CMake target import file for configuration "Release".
#----------------------------------------------------------------

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

# Import target "containers" for configuration "Release"
set_property(TARGET containers APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(containers PROPERTIES
  IMPORTED_IMPLIB_RELEASE "C:/Program Files (x86)/containers/lib/containers.lib"
  IMPORTED_LOCATION_RELEASE "C:/Program Files (x86)/containers/bin/containers.dll"
  )

list(APPEND _IMPORT_CHECK_TARGETS containers )
list(APPEND _IMPORT_CHECK_FILES_FOR_containers "C:/Program Files (x86)/containers/lib/containers.lib" "C:/Program Files (x86)/containers/bin/containers.dll" )

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

据我所见,没有任何异常。我的问题是:在编译和安装期间,没有生成文件C:/Program Files (x86)/containers/lib/containers.lib。因此,每次尝试使用查找包时,都会出现错误。(这只是针对visual studio生成器,在mingw中工作正常)。以下是我的CMakeLists.txt:
cmake_minimum_required(VERSION 3.1)

set(VERSION 1.0.0)

project (containers
  VERSION ${VERSION}
  DESCRIPTION "Library adding some features to containers of the stl."
  LANGUAGES CXX)

option(BUILD_TESTING "Build test programs" OFF)
include(CTest)

# Set the possible values of build type for cmake-gui
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build.")
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")

message( STATUS "Sources  path : ${PROJECT_SOURCE_DIR}")
message( STATUS "Binary   path : ${PROJECT_BINARY_DIR}")
message( STATUS "install  path : ${CMAKE_INSTALL_PREFIX}")
message( STATUS "Version       : ${PROJECT_VERSION}")
message( STATUS "Version       : ${PROJECT_VERSION}")
message( STATUS "Compiler      : ${CMAKE_CXX_COMPILER_ID}")

set(SOURCES ${PROJECT_SOURCE_DIR}/src/containers.cpp)
set(HEADERS ${PROJECT_SOURCE_DIR}/include/containers/containers_check.h
  ${PROJECT_SOURCE_DIR}/include/containers/containers.h
  ${PROJECT_SOURCE_DIR}/include/containers/append.h
  ${PROJECT_SOURCE_DIR}/include/containers/contains.h
  ${PROJECT_SOURCE_DIR}/include/containers/remove.h
  ${PROJECT_SOURCE_DIR}/include/containers/print.h
  )

add_library(containers SHARED ${SOURCES} ${HEADERS})
#add_library(containers INTERFACE)

target_compile_features(containers PRIVATE cxx_std_17)
set_target_properties(containers
  PROPERTIES
  MSVC_RUNTIME_LIBRARY "MultiThreadedDLL"
  CXX_STANDARD_REQUIRED YES
  CXX_EXTENSIONS OFF)

target_include_directories(containers
  PUBLIC
  $<INSTALL_INTERFACE:include>
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)

target_compile_options(containers PRIVATE
  # g++
  #$<$<CXX_COMPILER_ID:GNU>:$<BUILD_INTERFACE:-Wall>>
  #$<$<CXX_COMPILER_ID:GNU>:$<BUILD_INTERFACE:-Wextra>>
  #$<$<CXX_COMPILER_ID:GNU>:$<BUILD_INTERFACE:-pedantic>>
  #$<$<CXX_COMPILER_ID:GNU>:$<BUILD_INTERFACE:-Werror>>
  #$<$<CXX_COMPILER_ID:GNU>:-Wno-reorder>
  ## Clang
  #$<$<CXX_COMPILER_ID:Clang>:$<BUILD_INTERFACE:-Wall>>
  ##TODO
  ## MSVC
  #$<$<CXX_COMPILER_ID:MSVC>:$<BUILD_INTERFACE:/W4>>
  #$<$<CXX_COMPILER_ID:MSVC>:$<BUILD_INTERFACE:/WX>>
  )

install(TARGETS containers
  EXPORT containersTarget
  ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/ COMPONENT Development
  LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/ COMPONENT Library NAMELINK_COMPONENT Development
  RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin/ COMPONENT Runtimes
  )

install(FILES ${HEADERS}
  DESTINATION ${CMAKE_INSTALL_PREFIX}/include/containers/
  COMPONENT headers)


include(CMakePackageConfigHelpers)

# For moteur_de_calculConfig.cmake
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include CACHE PATH "install path for include files")
set(LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib CACHE PATH "install path for libraries")

#------------------------------------------------------------------------------
# Configure <export_config_name>ConfigVersion.cmake common to build and install tree
set(config_version_file ${PROJECT_BINARY_DIR}/containersConfigVersion.cmake)
write_basic_package_version_file(
  ${config_version_file}
  VERSION "${CMAKE_PROJECT_VERSION}"
  COMPATIBILITY ExactVersion
  )

#------------------------------------------------------------------------------
# Export '<export_config_name>Target.cmake' for a build tree
export(TARGETS
  containers
  FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Target.cmake"
  )

#------------------------------------------------------------------------------
# Configure '<export_config_name>Config.cmake' for a build tree
set(build_config ${CMAKE_BINARY_DIR}/containersConfig.cmake)
configure_package_config_file(
  "containersConfig.cmake.in"
  ${build_config}
  INSTALL_DESTINATION "${PROJECT_BINARY_DIR}"
  PATH_VARS INCLUDE_INSTALL_DIR LIBRARY_INSTALL_DIR VERSION
  )

#------------------------------------------------------------------------------
# Export '<export_config_name>Target.cmake' for an install tree
install(EXPORT
  containersTarget
  DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/cmake/${PROJECT_NAME}"
  )

#------------------------------------------------------------------------------
# Configure '<export_config_name>Config.cmake' for a install tree
set(install_config ${PROJECT_BINARY_DIR}/CMakeFiles/containersConfig.cmake)
configure_package_config_file(
  containersConfig.cmake.in
  ${install_config}
  INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/cmake/${PROJECT_NAME}"
  PATH_VARS INCLUDE_INSTALL_DIR LIBRARY_INSTALL_DIR VERSION
  )

# Install config files
install(
  FILES ${config_version_file} ${install_config}
  DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/cmake/${PROJECT_NAME}"
  )

# test
if(BUILD_TESTING)
  add_subdirectory(test)
endif()

# uninstall target
# use : make uninstall
if(NOT TARGET uninstall)
  configure_file(
    "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
    "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
    IMMEDIATE @ONLY)

  add_custom_target(uninstall
    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif()

我的cmake版本:

cmake version 3.18.0

我的 CMakeLists.txt 缺少什么,以生成 container.lib 文件?

2
看起来你忘记在库中使用 dllexport 导出函数/变量了。如果没有导出的符号,.lib 文件将不会被创建。(对于共享库而言,.lib 实际上是一个 import 文件)。 - Tsyvarev
嗯,我对这个概念不太熟悉,但我会去查一下的。谢谢。 - Kafka
2个回答

14

面对同样的问题,我在这里找到了解决方案:这里:为了使Visual Studio在.dll库之外也能导出符号到.lib文件中,你需要在你的CMake(版本>=3.4)脚本中设置如下:

set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

请注意,通过此方式创建的.lib文件是一个小型文件,并不是静态库。

CMake 手册


5

我想在这里补充一下接受的答案,为了其他可能会发现它的人:虽然CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS可以解决问题,但它很可能是掩盖了你的代码中存在的更深层次问题的临时解决方法。

我不是Microsoft编译器的专家,但我知道如果你使用MSVC构建共享库,应该仍会生成.lib文件。然而,与静态库一样,它并不包含所有已编译代码,而是提供有关共享库中导出符号的信息给编译器。这意味着编译器可以自动将任何其他目标链接到您的共享库,而无需手动从您的代码中使用Windows API函数加载库。如果您以这种方式将可执行文件链接到共享库,则Microsoft C运行时将在应用程序启动时自动调用LoadLibrary()。很有用,对吧?

如果编译器没有在共享库旁边生成一个.lib,这基本上意味着共享库中没有导出的符号。这就是为什么CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS解决了这个问题 - 它强制导出所有符号,从而导致编译器生成详细描述这些导出的.lib文件。然而,正如你可能能够想象到的那样,这是非常核心的选项。你的共享库中可能有很多东西,实际上不需要从外部可见!因此,关键问题变成了:为什么我的库没有导出任何内容?
在之前提到的链接答案中,除了所有的CMake技术细节之外,问题在于OP没有正确地标记他们的符号以进行导出。事实证明这也是我的问题,但是我采取了更加迂回的方式:我决定对于我的特定库,它以前可以在共享或静态配置下构建,现在我想强制它只能在共享配置下构建。因此,我从我的CMake项目中删除了一个特定的预处理器定义,该定义指定了构建模式是共享还是静态;这意味着我所有函数上的导出注释都被编译成了空内容(在静态配置下不需要),结果是我无意中构建了没有任何导出符号的共享库,MSVC只是说“好吧,我猜没有构建.lib的必要了”,并且没有生成一个。这导致构建问题,指出在磁盘上找不到.lib文件。
当我遇到上面的答案时,我感到怀疑,因为我想知道为什么我以前没有设置过这个值,尽管我已经使用CMake构建Windows共享库项目多年了。在我的情况下,正确的解决方案不是打开CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS - 实际上是删除检查我的“这是一个共享构建”的预处理器定义的C++预处理器条件。这重新启用了所有函数的导出注释,并且一切都按照应该的方式构建。
在使用CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS之前,请确保您的脚本中没有一些微妙的错误阻止您的符号被导出!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接