使用 IPP 将 OpenCV 与静态 zlib 链接,在 Linux 上使用 CMake

Linking OpenCV with static zlib using IPP, using CMake on Linux

我正在使用 IPP 库的独立英特尔版本从源代码构建 OpenCV。我还使用了 Intel 优化版本的 zlib,它(与标准版本的 zlib 不同)依赖于另外三个 IPP 库。另外,我正在静态地 linking zlib,所以我需要让任何使用它的目标知道这些依赖关系。

我已经在 Windows 上完成了所有工作,现在我正在尝试在 Linux 上做同样的事情。我已将以下文本添加到 Open CV 的主 CMakeLists.txt 文件中,就在搜索和初始化所有其他依赖项的位置之后:

include(cmake/OpenCVFindLibsGrfmt.cmake)
include(cmake/OpenCVFindLibsGUI.cmake)
include(cmake/OpenCVFindLibsVideo.cmake)
include(cmake/OpenCVFindLibsPerf.cmake)
include(cmake/OpenCVFindLAPACK.cmake)
include(cmake/OpenCVFindProtobuf.cmake)

#---------------------------My changes start here-------------------------
# We insert this code here because this is the point where ZLIB_LIBRARIES 
# has just become defined, and by putting it here we ensure that our 
# changes are propagated throughout the rest of the project.
if (MSVC)

    add_library(ippdcmt STATIC IMPORTED)
    add_library(ippsmt STATIC IMPORTED)
    add_library(ippcoremt STATIC IMPORTED)
    if(CMAKE_SIZEOF_VOID_P EQUAL 8)
        # We are compiling 64-bit code
        set_target_properties(ippdcmt PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/intel64_win/ippdcmt.lib")
        set_target_properties(ippsmt PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/intel64_win/ippsmt.lib")
        set_target_properties(ippcoremt PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/intel64_win/ippcoremt.lib")
    else()
        # We are compiling 32-bit code
        set_target_properties(ippdcmt PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/ia32_win/ippdcmt.lib")
        set_target_properties(ippsmt PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/ia32_win/ippsmt.lib")
        set_target_properties(ippcoremt PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/ia32_win/ipcoremt.lib")
    endif()
    list(APPEND ZLIB_LIBRARIES ippdcmt ippsmt ippcoremt)

elseif(CMAKE_COMPILER_IS_GNUCC)

    add_library(libippdc STATIC IMPORTED)
    add_library(libipps STATIC IMPORTED)
    add_library(libippcore STATIC IMPORTED)
    if(CMAKE_SIZEOF_VOID_P EQUAL 8)
        # We are compiling 64-bit code
        set_target_properties(libippdc PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/intel64/libippdc.a")
        set_target_properties(libipps PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/intel64/libipps.a")
        set_target_properties(libippcore PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/intel64/libippcore.a")        
    else()
        # We are compiling 32-bit code
        set_target_properties(libippdc PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/ia32/libippdc.a")
        set_target_properties(libipps PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/ia32/libipps.a")
        set_target_properties(libippcore PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/ia32/libippcore.a")  
    endif()
    list(APPEND ZLIB_LIBRARIES libippdc libipps libippcore)

endif()
#---------------------------My changes end here---------------------------

在 运行 CMake 然后 make 上,构建在几个小时后达到 99%,然后在要编译的 vary 最后一个模块之一上失败,抱怨找不到与 IPP 相关的zlib 的依赖项。检查编译日志,很容易看出原因:出于某种原因,makefile 将 zlib 作为最后一个库放在 link 行,after 相关的英特尔 IPP库,并且由于 gcc 以严格的顺序读取 link 行,这意味着依赖项没有得到正确处理。

因此,我需要一种方法来强制 CMake 以 IPP 库 always 将 zlib 放在 link 行之后的方式构建 makefile。

我读过 我应该能够使用 CMake 属性 IMPORTED_LINK_INTERFACE_LIBRARIES 来实现这一点。所以我尝试添加一行类似于

set_target_properties([something to denote zlib] PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES libippdc libipps libippcore)

...紧接在 list(APPEND ZLIB_LIBRARIES libippdc libipps libippcore) 之后。但是,我不知道用什么来代替 [something to denote zlib] 以便 CMake 理解并采取相应的行动。如果我用 ZLIB::ZLIB 替换它(CMake 的本机 FindZLIB 函数的通常输出),那么我不会收到任何错误消息,但它不会产生任何差异;几个小时后,构建完全像以前一样失败了。如果我尝试用我能想到的或在 OpenCV 的 CMake 文件中的其他地方找到的任何其他东西替换 [something to denote zlib] - 到目前为止,'zlib'、'ZLIB'、'ZLIB_LIBRARY'、'zlib.a', 'libz.a' - 然后 CMake 失败并显示一条错误消息:

set_target_properties Can not find target to add properties to: libz.a (or whatever)

所以我想我的问题是,OpenCV 的 CMake 系统如何在内部引用 zlib,以便我可以将此 属性 添加到其中?或者,我是不是以完全错误的方式处理这个问题,是否有更好的方法来实现我的 objective(简而言之,拥有一个静态 links Intel 增强版本的 OpenCV 构建zlib 及其所有依赖项)?

事实证明,我的代码块没有任何问题。我不确定 set_target_properties 行是否必要,但为了安全起见,我将其保留在最终语法中:

  set_property(TARGET   ZLIB::ZLIB 
               PROPERTY INTERFACE_LINK_LIBRARIES libippdc libipps libippcore)

主要问题是我的代码块的位置。事实证明,在对 include(cmake/OpenCVFindLibsGrfmt.cmake) 的调用中,找到并初始化了 zlib 本身 以及 libtiff、libpng 和 libIlmImf,所有这些都依赖于它。因此,这些目标的属性包含对 zlib alone 的依赖,而我后来的代码块并没有改变这一点。我的代码块必须在 zlib 的初始化和依赖于它的 everything 的初始化之间移动。

这有点棘手,但最后我做的是:

  1. 将行 include(cmake/OpenCVFindLibsPerf.cmake) 移动到块中的第一行,以便找到 IPP 库并 IPP_ROOT_DIR 正确初始化。
  2. 从初始化 zlib 的 cmake/OpenCVFindLibsGrfmt.cmake 中提取前十行左右,并在 include(cmake/OpenCVFindLibsPerf.cmake) 之后立即将它们放入主 CMakeLists.txt fine 中。
  3. 然后我重新插入了自定义代码块。
  4. 最后我把剩下的包含进去,完成所有其他库的初始化。

最终的结果是一个干净的构建。