【问题标题】:CMake find_* not searching subdirectoriesCMake find_* 不搜索子目录
【发布时间】:2020-12-16 20:37:06
【问题描述】:

我一直在尝试让我的交叉编译工具链从我的 WSL Ubuntu 到 RasberryPi 工作。 由于我的 RaspberryPi 4B 的 GCC 版本是 8.3.0,我最近尝试使用来自 here 的 Buster 工具链。 我当前的文件夹结构如下所示:

Test
  -> CMakeLists.txt
  -> main.cpp
Toolchain
  -> arm-linux-gnueabihf
  -> bin
  -> include
  -> lib
  -> libexec
  -> share
raspi_root
  -> lib
  -> usr

Test 文件夹包含一个简单的测试项目,以使工具链正常工作。真正的目标项目要大一些。工具链是从存储库下载的交叉编译器工具链,最后 raspi_root 文件夹是来自 Raspberry Pi 的 libusr 文件夹的副本。 main.cpp 看起来很基本:

#include <iostream>
#include <bluetooth>

int main(int argc, char** argv)
{
    std::cout << "Hello World" << std::endl;
}

请注意,它包含蓝牙标头,因为这是我遇到问题的库之一。

我的 CMakeLists.txt 看起来像这样:

set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})

SET(CMAKE_SYSTEM_NAME Linux)
set(COMPILER_PREF "/home/user/workspace/toolchain/bin/arm-linux-gnueabihf-")
SET(CMAKE_C_COMPILER "${COMPILER_PREF}gcc")
set(CMAKE_CXX_COMPILER "${COMPILER_PREF}g++")

set(SYSROOT "${SOURCE_DIR}/../raspi_root")
set(CMAKE_FIND_ROOT_PATH "${SYSROOT}")
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

cmake_minimum_required(VERSION 3.0) # setting this is required

set(project_target Test)
project(${project_target})            # this sets the project name

set(SOURCES main.cpp)

find_library(BLUETOOTH bluetooth REQUIRED)

add_executable(${project_target} ${SOURCES})
set_property(TARGET ${project_target} PROPERTY CXX_STANDARD 17)

target_link_libraries(${project_target} PUBLIC
    # ${SYSROOT}/usr/lib/arm-linux-gnueabihf/libbluetooth.so
    ${BLUETOOTH}
)

我试图让它尽可能简单,只让它使用工具链编译我的 hello world 程序并链接蓝牙库以使其在我的 Raspberry Pi 上工作。

现在出现以下问题: Wenn 我做cmake . 它没有找到蓝牙库文件:

Please set them or make sure they are set and tested correctly in the CMake files:
BLUETOOTH
    linked by target "Test" in directory /home/user/workspace/Test

他们就在${SYSROOT}/usr/lib/arm-linux-gnueabihf下面 只能找到像 ${SYSROOT}/usr/lib${SYSROOT}/lib 这样的传统目录中的库。当我从这些目录之一创建到 libbluetooth.so 的符号链接时,cmake 似乎找到了该库,尽管稍后在链接时出现了其他错误。 我还尝试通过将完整的库路径放在target_link_libraries 下替换find_library,但随后找到了库,但标题当然丢失了。我想这些必须单独包含在内。

但是,我的问题是,为什么 CMake 的 find_* 函数不能浏览更多的子目录?链接 boost-libraries 时也会发生这种情况。 find_package(boost) 找到标头但不链接库。

___ 编辑:___

感谢 Tsyvarev,我可以成功编译并执行我的 hello world 程序。现在,对于下一步,我想包含在我的其他项目中导致最多问题的 boost 线程库。 所以我将#include &lt;boost/thread.hpp&gt; 添加到我的main.cpp 和find_package(Boost COMPONENTS thread REQUIRED)${Boost_INCLUDE_DIRS} 到target_include_directories 和${Boost_LIBRARIES} 到我的CMakeLists.txt 中的target_link_libraries。现在它使用cmake . -DCMAKE_TOOLCHAIN_FILE=Toolchain 找到我的库并生成构建文件。但是使用make 我得到以下链接错误:

