交叉编译

更新时间:2018-10-24 20:54:46

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

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

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

  • src/board/目录下添加一个对应的配置文件, 文件名规范为config.XXX.YYY, 其中XXX部分就对应后面src/ref-impl/hal/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

安装交叉编译工具链

$ sudo apt-get install -y gcc-arm-linux-gnueabihf
$ arm-linux-gnueabihf-gcc --version

arm-linux-gnueabihf-gcc (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

添加配置文件

$ touch src/board/config.arm-linux.demo
$ ls src/board/
config.arm-linux.demo  config.macos.make  config.rhino.make  config.ubuntu.x86  config.win7.mingw32

编辑配置文件

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

$ vim src/board/config.arm-linux.demo

CONFIG_ENV_CFLAGS = \
    -D_PLATFORM_IS_LINUX_ \
    -Wall

OVERRIDE_CC = arm-linux-gnueabihf-gcc
OVERRIDE_AR = arm-linux-gnueabihf-ar
OVERRIDE_LD = arm-linux-gnueabihf-ld

CONFIG_src/ref-impl/hal         :=
CONFIG_examples                 :=
CONFIG_tests                    :=
CONFIG_src/tools/linkkit_tsl_convert :=

注意, 上面的最后4行表示跳过对src/ref-impl/hal, examples, tests, src/tools/linkkit_tsl_convert这些目录的编译。在编译未被适配平台的库时在最初是必要的, 这样可以避免产生过多的错误

选择配置文件

$ make reconfig
SELECT A CONFIGURATION:

1) config.arm-linux.demo  3) config.rhino.make      5) config.win7.mingw32
2) config.macos.make      4) config.ubuntu.x86
#? 1

SELECTED CONFIGURATION:

VENDOR :   arm-linux
MODEL  :   demo

CONFIGURE .............................. [examples]
CONFIGURE .............................. [src/infra/log]
CONFIGURE .............................. [src/infra/system]
CONFIGURE .............................. [src/infra/utils]
CONFIGURE .............................. [src/protocol/alcs]
CONFIGURE .............................. [src/protocol/coap]
CONFIGURE .............................. [src/protocol/http]
CONFIGURE .............................. [src/protocol/http2]
CONFIGURE .............................. [src/protocol/mqtt]
CONFIGURE .............................. [src/ref-impl/hal]
CONFIGURE .............................. [src/ref-impl/tls]
CONFIGURE .............................. [src/sdk-impl]
CONFIGURE .............................. [src/services/file_upload]
CONFIGURE .............................. [src/services/linkkit/cm]
CONFIGURE .............................. [src/services/linkkit/dm]
CONFIGURE .............................. [src/services/shadow]
CONFIGURE .............................. [src/services/subdev]
CONFIGURE .............................. [src/services/ota]
CONFIGURE .............................. [src/tools/linkkit_tsl_convert]
CONFIGURE .............................. [tests]

BUILDING WITH EXISTING CONFIGURATION:

VENDOR :   arm-linux
MODEL  :   demo

Components:

. tests
. src/services/file_upload
. src/services/subdev
. src/services/ota
. src/services/shadow
. src/services/linkkit/dm
. src/services/linkkit/cm
. src/sdk-impl
. src/protocol/mqtt
. src/protocol/coap
. src/protocol/http2
. src/protocol/alcs
. src/protocol/http
. src/tools/linkkit_tsl_convert
. src/ref-impl/tls
. src/ref-impl/hal
. src/infra/log
. src/infra/system
. src/infra/utils
. examples

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

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

$ make
BUILDING WITH EXISTING CONFIGURATION:

VENDOR :   arm-linux
MODEL  :   demo

[CC] guider.o                           <=  ...
[CC] utils_epoch_time.o                 <=  ...
[CC] iotx_log.o                         <=  ...
[CC] lite_queue.o                       <=  ...
...
...
[AR] libiot_sdk.a                       <=  ...
[AR] libiot_tls.a                       <=  ...

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

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

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

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

$ ls -1 output/release/include/
exports
imports
iot_export.h
iot_import.h

这里, iot_import.hiot_export.h就是使用SDK需要包含的头文件, 它们按功能点又包含不同的子文件, 分别列在imports/目录下和exports/目录下

开发未适配平台的HAL层

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

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


仍然以上一节中, 某款目前未适配的arm-linux目标平台为例, 假设这款平台和Ubuntu差别很小, 完全可以用Ubuntu上开发测试的HAL层代码作为开发的基础, 则可以这样做:

复制一份HAL层实现代码

注:在 src/ref-impl/hal/os 下需要创建一个与 src/board/confg.XXX.YYY 中的 XXX 一样的目录用于存放HAL实现。

$ cd src/ref-impl/hal/os/
$ ls
macos  ubuntu  win7
src/ref-impl/hal/os$ cp -rf ubuntu arm-linux
src/ref-impl/hal/os$ ls
arm-linux  macos  ubuntu  win7

src/ref-impl/hal/os$ tree -A arm-linux/
arm-linux/

+-- base64.c

+-- base64.h

+-- cJSON.c

+-- cJSON.h

+-- HAL_Crypt_Linux.c

+-- HAL_OS_linux.c

