全部产品
云市场

基于Make的交叉编译示例

更新时间:2019-03-25 11:35:27

本文以将SDK移植到 arm-linux 平台为例, 演示一个完整的交叉编译移植过程

提示: 如果您通过将SDK中的文件抽取出来的方式编译SDK, 则可以跳过本章


交叉编译到嵌入式硬件平台

对于嵌入式硬件平台的情况, 对编译出目标平台的libiot_sdk.a, 需要经历如下几个步骤:

  • tools/board/目录下添加一个对应的配置文件, 文件名规范为config.XXX.YYY, 其中XXX部分就对应后面wrappers/os/XXX目录的HAL层代码
  • 在配置文件中, 至少要指定:
    • 交叉编译器 OVERRIDE_CC 的路径
    • 交叉链接器 OVERRIDE_LD 的路径
    • 静态库压缩器 OVERRIDE_AR 的路径
    • 编译选项 CONFIG_ENV_CFLAGS, 用于C文件的编译
    • 链接选项 CONFIG_ENV_LDFLAGS, 用于可执行程序的链接
  • 尝试编译SDK, 对可能出现的跨平台问题进行修正, 直到成功产生目标格式的libiot_sdk.a
  • 最后, 您需要以任何您喜欢的编译方式, 产生目标架构的libiot_hal.a
  • 若目标平台尚未被适配, 则libiot_hal.a对应的源代码在C-SDK中并未包含, 需要您自行实现HAL_*()接口

下面以某款目前未官方适配的 arm-linux 目标平台为例, 演示如何编译出该平台上可用的libiot_sdk.a

安装交叉编译工具链

仍以Ubuntu16.04开发环境为例

  1. $ sudo apt-get install -y gcc-arm-linux-gnueabihf
  2. $ arm-linux-gnueabihf-gcc --version
  3. arm-linux-gnueabihf-gcc (Ubuntu/Linaro 4.8.4-2ubuntu1~14.04.1) 4.8.4
  4. Copyright (C) 2013 Free Software Foundation, Inc.
  5. This is free software; see the source for copying conditions. There is NO
  6. warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

添加配置文件

  1. $ touch tools/board/config.arm-linux.demo
  2. $ ls tools/board/
  3. config.alios.mk3080 config.arm-linux.demo config.ubuntu.x86

编辑配置文件

在这一步, 需要设置编译选项和工具链, 以及跳过编译的目录

  1. $ vim tools/board/config.arm-linux.demo
  2. CONFIG_ENV_CFLAGS = \
  3. -D_PLATFORM_IS_LINUX_ \
  4. -Wall \
  5. -DNO_EXECUTABLES
  6. CONFIG_ENV_LDFLAGS = \
  7. -lpthread -lrt
  8. OVERRIDE_CC = arm-linux-gnueabihf-gcc
  9. OVERRIDE_AR = arm-linux-gnueabihf-ar
  10. OVERRIDE_LD = arm-linux-gnueabihf-ld
  11. CONFIG_wrappers :=

注意, 上面的最后1行表示跳过对 wrappers 目录的编译, 以及 -DNO_EXECUTABLES 表示不要产生可执行程序。在编译未被适配平台的库时在最初是必要的, 这样可以避免产生过多的错误

注:上述配置文件的内容从某些浏览器复制出来之后将会丢失空行。

选择配置文件

  1. $ make reconfig
  2. SELECT A CONFIGURATION:
  3. 1) config.alios.mk3080
  4. 2) config.arm-linux.demo
  5. 3) config.ubuntu.x86
  6. #? 2
  7. SELECTED CONFIGURATION:
  8. VENDOR : arm-linux
  9. MODEL : demo

交叉编译产生库文件libiot_sdk.a

注: 本步骤不编译HAL, 只是为了验证配置文件中的交叉编译参数是否正确, 如果出现错误请对配置文件再次进行修改, 直到编译成功

  1. $ make
  2. BUILDING WITH EXISTING CONFIGURATION:
  3. VENDOR : arm-linux
  4. MODEL : demo
  5. [CC] infra_timer.o <= ...
  6. [CC] infra_json_parser.o <= ...
  7. [CC] infra_preauth.o <= ...

获取交叉编译的产物, 包括静态库和头文件

  1. $ ls -1 output/release/lib/
  2. libiot_sdk.a
  3. libiot_tls.a

这里, libiot_sdk.a文件就是编译好的物联网套件SDK, 已经是ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV)格式, 也就是arm-linux格式的交叉编译格式了

另外, libiot_tls.a是一个裁剪过的加解密库, 您可以选择使用它, 也可以选择使用平台自带的加解密库, 以减小最终固件的尺寸

  1. $ ls -1 output/release/include/
  2. dev_model_api.h
  3. dev_sign_api.h
  4. infra
  5. mqtt_api.h

这里, dev_sign_api.h就是使用SDK中”设备签名”功能需要包含的头文件, 类似mqtt_api.h是使用SDK中”MQTT上云”功能需要的, infra下的头文件也请加入编译搜索路径

开发未适配平台的HAL层

对于实现平台抽象层接口 HAL_XXX_YYY() 的库 libiot_hal.a, 不限制其编译和产生的方式

但是如果你愿意的话, 当然仍然可以借助物联网套件设备端C-SDK的编译系统来开发和产生它

