VS2015 link 静态库如何与其他库和可执行文件?

How does VS2015 link static libraries to other libraries and executables?

我正在尝试创建一个项目,它将创建一个可执行文件 MyExec.exe,这将依赖于另一个库 Niftilib,它本身依赖于 zlib.

我做的是用cmake创建了一个superbuild,使用ExternalProject_Add下载编译zlib:

ExternalProject_Add(Zlib
    SOURCE_DIR "${PROJECT_BINARY_DIR}/deps/zlib"
    BINARY_DIR "${PROJECT_BINARY_DIR}/deps/zlib-build"
    INSTALL_DIR "${PROJECT_BINARY_DIR}/deps/zlib-install"
    GIT_REPOSITORY "${git_protocol}://github.com/madler/zlib.git"
    GIT_TAG "50893291621658f355bc5b4d450a8d06a563053d"
    CMAKE_ARGS
        -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
        -DINSTALL_BIN_DIR=<INSTALL_DIR>/bin
        -DINSTALL_INC_DIR=<INSTALL_DIR>/include
        -DINSTALL_LIB_DIR=<INSTALL_DIR>/lib
        -DINSTALL_MAN_DIR=<INSTALL_DIR>/share/man
        -DINSTALL_PKGCONFIG_DIR=<INSTALL_DIR>/share/pkgconfig)

我为 Nifticlib 做了同样的事情:

ExternalProject_Add(Nifticlib
    SOURCE_DIR "${PROJECT_BINARY_DIR}/deps/nifticlib"
    BINARY_DIR "${PROJECT_BINARY_DIR}/deps/nifticlib-build"
    INSTALL_DIR "${PROJECT_BINARY_DIR}/deps/nifticlib-install"
    GIT_REPOSITORY "${git_protocol}://gitlab.com/slckr/nifticlib.git"
    GIT_TAG "9f427b39eb6a16822c6ed34454f87eb751b23220"
    CMAKE_ARGS
        -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
        -DZLIB_INCLUDE_DIR=${ZLIB_INC_DIR}
        -DZLIB_LIBRARY_DEBUG=${ZLIB_LIB_DIR}/zlibd.lib
    DEPENDS Zlib)

然后我对 MyExec 做了同样的事情:

ExternalProject_Add(MyExec
    SOURCE_DIR "${PROJECT_BINARY_DIR}/MyExec"
    BINARY_DIR "${PROJECT_BINARY_DIR}/MyExec-build"
    INSTALL_DIR "${PROJECT_BINARY_DIR}/MyExec-install"
    GIT_REPOSITORY "${git_protocol}://gitlab.com/slckr/MyExec.git"
    GIT_TAG "8514aacf5422f1111602e24ea73b229556293b8c"
    CMAKE_ARGS
        -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
        -DBOOST_INC_DIR=${Boost_INCLUDE_DIRS}
        -DBOOST_LIB_DIR=${Boost_LIBRARY_DIRS}
        -DZLIB_INC_DIR=${ZLIB_INC_DIR}
        -DZLIB_LIB_DIR=${ZLIB_LIB_DIR}
        -DNIFTI_INC_DIR=${NIFTI_INC_DIR}
        -DNIFTI_LIB_DIR=${NIFTI_LIB_DIR}
    DEPENDS Nifticlib)

在我的 MyExec 项目的 CMakeLists 中,我有这个:

cmake_minimum_required(VERSION 3.6)

project(MyExec)

include_directories(${BOOST_INC_DIR} ${ZLIB_INC_DIR} ${NIFTI_INC_DIR})
link_directories(${BOOST_LIB_DIR} ${ZLIB_LIB_DIR} ${NIFTI_LIB_DIR})

add_subdirectory(DataStructure)
add_subdirectory(FileHandler)
add_subdirectory(Parser)

add_executable(${PROJECT_NAME} MyExec.cc)
target_link_libraries(${PROJECT_NAME} zlibd znz nifticdf niftiio DataStructure FileHandler Parser)

