【问题标题】:CMake PUBLIC / INTERFACE problems while linking链接时出现 CMake PUBLIC / INTERFACE 问题
【发布时间】:2020-11-08 21:07:18
【问题描述】:

我在 CMake 和链接/编译我正在处理的项目的一部分方面遇到了问题。

目标的文件夹结构如下:

── sleeptimer
    ├── config
    │   └── sl_sleeptimer_config.h
    ├── inc
    │   └── sl_sleeptimer.h
    └── src
        ├── sl_sleeptimer.c
        ├── sl_sleeptimer_hal.h
        ├── sl_sleeptimer_hal_prortc.c
        ├── sl_sleeptimer_hal_rtc.c
        └── sl_sleeptimer_hal_rtcc.c

应添加此内容的 CMake 文件如下所示:

project(service)

add_library(${PROJECT_NAME}
        sleeptimer/src/sl_sleeptimer.c)

target_include_directories(${PROJECT_NAME} PUBLIC
        sleeptimer/config
        sleeptimer/inc
        sleeptimer/src)

target_link_libraries(${PROJECT_NAME} common_platform emlib)

但我在链接时遇到错误:

platform/service/libservice.a(sl_sleeptimer.c.obj): In function `sl_sleeptimer_init':
/mnt/c/Users/username/Downloads/_test/gecko_sdk/platform/service/sleeptimer/src/sl_sleeptimer.c:152: undefined reference to `sleeptimer_hal_init_timer'
/mnt/c/Users/username/Downloads/_test/gecko_sdk/platform/service/sleeptimer/src/sl_sleeptimer.c:153: undefined reference to `sleeptimer_hal_enable_int'
/mnt/c/Users/username/Downloads/_test/gecko_sdk/platform/service/sleeptimer/src/sl_sleeptimer.c:154: undefined reference to `sleeptimer_hal_get_timer_frequency'
platform/service/libservice.a(sl_sleeptimer.c.obj): In function `sl_sleeptimer_stop_timer':
/mnt/c/Users/username/Downloads/_test/gecko_sdk/platform/service/sleeptimer/src/sl_sleeptimer.c:313: undefined reference to `sleeptimer_hal_disable_int'
platform/service/libservice.a(sl_sleeptimer.c.obj): In function `sl_sleeptimer_get_tick_count':
/mnt/c/Users/username/Downloads/_test/gecko_sdk/platform/service/sleeptimer/src/sl_sleeptimer.c:428: undefined reference to `sleeptimer_hal_get_counter'
platform/service/libservice.a(sl_sleeptimer.c.obj): In function `set_comparator_for_next_timer':
/mnt/c/Users/username/Downloads/_test/gecko_sdk/platform/service/sleeptimer/src/sl_sleeptimer.c:1091: undefined reference to `sleeptimer_hal_enable_int'
/mnt/c/Users/username/Downloads/_test/gecko_sdk/platform/service/sleeptimer/src/sl_sleeptimer.c:1092: undefined reference to `sleeptimer_hal_set_compare'
platform/service/libservice.a(sl_sleeptimer.c.obj): In function `update_first_timer_delta':
/mnt/c/Users/username/Downloads/_test/gecko_sdk/platform/service/sleeptimer/src/sl_sleeptimer.c:1100: undefined reference to `sleeptimer_hal_get_counter'

所有未定义的函数都在sl_sleeptimer_hal.h 中声明。

我有点迷茫,因为我或多或少刚刚开始学习 make / CMake。

【问题讨论】:

  • 您需要提供更多信息。具体来说,那些未定义的函数在哪里定义?看起来您可能需要将所有这些 .c 文件添加到 add_library
  • sleeptimer/src 添加到target_include_directories 中不会生成该目录中的所有C 文件。它只是告诉编译器在那里寻找头文件。
  • 未定义的函数是在sl_sleeptimer_hal.h 中定义的,由于sl_sleeptimer_hal.h@kaylum,我已将sleeptimer/src 添加到target_include_directories
  • 你确定这些函数是在头文件中定义的吗?那将是不寻常的。头文件通常只包含函数原型,而不包含完整的函数实现/定义。
  • 你添加所有其他文件是对的,我的错。感谢您指出这一点。标题中也没有定义这些函数,也是我的错,只是原型。

标签: c makefile cmake


【解决方案1】:

我认为问题在于您没有添加所有源文件。 我还添加了一些建议。默认为 PRIVATE,除非你知道你需要 PUBLIC/INTERFACE。

# Your project and your targets should never have the same name btw
project(SERVICE
 LANGUAGES C
)

add_library(service)

# Add all your source files
target_sources(service PRIVATE 
    sleeptimer/src/sl_sleeptimer.c
    sleeptimer/src/sl_sleeptimer_hal_prortc.c
    sleeptimer/src/sl_sleeptimer_hal_rtc.c
    sleeptimer/src/sl_sleeptimer_hal_rtcc.c
)

# EDIT:
# You probably want 1 or all of these to be PUBLIC depending on your circumstances.
target_include_directories(service 
# Clients don't need to know these include directories exist
PRIVATE
    sleeptimer/config
    sleeptimer/src

# Both service and clients that link against service need this include directory
PUBLIC
    sleeptimer/inc
)

target_link_libraries(service PRIVATE common_platform emlib)

编辑:

PRIVATE/INTERFACE/PUBLIC的基本解释:

PRIVATE 意味着只有目标服务可以看到它。 INTERFACE 表示只有链接到服务的目标才能看到它。 PUBLIC 是 PRIVATE/INTERFACE 的组合。

INTERFACE 通常只用于只有头文件的库,或者非常特殊的情况。

要获得真正深入的解释,我建议使用 Professional CMake: 实用指南 (https://crascit.com/professional-cmake/)

【讨论】:

  • 我认为我必须为其他目标引用的头文件指定接口?你说我的项目和目标不应该使用相同的名称。如果这只是一个“子”项目或更大项目的目标,这是否适用?
  • 您的项目名称和目标名称应该始终不同。这是因为 cmake 变量依赖于项目名称,这可能会导致严重的混淆。此外,您通常根本不希望头文件管理器成为 INTERFACE。 INTERFACE 是一个非常特殊的情况。但是,您很可能希望 inlude_directories 公开。
  • 一些 include_directories 准确地说不是全部
  • 感谢您的解释。您能否进一步详细说明或给我眨眼,我必须阅读有关 INTERFACE 说明符的内容。据我了解,这些是我的目标以及项目中其他目标使用的文件?因为我需要这个头来编译这个目标并且我也在我自己的代码中使用它,所以这应该是一个接口。
  • 我添加了关于 PRIVATE/INTERFACE/PUBLIC 的基本解释。您可能希望您的“inc”目录是公开的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-10
  • 2017-06-21
  • 1970-01-01
相关资源
最近更新 更多