复制一份HAL层实现代码

注: 在 wrappers/os 下需要创建一个与 tools/board/confg.XXX.YYY 中的 XXX 一样的目录用于存放HAL实现

由于目标平台为arm-linux,因此可以复制Ubuntu下面的HAL实现,下面是操作示例:

  1. $ cd wrappers/os/
  2. $ ls
  3. freertos nos nucleus ubuntu
  4. wrappers/os$ cp -rf ubuntu arm-linux
  5. wrappers/os$ rm -f arm-linux/HAL_UART_linux.c
  6. wrappers/os$ ls
  7. arm-linux freertos nos nucleus ubuntu
  8. wrappers/os$ tree -A arm-linux/
  9. arm-linux/
  10. +-- HAL_AWSS_linux.c
  11. +-- HAL_Crypt_Linux.c
  12. +-- HAL_FS_Linux.c
  13. +-- HAL_KV_linux.c
  14. +-- HAL_OS_linux.c
  15. +-- HAL_TCP_linux.c
  16. +-- HAL_UDP_linux.c

打开之前被关闭的编译开关

  1. $ vim tools/board/config.arm-linux.demo
  2. CONFIG_ENV_CFLAGS = \
  3. -D_PLATFORM_IS_LINUX_ \
  4. -Wall\
  5. -DNO_EXECUTABLES
  6. CONFIG_ENV_LDFLAGS = \
  7. -lpthread -lrt
  8. OVERRIDE_CC = arm-linux-gnueabihf-gcc
  9. OVERRIDE_AR = arm-linux-gnueabihf-ar
  10. OVERRIDE_LD = arm-linux-gnueabihf-ld
  11. # CONFIG_wrappers :=

可以看到在CONFIG_wrappers :=这一行前添加了一个#符号, 代表这一行被注释掉了, wrappers将会进入编译过程

尝试交叉编译被复制的HAL层代码

  1. $ make reconfig
  2. SELECT A CONFIGURATION:
  3. 1) config.alios.mk3080
  4. 2) config.arm-linux.demo
  5. 3) config.ubuntu.x86
  6. #? 2
  7. SELECTED CONFIGURATION:
  8. VENDOR : arm-linux
  9. MODEL : demo
  10. ...
  11. $ make

可以看到我们进展的十分顺利, 被复制的代码 wrappers/os/arm-linux/*.c 直接编译成功了, 产生了 arm-linux 格式的 libiot_hal.a

交叉编译样例程序

这样有了libiot_hal.a, libiot_tls.a, 以及libiot_sdk.a, 已经可以尝试交叉编译样例的可执行程序, 并在目标嵌入式硬件开发板上运行一下试试了

方法是去掉 config.arm-linux.demo 里面的 -DNO_EXECUTABLES开关, 使得*/examples/目录下的样例源码被编译出来

注:删掉-DNO_EXECUTABLES开关时记得把上面一行-Wall后面的’\’符号也删掉

修改后的config.arm-linux.demo内容如下所示:

  1. $ vi tools/board/config.arm-linux.demo
  2. CONFIG_ENV_CFLAGS = \
  3. -D_PLATFORM_IS_LINUX_ \
  4. -Wall
  5. CONFIG_ENV_LDFLAGS = \
  6. -lpthread -lrt
  7. OVERRIDE_CC = arm-linux-gnueabihf-gcc
  8. OVERRIDE_AR = arm-linux-gnueabihf-ar
  9. OVERRIDE_LD = arm-linux-gnueabihf-ld
  10. # CONFIG_wrappers :=

可以看到在 -DNO_EXECUTABLES 开关从 CONFIG_ENV_CFLAGS 中去掉了, 例子可执行程序进入了编译范围

重新载入配置文件, 交叉编译可执行程序

  1. $ make reconfig
  2. $ make

如果有如下的编译输出, 则代表 mqtt-example 等一系列样例程序已经被成功的编译出来, 它们存放在 output/release/bin 目录下

  1. [LD] dev-sign-example <= ...
  2. [LD] mqtt-example <= ...
  3. [LD] linkkit-example-solo <= ...
  4. $ cd output/release/bin/
  5. $ ls
  6. dev-sign-example linkkit-example-solo mqtt-example
  7. $ file *
  8. dev-sign-example: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked ...
  9. linkkit-example-solo: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked ...
  10. mqtt-example: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked ...

可以用file命令验证, 这些可执行程序确实是交叉编译到 arm-linux 架构上的

尝试运行样例程序

接下来, 您就可以把样例程序例如mqtt-example, 用SCP, TFTP或者其它方式, 拷贝下载到您的目标开发板上运行调试了

  • 如果一切顺利, 样例程序和同样例程在 Ubuntu 上运行效果相同, 则证明 wrappers/os/arm-linux 部分的HAL层代码工作正常
  • 如果样例程序运行起来, 和同样例程在 Ubuntu 上运行效果不同, 则需要再重点修改调试HAL实现
  • 也就是指 wrappers/os/arm-linux 目录的HAL层代码, 因为这些代码是我们从 Ubuntu 主机部分复制的, 完全可能并不适合 arm-linux

如此反复直到确保 libiot_hal.a 的开发没问题为止