<path to toolchain linker>/ld: warning: librt.so.1, needed by ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so, not found (try using -rpath or -rpath-link)
<path to toolchain linker>/ld: warning: libpthread.so.0, needed by ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so, not found (try using -rpath or -rpath-link)
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_setspecific@GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_condattr_setclock@GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_key_create@GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_join@GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_detach@GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_getspecific@GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_create@GLIBC_2.4'
<path to toolchain linker>/ld: /home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_chrono.so: undefined reference to `clock_gettime@GLIBC_2.4'

我认为一旦正确找到库,未定义的引用就会被解析? CMakeCache.txt 说找到的线程库是libpthread.a 而不是libpthread.so。此外,在运行make VERBOSE=1 时,这是链接命令(为了便于阅读而中断):

/home/felix/workspace/toolchain/bin/arm-linux-gnueabihf-g++    
    -rdynamic CMakeFiles/Test.dir/main.cpp.o  
    -o Test
    -Wl,-rpath,/home/felix/workspace/Test/../raspi_root/usr/lib/arm-linux-gnueabihf:/home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf
    ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so
    /home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_chrono.so
    /home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_system.so
    /home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_date_time.so
    /home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_atomic.so
    ../raspi_root/usr/lib/arm-linux-gnueabihf/libpthread.a
    ../raspi_root/usr/lib/arm-linux-gnueabihf/libbluetooth.so

我是否需要让 CMake 搜索共享库而不是静态库?我该怎么做?如果没有,我错过了什么?

感谢您的帮助。

【问题讨论】:

  • “但是,我的问题是,为什么 CMake 的 find_* 函数不能浏览更多的子目录?” - 因为它是designed sofind_library 和其他 find_* 函数的搜索机制不是递归的。有像/usr 这样的已知系统安装前缀,像lib/ 这样的库前缀,所以CMake 只在那里查找。如果您希望 CMake 在${SYSROOT}/usr/lib/arm-linux-gnueabihf 下搜索,则添加适当的目录进行搜索。例如。 set(CMAKE_LIBRARY_PATH "/usr/lib/arm-linux-gnueabihf").
  • 另请注意,在 CMake 工具链中的设置通常与 CMakeLists.txt 文件分离。从SET(CMAKE_SYSTEM_NAME ...)SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ...) 的行通常位于工具链文件 中,由-DCMAKE_TOOLCHAIN_FILE=&lt;path/to/file&gt; 选项指定到cmake。有关交叉编译的更多信息,请参阅documentation
  • 首先非常感谢您的快速响应!关于工具链的分离,我按照你的建议做了。据我了解,这只是为了有一个通用的 cmake 文件来本地构建项目,并且根据我选择的交叉编译环境,我可以选择相应的工具链文件。那是对的吗?或者通过变量指定工具链文件是否有其他值得注意的副作用,除了包括单独的变量(CMAKE_SYSTEM_NAME 到 CMAKE_FIND_ROOT_PATH_MODE)
  • 除了将项目与构建环境分离之外,将特定于环境的变量放入单独的工具链文件中可以可靠地使用 try_compile 命令(和相关功能):当 CMake 为编译/链接配置新项目时检查,它也将CMAKE_TOOLCHAIN_FILE 变量传递给该项目,以便该项目使用与您的项目相同的工具链(及其设置)。

标签: c++ linux cmake cross-compiling


【解决方案1】:

好的,感谢 Tsyvarev 对我所缺少的内容的快速提示。事实证明,答案比我想象的要明显。

正如 Tsyvarev 在 cmets CMake 中提到的那样,不会在指定的根目录中递归搜索库。相反,它搜索标准路径,例如 /usr/lib、/lib 等。可以通过将它们附加到 CMAKE_LIBRARY_PATH 来添加更多搜索路径,如 documentation 中所述。所以为了解决我的错误,我做了以下事情: 我将所需的库路径附加到搜索路径。

...
set(SOURCES main.cpp)
set(CMAKE_LIBRARY_PATH 
    ${CMAKE_LIBRARY_PATH}
    "/lib/arm-linux-gnueabihf"
    "/usr/lib/arm-linux-gnueabihf"
)
add_executable(${project_target} ${SOURCES})
...

然后我发现我忘了添加任何包含目录:

target_include_directories(${project_target} PUBLIC
    ${SYSROOT}/usr/include/bluetooth
    ${SYSROOT}/usr/include/arm-linux-gnueabihf
)

我能够编译main.cpp

至于编辑: 为了正确链接 boost 线程库,我还必须链接它的依赖项。所以我说:

find_package(Boost COMPONENTS thread REQUIRED)

...

target_include_directories(${project_target} PUBLIC
    ${SYSROOT}/usr/include/bluetooth
    ${SYSROOT}/usr/include/arm-linux-gnueabihf
    ${Boost_INCLUDE_DIRS}
)

target_link_libraries(${project_target} PUBLIC
    rt
    Threads::Threads
    ${Boost_LIBRARIES}
    ${BLUETOOTH}
)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 2016-02-12
    相关资源
    最近更新 更多