使用CMake构建带有外部库的项目

3

我是一个 ARM 构建的初学者。 我想为 armel 平台构建此代码。 这是我的代码:

#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>
#include <nlohmann/json.hpp>
int main() 
{
    return 0;
}

我有一个Cmake文件:

cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR)
project(test CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_COMPILER arm-linux-gnueabi-g++-10)

set(SRC_FILES test.cpp)

add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY)
add_definitions(-DBOOST_SYSTEM_NO_DEPRECATED)
add_definitions(-DBOOST_ALL_NO_LIB)
add_definitions(-DBOOST_NO_RTTI)
add_definitions(-DBOOST_NO_TYPEID)
add_definitions(-DBOOST_ASIO_DISABLE_THREADS)

add_executable(${PROJECT_NAME} ${SRC_FILES})

我将nlohmann库安装到了:

/usr/local/include/nlohmann/json.hpp

在我生成make和make之后:
/home/test-machine/project-dir/test/test.cpp:3:10: fatal error: nlohmann/json.hpp: No such file or directory
    3 | #include <nlohmann/json.hpp>
      |          ^~~~~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [CMakeFiles/test.dir/build.make:82: CMakeFiles/test.dir/test.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:95: CMakeFiles/test.dir/all] Error 2
make: *** [Makefile:103: all] Error 2


为什么会出现这个错误,请帮我解决!!!

2
非本地编译器通常不会默认使用系统包含路径,您可能需要指定/usr/local/include作为包含目录。 - Alan Birtles
你可以使用命令"include_directories(/usr/local/include)"来实现:https://cmake.org/cmake/help/latest/command/include_directories.html - Laurent Jospin
谢谢!我在真实代码上测试了它,但是我遇到了很多ld的通知。我收到了这样的通知:/usr/lib/gcc-cross/arm-linux-gnueabi/10/../../../../arm-linux-gnueabi/bin/ld: CMakeFiles/power-control.dir/src/power-control.cpp.o: in function `sdbusplus::bus::bus::process_discard()': power-control.cpp:(.text._ZN9sdbusplus3bus3bus15process_discardEv[_ZN9sdbusplus3bus3bus15process_discardEv]+0x98): undefined reference to `sdbusplus::exception::SdBusError::SdBusError(int, char const*, sdbusplus::SdBusInterface*) 在执行make之后,我没有执行文件。 - Ivan Raih
https://json.nlohmann.me/integration/cmake/ - Artyer
3个回答

1

在我看来,更正确的方式似乎是正确安装库,然后使用 find_package指令。

# CMakeLists.txt
find_package(nlohmann_json 3.2.0 REQUIRED)
...
add_library(foo ...)
...
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)

上面的例子是nlohmann Cmake文档的一部分。


1

你的代码存在一些问题。如果你不介意,我会使用更新的CMake。

# CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(test LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

add_executable(foobar)

target_sources(foobar PRIVATE
    test.cpp
)

target_compile_definitions(foobar PRIVATE
    BOOST_ERROR_CODE_HEADER_ONLY
    BOOST_SYSTEM_NO_DEPRECATED
    BOOST_ALL_NO_LIB
    BOOST_NO_RTTI
    BOOST_NO_TYPEID
    BOOST_ASIO_DISABLE_THREADS
)

要指定您的ARM编译器,请使用CMAKE_TOOLCHAIN_FILE。如果您在CMake代码中指定编译器,这可能会很好,但以后会引起问题。

# arm.cmake

set(CMAKE_CXX_COMPILER arm-linux-gnueabi-g++-10)

set(CMAKE_C_COMPILER arm-linux-gnueabi-g-10)

现在当你创建项目时,请执行以下操作:

cd <your-project>
cmake -S . -B build/ -D CMAKE_TOOLCHAIN_FILE=arm.cmake

现在你的代码存在一个问题,就是没有办法找到你的第三方依赖库。
你需要添加代码来查找/链接boost。并且查找/链接nlohmann/json

Boost

如何在CMakeLists.txt中添加Boost库?

nlohmann/json

这个仓库实际上有非常好的文档,告诉你如何将库添加到你的CMake项目中。

https://github.com/nlohmann/json#cmake

简而言之:

要在CMake项目中使用此库,您可以直接使用find_package()定位它,并使用生成的包配置中的命名空间导入目标:

# CMakeLists.txt
find_package(nlohmann_json 3.2.0 REQUIRED)
...
add_library(foo ...)
...
target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)

0

对于非本地编译器,您必须配置整个环境。

实际上,在这样做时,我强烈建议使用工具链文件

使用它,您可以设置您的工具链,甚至是多个工具链。

然后,对于环境,我建议使用其安装程序安装库,并让CMake找到它。以nlohmann json为例:

nlohmann_json$ mkdir build
nlohmann_json$ cd build
nlohmann_json/build$ cmake .. -DCMAKE_INSTALL_PREFIX=/home/youruser/arm-prefix -DCMAKE_TOOLCHAIN_FILE=yourtoolchain.cmake
nlohmann_json/build$ cmake --build . --target install

这些命令将使用您的工具链设置nlohmann json,并将其安装在新的前缀中。

然后,在您的项目中,您可以拥有这样的工具链和这样的CMakeLists.txt文件:

toolchain.cmake:

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_CXX_COMPILER arm-linux-gnueabi-g++-10)
set(CMAKE_C_COMPILER arm-linux-gnueabi-gcc-10)
set(CMAKE_STAGING_PREFIX /home/youruser/arm-prefix)
set(CMAKE_SYSTEM_PREFIX_PATH /home/youruser/arm-prefix)

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

CMakeLists.txt:

project(test CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(test)

find_package(nlohmann_json REQUIRED)

target_sources(test PRIVATE test.cpp)
target_link_libraries(test PUBLIC nlohmann_json::nlohmann_json)

魔法在于前缀路径。当您将安装前缀设置为安装库并在构建项目时设置相同的前缀路径时,find_package 突然起作用了。如果在这两个项目之间使用相同的工具链,则 CMake 将检测到这两个软件包是兼容的。

请注意,我在 CMakeLists 文件中也明确没有使用变量。这是因为变量是 CMake 的痛点,并导致意外行为。在正常的 CMake 文件中定义项目时,它们的使用应该很少。

此外,请远离 add_definitionslink_directoriesinclude_directories 和所有这些命令。始终优先使用 target_compile_definitionstarget_link_librariestarget_include_directories 和其他基于目标的命令。


至于boost,我不太了解他们的构建系统。可能有一些交叉编译库并安装它的方法,但我的知识就到这里了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接