+-- HAL_TCP_linux.c

+-- HAL_UDP_linux.c

+-- kv.c

+-- kv.h

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

$ vim src/board/config.arm-linux.demo

CONFIG_ENV_CFLAGS = \
    -D_PLATFORM_IS_LINUX_ \
    -Wall

OVERRIDE_CC = arm-linux-gnueabihf-gcc
OVERRIDE_AR = arm-linux-gnueabihf-ar
OVERRIDE_LD = arm-linux-gnueabihf-ld

# CONFIG_src/ref-impl/hal         :=
CONFIG_examples                 :=
CONFIG_tests                    :=
CONFIG_src/tools/linkkit_tsl_convert :=

可以看到在CONFIG_src/ref-impl/hal :=这一行前添加了一个#符号, 代表这一行被注释掉了, 效果等同于被删掉, src/ref-impl/hal将会进入编译过程

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

$ make reconfig
SELECT A CONFIGURATION:

1) config.arm-linux.demo  3) config.rhino.make      5) config.win7.mingw32
2) config.macos.make      4) config.ubuntu.x86
#? 1

SELECTED CONFIGURATION:

VENDOR :   arm-linux
MODEL  :   demo
...
...

$ make
[CC] utils_md5.o                        <=  ...
[CC] utils_event.o                      <=  ...
[CC] string_utils.o                     <=  ...
...
...
[AR] libiot_sdk.a                       <=  ...
[AR] libiot_hal.a                       <=  ...
[AR] libiot_tls.a                       <=  ...

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

允许交叉编译样例程序

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

方法和上一步一样, 打开config.arm-linux.demo里面的CONFIG_example开关, 使得examples/目录下的样例源码被编译出来

$ vi src/board/config.arm-linux.demo

CONFIG_ENV_CFLAGS = \
    -D_PLATFORM_IS_LINUX_ \
    -Wall

CONFIG_ENV_LDFLAGS = \
    -lpthread -lrt

OVERRIDE_CC = arm-linux-gnueabihf-gcc
OVERRIDE_AR = arm-linux-gnueabihf-ar
OVERRIDE_LD = arm-linux-gnueabihf-ld

# CONFIG_src/ref-impl/hal         :=
# CONFIG_examples                 :=
CONFIG_tests                    :=
CONFIG_src/tools/linkkit_tsl_convert :=

可以看到在CONFIG_examples =这一行前添加了一个#符号, 代表这一行被注释掉了, 效果等同于被删掉, examples/ 目录也就是例子可执行程序进入了编译范围

另外一点需要注意的改动是增加了:

CONFIG_ENV_LDFLAGS = \
    -lpthread -lrt

部分, 这是因为产生这些样例程序除了链接libiot_hal.alibiot_hal.a之外, 还需要连接 libpthread 库和 librt

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

$ make reconfig
SELECT A CONFIGURATION:

1) config.arm-linux.demo  3) config.rhino.make      5) config.win7.mingw32
2) config.macos.make      4) config.ubuntu.x86
#? 1

SELECTED CONFIGURATION:

VENDOR :   arm-linux
MODEL  :   demo
...

需要注意, 编译样例程序, 需要用:

make all

命令, 而不再是上面的

make

命令来产生编译产物, 比如:

$ make all
BUILDING WITH EXISTING CONFIGURATION:

VENDOR :   arm-linux
MODEL  :   demo

[CC] base64.o                           <= base64.c
[CC] cJSON.o                            <= cJSON.c
[CC] HAL_UDP_linux.o                    <= HAL_UDP_linux.c
...
...

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

[LD] mqtt_rrpc-example                  <= mqtt_rrpc-example.o
[LD] uota_app-example                   <= uota_app-example.o
[LD] http-example                       <= http-example.o
[LD] mqtt-example                       <= mqtt-example.o
[LD] mqtt_multi_thread-example          <= mqtt_multi_thread-example.o
[LD] ota_mqtt-example                   <= ota_mqtt-example.o
[LD] linkkit-example-sched              <= linkkit_example_sched.o
[LD] linkkit-example-solo               <= linkkit_example_solo.o

$ cd output/release/bin/
$ ls
http-example  linkkit-example-sched  linkkit-example-solo  mqtt-example  mqtt_multi_thread-example  mqtt_rrpc-example  ota_mqtt-example  uota_app-example

$ file *
http-example:              ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, ...
linkkit-example-sched:     ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, ...
linkkit-example-solo:      ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, ...
mqtt-example:              ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, ...
mqtt_multi_thread-example: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, ...
mqtt_rrpc-example:         ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, ...
ota_mqtt-example:          ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, ...
uota_app-example:          ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, ...

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

尝试运行样例程序

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

  • 如果一切顺利, 样例程序和同样例程在 Ubuntu 上运行效果相同, 则证明 src/ref-impl/hal/os/arm-linux 部分的HAL层代码工作正常

  • 如果样例程序运行起来, 和同样例程在 Ubuntu 上运行效果不同, 则需要再重点修改调试HAL实现

  • 也就是指 src/ref-impl/hal/os/arm-linux 目录的HAL层代码, 因为这些代码是我们从 Ubuntu 主机部分复制的, 完全可能并不适合 arm-linux

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

results matching ""

    No results matching ""