4 直接使用 SDK 工具链

可以直接将 SDK 工具链用于基于 Makefile 和 Autotools 的项目。

4 基于 Autotools 的项目

安装合适的 交叉开发工具链 后, 就可以方便地在 OpenEmbedded Build System 之外,使用 GNU Autotools 工作流开发项目。

下图展示了一个简单的 Autotools 工作流。

../_images/sdk-autotools-flow.png

按照以下步骤创建一个基于 Autotools 的简单 "Hello World" 项目:

备注

关于 GNU Autotools 工作流的更多信息,可以参考 GNOME Developer 网站上的同一示例。

  1. 创建工作目录并添加文件: 为项目创建一个空目录,并切换到该目录:

    $ 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
      
  2. 加载交叉工具链环境设置文件: 如本手册前文所述,安装交叉工具链时, 会在 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
    
  3. 创建 configure 脚本: 使用 autoreconf 命令生成 configure 脚本:

    $ autoreconf
    

    autoreconf 会负责运行其他 Autotools 工具,如 aclocal、autoconf 和 automake。

    备注

    如果 autoreconf 处理 configure.ac 时报告缺少文件, 可以使用 "-i" 选项,确保将缺少的辅助文件复制到构建主机。

  4. 交叉编译项目: 以下命令使用交叉编译器编译项目。 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
    
  5. 构建并安装项目: 以下两个命令生成项目,并将其安装到目标目录:

    $ make
    $ make install DESTDIR=./tmp
    

    备注

    关于交叉工具链环境设置脚本所设置的环境变量,以及 Makefile 如何使用或覆盖它们, 请参见 基于 Makefile 的项目。

    以下命令可以简单验证项目的安装情况。它会打印该二进制文件能够运行的架构, 此架构应与所安装的交叉工具链支持的架构相同:

    $ file ./tmp/usr/local/bin/hello
    
  6. 执行项目: 需要在目标硬件上运行项目。 如果目标硬件恰好就是构建主机,可以按以下方式运行:

    $ ./tmp/usr/local/bin/hello
    

    项目会按预期显示 "Hello World!" 消息。

4 基于 Makefile 的项目

简单的 Makefile 项目会使用交叉工具链环境设置脚本设定的环境变量, 并与这些变量交互。环境变量遵循通用的 make 规则。

本节介绍一个简单的 Makefile 开发流程,并通过示例说明如何在开发过程中使用 交叉工具链环境变量和 Makefile 变量。

../_images/sdk-makefile-flow.png

本节重点解释以下三种情况下的变量行为:

  • 情况 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!" 示例说明变量的使用:

  1. 创建工作目录并添加文件: 为项目创建一个空目录,并切换到该目录:

    $ 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");
      }
      
  2. 加载交叉工具链环境设置文件: 如本手册前文所述,安装交叉工具链时, 会在 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
    
  3. 创建 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
    
  4. 构建项目: 使用 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 中设置了什么值。

  5. 执行项目: 使用以下命令运行项目(即 target_bin):

    $ ./target_bin
    Hello World!
    

    备注

    如果使用交叉工具链编译器构建 target_bin,且构建主机与目标机器架构不同, 则需要在目标设备上运行项目。

    项目会按预期显示 "Hello World!" 消息。