在树莓派上交叉编译和调试 C/C++ 库
树莓派是一款令人惊叹的微型电脑,功能强大且价格低廉,是全球业余爱好者和开发者的梦想。凭借其在嵌入式系统中的应用潜力,使用 C/C++ 开发其代码非常普遍,尤其是在效率和性能至关重要的场合。然而,即使它是一款性价比很高的强大系统,在构建相对较大的 C/C++ 库时也可能速度较慢,因此交叉编译对于开发人员来说非常方便。
本文将介绍如何在 Windows 上设置到树莓派的交叉编译(从 Linux 上也可以实现,配置非常相似)。我们将交叉编译一个库,将 Conan 包上传到服务器(可以是 conan_server、conan.io 或 Artifactory),然后从树莓派安装和使用该库,即构建一个应用程序并将其链接到这个交叉编译的库。作为额外收获,本文还将解释如何将源代码捆绑到包本身,以便稍后从树莓派调试库。
Hello world 库
将要构建和打包的库存在于此 GitHub 仓库中。它只是一个简单的 C++ “Hello world” 库项目,使用 CMake,没有任何特殊或与 Conan 相关的内容。
然后,我们将从使用 conan new
命令创建的包模板开始。
$ conan new Hello/0.1@user/testing -t # use your own user
现在,让我们用以下内容替换根目录下的 conanfile.py
。
from conans import ConanFile, CMake
import os
class HelloConan(ConanFile):
name = "Hello"
version = "0.1"
settings = "os", "compiler", "build_type", "arch"
def source(self):
self.run("git clone https://github.com/memsharded/hello.git")
def build(self):
cmake = CMake(self.settings)
gcc_dbg_src = ""
if self.settings.compiler == "gcc" and self.settings.build_type == "Debug":
gcc_dbg_src = ' -DCMAKE_CXX_FLAGS="-fdebug-prefix-map=%s/hello=src"' % os.getcwd()
self.run('cmake hello %s %s' % (cmake.command_line, gcc_dbg_src))
self.run("cmake --build . %s" % cmake.build_config)
def package(self):
self.copy("*.h", dst="include", src="hello")
if self.settings.compiler == "gcc" and self.settings.build_type == "Debug":
self.copy("*.cpp", dst="src", src="hello")
self.copy("*.lib", dst="lib", keep_path=False)
self.copy("*.a", dst="lib", keep_path=False)
def package_info(self):
self.cpp_info.libs = ["hello"]
它与模板创建的非常相似,但有两个细微的差别。首先,由于我们希望能够在树莓派中调试包,因此有必要定义 gcc 标志 debug-prefix-map
,以便它指向相对源文件夹 src
而不是原始文件夹。因为我们将在不同的机器上进行调试,原始的绝对源路径将毫无意义。因此,我们只是为 CMake 定义了该标志(有条件地针对 gcc
和 Debug
设置)。
if self.settings.compiler == "gcc" and self.settings.build_type == "Debug":
gcc_dbg_src = ' -DCMAKE_CXX_FLAGS="-fdebug-prefix-map=%s/hello=src"' % os.getcwd()
然后,我们只需将源文件 *.cpp
复制到最终包中(也仅针对相同的设置)。
if self.settings.compiler == "gcc" and self.settings.build_type == "Debug":
self.copy("*.cpp", dst="src", src="hello")
可以通过运行以下命令测试此包配方:
$ conan test_package
Hello world!
设置交叉编译工具链
在本例中,我们将使用 SysProg 工具链。我们使用 4.6.3 工具链,并带有完整的 sysroot,这非常方便。我们下载工具,将其安装到 C:\SysGCC\Raspberry
中,并将 C:/SysGCC/Raspberry/bin/
添加到系统 PATH 中。
现在,我们可以像 conan test_package -e CXX=some_gcc_compiler
那样将交叉编译器作为参数指定给 Conan 命令,但我们可以使用 **Conan 配置文件** 使其更简单。因此,我们在 <userhome>/.conan/profiles/rpi_gcc46
中创建一个包含以下内容的文件:
[settings]
os: Linux
compiler: gcc
compiler.version: 4.6
compiler.libcxx: libstdc++
build_type: Debug
arch: armv6
[env]
CC=arm-linux-gnueabihf-gcc
CXX=arm-linux-gnueabihf-g++
请注意,需要定义 armv6
架构和 Linux
设置,因为默认的 Conan 设置将对应于 Windows 开发环境。
由于生成的二进制文件在 Windows 上不可执行,因此我们更改了 test_package/conanfile.py
,以便 test()
方法只检查二进制文件是否存在。
def test(self):
if platform.system () != self.settings.os:
assert os.path.exists("bin/example")
else:
self.run(os.sep.join([".", "bin", "example"]))
通过此配置,创建用于 R-PI 的调试包只需执行以下操作:
$ conan test_package -pr=rpi_gcc46
上传并安装到树莓派
在本地创建包后,可以将其上传到任何 Conan 远程服务器(conan.io、Artifactory、conan_server)。
$ conan upload Hello/0.1@user/testing -r=myremote --all
在树莓派端,我们将创建一个非常简单的使用者项目,其中包含一个 example.cpp
文件。
#include "hello.h"
int main(){
hello();
}
一个用于构建它的 CMakeLists.txt
脚本。
Project(Consumer)
cmake_minimum_required(VERSION 2.8.9)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
add_executable(example example.cpp)
target_link_libraries(example ${CONAN_LIBS})
以及用于安装依赖项的 conanfile.txt
。
[requires]
Hello/0.1@diego/testing
[generators]
cmake
[imports]
src, *.cpp -> src
请注意,.cpp
源文件是如何从包中复制(“导入”)到当前二进制文件夹的,以便调试器可以轻松找到它们。
安装交叉编译的“Hello”包很容易,现在我们不需要配置文件,因为 R-PI 的默认设置很好,所以我们只需设置 build_type
。
$ conan install .. -s build_type=Debug
构建和调试
构建我们的 R-PI 应用程序现在是一个标准的 CMake 过程。
$ mkdir build && cd build
$ cmake .. -DCMAKE_BUILD_TYPE=Debug
$ cmake --build .
$ bin/example
Hello World!
好消息是,在本例中,我们将其构建为 Debug 模式,因此我们可以调试应用程序并 step
进入包库代码。
$ gdb bin/example
> ...
> Reading symbols from /home/pi/consumer/build/bin/example...done.
(gdb) start
Temporary breakpoint 1 at 0x8914: file /home/pi/consumer/example.cpp, line 4.
Starting program: /home/pi/consumer/build/bin/example
(gdb) step
hello () at src/hello.cpp:5
5 std::cout << "Hello World!\n";
瞧,我们可以看到 hello.cpp
源代码行!
结论
Conan 是一个纯 Python 应用程序,因此在树莓派上安装它就像 sudo pip install conan
一样简单。
在本例中,我们演示了如何为 gcc
和 gdb
创建包含调试信息的包,但类似的方法也可以应用于其他平台,例如打包 Visual Studio 的 .pdb
文件。
由于 Conan 与构建系统和编译器完全正交,因此使用 Conan 交叉编译包非常简单。配置文件是一个非常方便的功能,可以将设置、选项和环境变量集中在一起,以便轻松地在不同的开发环境和目标之间切换。
当交叉编译工具链更复杂时,可能需要更多配置才能考虑这些工具链的多样性,但这肯定是可以做到的。我们知道 Conan 用户正在积极使用 Conan 打包 Android 和 iOS 系统。无论如何,我们正在准备一些针对构建需求管理的主要改进,例如 Android 工具链,您一定会喜欢的。请保持关注,在 x 上关注我们或订阅我们的发行公告邮件列表!