【问题标题】:How to build CMakeLists the right way?如何以正确的方式构建 CMakeLists?
【发布时间】:2020-03-15 01:52:31
【问题描述】:

我有以下问题:我有两组不同的文件(主要文件和附加文件),我想将它们分开。所以,我有一组文件(主要),我是这样配置的:

set(libplayersource
        ....
        )

add_library( # Sets the name of the library.
        libplayer

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        ${libplayersource})

然后我有第二组文件(附加),我是这样配置的:

set(codec_source
        ...)

add_library(libcodec SHARED ${codec_source})

最终,我需要链接这两组文件:

target_link_libraries( # Specifies the target library.
        libplayer
        libcodec)

在这个配置之后,我还需要包含log lib 以使其工作。首先,我需要找到这个log 库,然后将它包含在我的原生库中。

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)

另外,我应该编辑target_link_libraries 以包含log lib:

target_link_libraries( # Specifies the target library.
        libplayer
        libcodec
        ${log-lib})

如果你打算在libplayer 中使用这个log 库,一切都很好,但是如果你打算在libcodec 集合中使用它,你会得到这个错误:

对 `__android_log_print' 的未定义引用

clang++.exe:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)

这意味着链接器没有看到这个方法的实现。

我在 SO 上找到了这个答案:

https://stackoverflow.com/a/47803975/5709159

为了解决这个问题,我在我的CMakeLists 文件中添加了这一行:

target_link_libraries( # Specifies the target library.
        libcodec
        android
        ${log-lib}
        )

主要 CMake 文件实现:

...
#Main module
set(libplayersource
        ....
        )

add_library( # Sets the name of the library.
        libplayer

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        ${libplayersource})

#Additional module
set(codec_source
        ...)

add_library(libcodec SHARED ${codec_source})

#Log lib
find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)

#Linking

target_link_libraries( # Specifies the target library.
        libcodec
        ${log-lib}
        )

target_link_libraries( # Specifies the target library.
        libplayer
        libcodec
        ${log-lib})
...

所以,我需要在两个库中提及 log lib。

问题是 - 为什么链接器在libcodec 中看不到log lib?为什么我必须添加额外的块?

target_link_libraries( # Specifies the target library.
        libcodec
        ${log-lib}
        )

使log lib 对libcodec 中的链接器可见?

P.S 在 Visual Studio 中,如果你有主项目 A 和两个库 B 和 C,你将这些 B 和 C 库包含在 A 中,就是这样;每个人都知道每个人。我可以从 C 调用 B 中的方法等等。为了从 C 调用 B 方法,我不需要在 B 中包含 C。将这两个库作为主项目包含在 A 中就足够了...

如果我错过了问题中的某些内容,请随时提问。

【问题讨论】:

  • 因为libcodec 是与程序的其余部分分开编译和链接的。为什么 CMake 应该为您猜测?
  • @Botje 编辑了我的问题,添加了 P.S 块
  • 你确定 Visual Studio 会为 static 库 (.libs) AND shared 库 ( DLL)?我希望共享情况在 VS 中同样会失败。
  • @Botje 你的意思是其中一个库应该是静态的,而另一个应该是共享的?我不确定,但如果是其中两个静态 (.lib) ,那么他们可以互相交谈
  • 他们不会“互相交谈”。编译器可能会生成带有未满足符号引用的静态库(.lib 文件)。只有当您将可执行文件或另一个共享库中的所有内容链接在一起时,才能解决未满足的符号。如果您在 CMakeLists.txt 中创建 libplayerlibcodec STATIC,您将看到相同的结果。

标签: c++ cmake android-ndk linker


【解决方案1】:

如果您的libcodec 使用log-lib 中定义的实现,您必须 明确地将log-lib 链接到libcodec。这个电话:

target_link_libraries( # Specifies the target library.
        libplayer
        libcodec
        ${log-lib})

libcodeclog-lib 链接到libplayer,它log-lib 链接到libcodec。它暗示了这个依赖图:

        libplayer
        /       \
  libcodec     log-lib

target_link_libraries() 调用的第一个参数是“链接到”库,以下所有目标都链接到第一个。因此,您需要将log-lib 链接到libcodec,如下所示:

target_link_libraries( # Specifies the target library.
        libcodec
        ${log-lib}
        )

现在,libcodec 将了解log-lib 中定义的实现,这里暗示了依赖关系图:

        libplayer
        /       \
  libcodec     log-lib
     /
log-lib

可以让这个更干净。我们可以去掉libplayerlog-lib之间的直接链接,并允许log-lib实现传播通过libcodeclibplayer

target_link_libraries(libcodec PUBLIC
        ${log-lib}
        )

target_link_libraries(libplayer PRIVATE
        libcodec
        )

这会将依赖关系图简化为:

        libplayer
        /
  libcodec
     /
log-lib

请参阅 CMake 文档中的 this 部分,了解在链接时如何以及何时使用 PUBLICPRIVATE 关键字。

【讨论】:

  • 所以,如果我理解正确的话,这种方法实际上是这种实现的正确方法,对吧?
  • 是的,但是,您似乎可以稍微简化一下。如果libplayer 依赖于libcodec,而libcodec 依赖于log-lib,则将log-lib 链接到libcodec,它将被继承通过libplayerlibcodec
  • @AlekseyTimoshchenko 我扩展了我的答案以显示这种简化。希望这有帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 2018-05-16
  • 2020-05-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-29
  • 1970-01-01
相关资源
最近更新 更多