install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)

我的目标是能够分发 MyExec.exe 而无需所有必需的库(boost 除外)。我希望将 nifticlib 库嵌入到我的 exec 中。

如果我这样编译,它不起作用,因为它说缺少 zlibd.dll。我发现我必须 link 我的可执行文件到 zlibstaticd 而不是 zlibd。

但我的问题是,我是否也应该在 Nifticlib 项目中将 -DZLIB_LIBRARY_DEBUG=${ZLIB_LIB_DIR}/zlibd.lib 更改为 -DZLIB_LIBRARY_DEBUG=${ZLIB_LIB_DIR}/zlibstaticd.lib

还是只对可执行项目有影响?为什么 nifticlib 要求我提供 zlib 库的路径,如果它是作为静态库构建的并且不执行任何 linking 操作?

谢谢。

编辑: 如果我不 link zlib 到我的可执行文件,我会收到这些错误:

5>znz.lib(znzlib.obj) : error LNK2019: unresolved external symbol gzdopen referenced in function znzdopen
5>znz.lib(znzlib.obj) : error LNK2019: unresolved external symbol gzread referenced in function znzread
5>znz.lib(znzlib.obj) : error LNK2019: unresolved external symbol gzwrite referenced in function znzwrite
5>znz.lib(znzlib.obj) : error LNK2019: unresolved external symbol gzputs referenced in function znzputs
5>znz.lib(znzlib.obj) : error LNK2019: unresolved external symbol gzgets referenced in function znzgets
5>znz.lib(znzlib.obj) : error LNK2019: unresolved external symbol gzputc referenced in function znzputc
5>znz.lib(znzlib.obj) : error LNK2019: unresolved external symbol gzgetc referenced in function znzgetc
5>znz.lib(znzlib.obj) : error LNK2019: unresolved external symbol gzflush referenced in function znzflush
5>znz.lib(znzlib.obj) : error LNK2019: unresolved external symbol gzeof referenced in function znzeof
5>znz.lib(znzlib.obj) : error LNK2019: unresolved external symbol gzclose referenced in function Xznzclose
5>znz.lib(znzlib.obj) : error LNK2019: unresolved external symbol gzopen referenced in function znzopen
5>znz.lib(znzlib.obj) : error LNK2019: unresolved external symbol gzseek referenced in function znzseek
5>znz.lib(znzlib.obj) : error LNK2019: unresolved external symbol gztell referenced in function znztell

znz 是 nifticlib 的一部分。是使用zlib库的部分。

编辑 2: 为了简单起见,我的问题是 linking 是否像 Linking 1 或 Linking 2 一样发生(知道 nifticlib 依赖于 zlib,两者编译为静态库):

  Linking 1                           Linking 2
--------------           --------------      ---------------
|    zlib    |           |    zlib    |      |  nifticlib  |
--------------           --------------      ---------------
      |                         \                   /
--------------                   \                 /
| nifticlib  |                    \               /
--------------                     \             /
      |                          -------------------
--------------                   |   MyExec.exe    |
| MyExec.exe |                   -------------------
--------------

通常的方法是仅在生成可执行二进制文件时才进行链接。这包括例如普通的可执行文件,但也包括动态库(.dll、.so)。未对静态库(.lib、.a)进行链接。

这意味着如果您构建 "nifticlib" 的静态库,则不需要链接到 "zlib"。

您应该明确地将依赖项从动态依赖项更改为静态依赖项,因为 CMake 将依赖项从静态库传递到最终二进制文件。在这种情况下,它应该无关紧要,因为您没有指定真正的 CMake 依赖项,只是库的一些变量。

注意:在 Visual Studio 中,您可以很容易地 "link" 静态库相互导入。它所做的只是将所有函数串联到一个 .lib 文件中。 CMake 不使用此功能,而是在静态库目标上执行 "TARGET_LINK_LIBRARIES" 时像上面提到的那样携带依赖项。