4 直接使用 SDK 工具链
可以直接将 SDK 工具链用于基于 Makefile 和 Autotools 的项目。
4 基于 Autotools 的项目
安装合适的 交叉开发工具链 后, 就可以方便地在 OpenEmbedded Build System 之外,使用 GNU Autotools 工作流开发项目。
下图展示了一个简单的 Autotools 工作流。
按照以下步骤创建一个基于 Autotools 的简单 "Hello World" 项目:
备注
关于 GNU Autotools 工作流的更多信息,可以参考 GNOME Developer 网站上的同一示例。
创建工作目录并添加文件: 为项目创建一个空目录,并切换到该目录:
$ mkdir $HOME/helloworld $ cd $HOME/helloworld
目录准备好后,添加工作流需要的文件:项目源文件、辅助配置文件、 辅助生成 Makefile 的文件,以及 README 文件,分别为
hello.c、configure.ac、Makefile.am和README。使用以下命令创建 GNU 编码标准要求的空 README 文件:
$ touch README
按以下内容创建其余三个文件:
hello.c:#include <stdio.h> int main() { printf("Hello World!\n"); return 0; }
configure.ac:AC_INIT(hello,0.1) AM_INIT_AUTOMAKE([foreign]) AC_PROG_CC AC_CONFIG_FILES(Makefile) AC_OUTPUT
Makefile.am:bin_PROGRAMS = hello hello_SOURCES = hello.c
加载交叉工具链环境设置文件: 如本手册前文所述,安装交叉工具链时, 会在 SDK 安装目录中创建一个交叉工具链环境设置脚本。 使用工具开发项目之前,必须先用 source 加载该脚本。 脚本名称以 "environment-setup" 开头,包含机器架构,之后是 "poky-linux"。 本例从 SDK 的默认安装目录加载脚本,使用 32 位 Intel x86 架构及 Yocto 项目 6.1 版本:
$ source /opt/poky/6.1/environment-setup-i586-poky-linux
也可以直接在 Yocto 构建中加载环境设置,例如:
$ source tmp/deploy/images/qemux86-64/environment-setup-core2-64-poky-linux
创建 configure 脚本: 使用
autoreconf命令生成configure脚本:$ autoreconfautoreconf会负责运行其他 Autotools 工具,如aclocal、autoconf和automake。备注
如果
autoreconf处理configure.ac时报告缺少文件, 可以使用 "-i" 选项,确保将缺少的辅助文件复制到构建主机。交叉编译项目: 以下命令使用交叉编译器编译项目。 CONFIGURE_FLAGS 环境变量为 GNU configure 提供最基本的参数:
$ ./configure ${CONFIGURE_FLAGS}
对于基于 Autotools 的项目,只需向
configure.sh传入适当的 host 选项, 就能使用交叉工具链。host 选项的值可以从工具链安装目录中的环境设置脚本名称推导。 例如,使用 GNU EABI 的 ARM 目标对应的值是armv5te-poky-linux-gnueabi, 脚本名称为environment-setup-armv5te-poky-linux-gnueabi。 因此,以下命令可以更新项目,并使用相应的交叉工具链工具重新构建:$ ./configure --host=armv5te-poky-linux-gnueabi --with-libtool-sysroot=sysroot_dir
构建并安装项目: 以下两个命令生成项目,并将其安装到目标目录:
$ make $ make install DESTDIR=./tmp
备注
关于交叉工具链环境设置脚本所设置的环境变量,以及 Makefile 如何使用或覆盖它们, 请参见 基于 Makefile 的项目。
以下命令可以简单验证项目的安装情况。它会打印该二进制文件能够运行的架构, 此架构应与所安装的交叉工具链支持的架构相同:
$ file ./tmp/usr/local/bin/hello
执行项目: 需要在目标硬件上运行项目。 如果目标硬件恰好就是构建主机,可以按以下方式运行:
$ ./tmp/usr/local/bin/hello项目会按预期显示 "Hello World!" 消息。
4 基于 Makefile 的项目
简单的 Makefile 项目会使用交叉工具链环境设置脚本设定的环境变量,
并与这些变量交互。环境变量遵循通用的 make 规则。
本节介绍一个简单的 Makefile 开发流程,并通过示例说明如何在开发过程中使用 交叉工具链环境变量和 Makefile 变量。
本节重点解释以下三种情况下的变量行为:
情况 1:Makefile 未设置与 SDK 设置脚本中环境变量同名的变量。 由于
Makefile没有显式设置对应变量,变量保留环境设置脚本赋予的值。情况 2:Makefile 设置了与 SDK 设置脚本中环境变量同名的变量。 构建时,
Makefile中显式设置的变量会覆盖环境中的设置。 此时使用Makefile中的值。情况 3:命令行设置了与 SDK 设置脚本中环境变量同名的变量。 从命令行执行
Makefile时,这些设置会覆盖环境变量。 此时使用命令行给出的值。
备注
无论如何设置变量,如果为 make 使用 "-e" 选项,
SDK 设置脚本提供的变量都会优先:
$ make -e target
本节其余部分通过一个简单的 Makefile 示例演示这些行为。
在新的 shell 环境中,运行设置脚本之前尚未设置 SDK 环境变量。 例如,以下命令显示编译器变量(即 CC)的值为空:
$ echo ${CC}
$
对于当前 Yocto 项目 6.1 版本的 core-image-sato 镜像,
运行面向 64 位构建主机及 i586 调优目标架构的 SDK 设置脚本后,
再次输出该变量即可看到脚本设定的值:
$ source /opt/poky/6.1/environment-setup-i586-poky-linux
$ echo ${CC}
i586-poky-linux-gcc -m32 -march=i586 --sysroot=/opt/poky/6.1/sysroots/i586-poky-linux
下面通过简单的 "Hello World!" 示例说明变量的使用:
创建工作目录并添加文件: 为项目创建一个空目录,并切换到该目录:
$ mkdir $HOME/helloworld $ cd $HOME/helloworld
目录准备好后,添加工作流需要的文件:调用函数的
main.c、 包含头文件内容的module.h,以及定义函数的module.c。按以下内容创建这三个文件:
main.c:#include "module.h" void sample_func(); int main() { sample_func(); return 0; }
module.h:#include <stdio.h> void sample_func();
module.c:#include "module.h" void sample_func() { printf("Hello World!"); printf("\n"); }
加载交叉工具链环境设置文件: 如本手册前文所述,安装交叉工具链时, 会在 SDK 安装目录中创建交叉工具链环境设置脚本。 使用工具开发项目之前,必须先用 source 加载它。 脚本名称以 "environment-setup" 开头,包含机器架构,之后是 "poky-linux"。 本例从 SDK 的默认安装目录加载脚本,使用 32 位 Intel x86 架构和 Yocto 项目 Blacksail 版本:
$ source /opt/poky/6.1/environment-setup-i586-poky-linux
也可以直接在 Yocto 构建中加载环境设置,例如:
$ source tmp/deploy/images/qemux86-64/environment-setup-core2-64-poky-linux
创建 Makefile: 本例的 Makefile 中有两行可以设置 CC。 一行与 SDK 环境设置脚本设置的值完全相同,另一行将 CC 设为 "gcc", 即构建主机上默认的 GNU 编译器:
# CC=i586-poky-linux-gcc -m32 -march=i586 --sysroot=/opt/poky/2.5/sysroots/i586-poky-linux # CC="gcc" all: main.o module.o ${CC} main.o module.o -o target_bin main.o: main.c module.h ${CC} -I . -c main.c module.o: module.c module.h ${CC} -I . -c module.c clean: rm -rf *.o rm target_bin
构建项目: 使用
make命令创建二进制输出文件。 由于 Makefile 中的变量设置已被注释,CC 采用 SDK 环境设置文件运行时设置的值:$ make i586-poky-linux-gcc -m32 -march=i586 --sysroot=/opt/poky/2.5/sysroots/i586-poky-linux -I . -c main.c i586-poky-linux-gcc -m32 -march=i586 --sysroot=/opt/poky/2.5/sysroots/i586-poky-linux -I . -c module.c i586-poky-linux-gcc -m32 -march=i586 --sysroot=/opt/poky/2.5/sysroots/i586-poky-linux main.o module.o -o target_bin
从上述命令结果可以看到,所使用的编译器由设置脚本定义的 CC 变量指定。
取消 Makefile 中对应行的注释,再次运行
make, 即可使用 Makefile 中的同名变量覆盖 CC 环境变量:$ make clean rm -rf *.o rm target_bin # # Edit the Makefile by uncommenting the line that sets CC to "gcc" # $ make gcc -I . -c main.c gcc -I . -c module.c gcc main.o module.o -o target_bin
如上例所示,此时使用的是默认编译器,而不是交叉工具链编译器。
接下来演示通过命令行提供变量来覆盖其值。 先在 Makefile 中恢复注释字符,使直接运行
make时使用已配置的 SDK 编译器。 然后运行make,通过命令行参数将 CC 设为 "gcc":$ make clean rm -rf *.o rm target_bin # # Edit the Makefile to comment out the line setting CC to "gcc" # $ make i586-poky-linux-gcc -m32 -march=i586 --sysroot=/opt/poky/2.5/sysroots/i586-poky-linux -I . -c main.c i586-poky-linux-gcc -m32 -march=i586 --sysroot=/opt/poky/2.5/sysroots/i586-poky-linux -I . -c module.c i586-poky-linux-gcc -m32 -march=i586 --sysroot=/opt/poky/2.5/sysroots/i586-poky-linux main.o module.o -o target_bin $ make clean rm -rf *.o rm target_bin $ make CC="gcc" gcc -I . -c main.c gcc -I . -c module.c gcc main.o module.o -o target_bin
在这种情况下,命令行参数覆盖了 SDK 环境变量。
最后,再次编辑 Makefile,使其使用 "gcc" 编译器,但在
make命令行中加入 "-e":$ make clean rm -rf *.o rm target_bin # # Edit the Makefile to use "gcc" # $ make gcc -I . -c main.c gcc -I . -c module.c gcc main.o module.o -o target_bin $ make clean rm -rf *.o rm target_bin $ make -e i586-poky-linux-gcc -m32 -march=i586 --sysroot=/opt/poky/2.5/sysroots/i586-poky-linux -I . -c main.c i586-poky-linux-gcc -m32 -march=i586 --sysroot=/opt/poky/2.5/sysroots/i586-poky-linux -I . -c module.c i586-poky-linux-gcc -m32 -march=i586 --sysroot=/opt/poky/2.5/sysroots/i586-poky-linux main.o module.o -o target_bin
此时,"-e" 选项强制
make使用 SDK 环境变量,无论 Makefile 中设置了什么值。执行项目: 使用以下命令运行项目(即
target_bin):$ ./target_bin Hello World!
备注
如果使用交叉工具链编译器构建 target_bin,且构建主机与目标机器架构不同, 则需要在目标设备上运行项目。
项目会按预期显示 "Hello World!" 消息。