【问题标题】:Linking a static boost build into a static library under VS2012 & Win32/64在 VS2012 和 Win32/64 下将静态提升构建链接到静态库
【发布时间】:2013-08-21 00:54:19
【问题描述】:

我正在尝试构建一个静态库以作为网络设备的 API 发布。我可以成功编译并链接该库以生成 .lib 输出文件,并将它们重新定位到一个目录结构中,如下所示:

EyeLib
 L-Include
 |  L-PublicInterface.h
 L-Lib
 |  L-debug
 |  |   L-MyLib.lib
 |  |   L-MyLib.pdb
 |  L-release
 |      L-MyLib.lib
 L-MyLibConfig.cmake

其中 MyLibConfig.cmake 文件非常简单,包含:

# the header file is relative to this cmake file, so get the path.
GET_FILENAME_COMPONENT( MyLib_TOPLEVEL_DIR ${CMAKE_CURRENT_LIST_FILE} PATH )
SET( MyLib_INCLUDE_DIR ${MyLib_TOPLEVEL_DIR}/include )

IF( WIN32 )
  FIND_LIBRARY( MyLib_DEBUG_LIBRARY MyLib ${MyLib_TOPLEVEL_DIR}/lib/debug )
  FIND_LIBRARY( MyLib_RELEASE_LIBRARY MyLib ${MyLib_TOPLEVEL_DIR}/lib/release )
  SET( MyLib_LIBRARIES optimized ${MyLib_RELEASE_LIBRARY} debug ${MyLib_DEBUG_LIBRARY} )
ENDIF( WIN32 )
IF( UNIX )
  FIND_LIBRARY( MyLib_LIBRARY MyLib ${MyLib_TOPLEVEL_DIR}/lib )
  SET( MyLib_LIBRARIES "${MyLib_LIBRARY}" )
  MARK_AS_ADVANCED( MyLib_LIBRARY )
ENDIF( UNIX )

# handle the QUIETLY and REQUIRED arguments
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(MyLib DEFAULT_MSG MyLib_LIBRARIES MyLib_INCLUDE_DIR)

MARK_AS_ADVANCED( MyLib_INCLUDE_DIR )

此构建结构适用于我过去构建的一些测试库,但是当我尝试使用它构建一个简单的测试应用程序时出现链接错误,提示“错误 LNK1104:无法打开文件‘libboost_thread’ -vc110-mt-s-1_54.lib'"

如果我将测试应用程序添加到与库构建相同的项目中,我可以成功构建和运行测试应用程序。我认为这是因为库构建正在寻找要链接的 boost 库,因此它会传播到项目中的可执行文件。

我使用 b2 link=static runtime-link=static threading=multi variant=debug,release --layout=tagged 构建了 boost 1.54,并将库构建和测试应用构建链接到静态 MSVC 运行时 (/MT) .

谁能提供一些帮助/建议/进一步测试这个?我需要确保所有的 boost 内容都编译到 API 库中,这样我们的客户就不必自己安装 boost。

其他信息

如果有帮助,这里是库构建中的 cmakelists.txt 文件:

set(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}/lib")

set(Boost_USE_STATIC_LIBS   ON)
set(Boost_USE_MULTITHREADED ON)
find_package(Boost REQUIRED COMPONENTS system date_time regex thread chrono)
if(NOT WIN32)
  list(APPEND Boost_LIBRARIES pthread)
endif()

include_directories(${Boost_INCLUDE_DIRS})

FILE(GLOB srcs *.cpp)
FILE(GLOB headers *.h)
set(libname MyLib)

set(deps ${Boost_LIBRARIES})

#To allow compilation. std=c++0x is for accepting the access to enums, which usually is just accepted with Visual Studio
IF( NOT WIN32 )
  set (CMAKE_CXX_FLAGS "-fpermissive -std=c++0x")
ENDIF( NOT WIN32 )

SOURCE_GROUP( ${libname} FILES ${srcs} )
SOURCE_GROUP( "${libname}\\Hdr" FILES ${headers} )
add_library(${libname} ${srcs} ${headers})
target_link_libraries( ${libname} ${deps} )

【问题讨论】:

    标签: visual-studio boost visual-studio-2012 cmake static-libraries


    【解决方案1】:

    这是设计使然。

    在构建静态库时,对该库的任何依赖项都不会直接链接到该库中。相反,在构建可执行文件时,所有库依赖项(直接和间接)都将直接链接到该可执行文件。

    这也是大多数编译器处理静态库的方式。虽然 VS 确实提供了将依赖项链接到静态库的特殊选项,但这在例如gcc 不诉诸脏文件黑客。由于 CMake 仅支持可在所有受支持的生成器上使用的功能,因此即使在 VS 版本上,CMake 也不允许这样做。

    你现在有几个选择:

    • 使用 dll 而不是静态库 (add_library(${libname} SHARED ...))。虽然静态库基本上是一堆包装在一起的目标文件,但 dll 或多或少与可执行文件相同。特别是,所有静态库依赖项都直接链接到 dll 中。这里的缺点是您必须处理通常的 dll 混乱:您必须指定要导出的函数以及跨 dll 边界传递内容的常见问题。
    • 让您的查找脚本也搜索所有依赖项。您应该能够以代码重复量最少的方式重组库的依赖关系处理。缺点是配置第三方应用程序变得更加困难(尤其是在 Windows 上),因为您现在不仅需要找到库本身,还需要找到它的所有依赖项。
    • 使用exported targets。如果库与最终可执行文件构建在同一台机器上,这种方法最有意义。在构建库时,CMake 会自动生成配置文件以使用该库。然后,您的应用程序只需要找到包含该脚本的内容,您就可以开始了。缺点是导出机制不是 CMake 最直接的特性,因此您需要花一些时间来熟悉它。
    • 将库源直接拉入每个可执行文件。基本上每个可执行文件都会在库源目录上执行add_subdirectory。您仍然必须为每个可执行文件配置依赖项,除此之外,您还必须为每个可执行文件单独构建库。您可能不想这样做。

    【讨论】:

    • 你没有在这里列出的一个选项,如果我只是将依赖项与库一起分发,它会起作用吗?只要它们与 MyLib.lib 位于同一位置,cmake 就应该能够找到它。这意味着客户端可以自己链接到 DLL 或完全可移植的可执行文件。此解决方案是否可能导致任何不可预见的问题?我主要担心的是我不希望客户必须为他们的应用程序使用与我构建库时相同版本的 boost。
    • @OcularProgrammer 这基本上是选项#2:您编写一个解决依赖关系的查找脚本,可能通过从您的发行版中获取它们。混合库版本是一个问题,但不幸的是,它适用于所有形式的二进制库分发。如果您在接口上公开 Boost 类型,则您的库和可执行文件必须都使用相同的 boost 版本。否则跨库边界传递 boost 类型可能会搞砸。包含使用不同的版本通常是可以的,但您仍应尽可能避免使用它。
    • 为建议喝彩。 MyLibConfig.cmake 需要一些技巧才能正确地从目录结构中获取库和依赖项,但是当我获取所有依赖项并将它们移动到适当的 lib 目录中时,我们现在有了一个不错的、可移植的安装包。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2011-01-20
    • 1970-01-01
    • 2011-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多