从源码构建 SOF 工具链和 SOF

  • 第 1 步. 建立工作空间目录
  • 第 2 步. 建立构建环境
    • 安装依赖包
    • 安装 CMake
    • 从源码构建 alsa-lib 和 alsa-utils
  • 第 3 步. 从源码构建工具链
    • crosstool-ng
    • 工具链
    • 附加的头文件
  • 第 4 步. 构建并签名固件二进制文件
    • 重新配置并从头构建
    • 增量构建
    • 固件构建输出
  • 第 5 步. 构建拓扑和工具
    • 从头开始一步重新构建
    • 增量构建
    • 拓扑和工具构建结果
  • 第 6 步. 构建 Linux 内核

你可以在目标机器或 VM 上启动并测试 Sound Open Firmware。当前支持的目标 Intel 平台包括:Bay Trail,Cherry Trail,Haswell,Broadwell,Apollo Lake,Cannon Lake,Ice Lake,Jasper Lake,和 Tiger Lake。

SOF 也支持 NXP i.MX8/i.MX8X/i.MX8M 平台。

下面的步骤描述了如何在 Ubuntu 16.04,18.04,18.10,和 20.04,及 Fedora 36 上安装 SOF 开发环境。这些步骤应该只需要少量修改或不需要修改,即可用在 Ubuntu 19.04,19.10 和其它 Linux 发行版上。

注意

从源码构建工具链可能需要花费几个小时。我们建议你使用 Docker 构建 SOF。更多信息,请参考 用 Docker 构建 SOF

第 1 步. 建立工作空间目录

设置环境变量 $SOF_WORKSPACE 指向保存所有 SOF 相关工作的目录。

下面的代码示例假设 $SOF_WORKSPACE 是最顶层的工作目录。需要在相同的目录层级克隆所有的 git 仓库,因为一些默认的配置文件使用 ../sof/ 这样的相对位置引用其它仓库。

请确保 $SOF_WORKSPACE 目录在构建工具链时,具有充足的磁盘空间。每个工具链大概需要 15GB 的磁盘空间。工具链构建完成后,你可以回收一些磁盘空间。

SOF_WORKSPACE=$HOME/data/work_sof
mkdir -p "$SOF_WORKSPACE"

第 2 步. 建立构建环境

安装依赖包

注意

这份指南使用了 Ubuntu/Fedora 作为示例,但任何现代的 Linux 发行版都可以用于 SOF 开发。

由于 Linux 发行版中持续的更新默认包含的软件包,对于一些可能缺失的工具和软件包,SOF 文档中可能没有包含明确的说明。遇到这种缺失的依赖时,你可以参考你的 Linux 发行版的文档来了解如何安装它们。

  • Fedora (在 v36 版上做了测试,近期的其它版本应该也可以很好的工作):
sudo dnf group install "Development Tools" "C Development Tools and Libraries"
sudo dnf install ncurses-devel gtk3-devel gettext-devel texinfo help2man \
  glibc-static libstdc++-static openssl-devel tree
  • Ubuntu 20.04:
sudo apt install build-essential git autoconf flex bison texinfo help2man \
   gawk libtool-bin libncurses5 libncurses5-dev libssl-dev libgtk-3-dev \
        tree ninja-build gettext libasound2-dev
  • Ubuntu 18.10:
sudo apt-get install build-essential git libgtk-3-dev libsdl1.2-dev \
   libspice-protocol-dev libspice-server-dev libusb-1.0-0-dev \
   libusbredirhost-dev libtool-bin acpica-tools valgrind texinfo \
   virt-manager qemu-kvm libvirt-daemon-system libvirt-clients virtinst \
   libfdt-dev libssl-dev pkg-config help2man gawk libncurses5 \
   libncurses5-dev
  • Ubuntu 16.04 和 18.04:
sudo apt-get install build-essential git libgtk-3-dev libsdl1.2-dev \
   libspice-protocol-dev libspice-server-dev libusb-1.0-0-dev \
   libusbredirhost-dev libtool-bin iasl valgrind texinfo virt-manager \
   qemu-kvm libvirt-bin virtinst libfdt-dev libssl-dev pkg-config help2man \
   gawk libncurses5 libncurses5-dev

如果你正在使用 Ubuntu 16.04,则必须将 gcc 的版本更新到 gcc 7.3+,以便于构建 Advanced Linux Sound Architecture (ALSA)。

sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install gcc-7 g++-7
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 70 --slave /usr/bin/g++ g++ /usr/bin/g++-7

安装 CMake

如果你在使用 Ubuntu 18.04+ 或 Fedora,你可以使用 apt/dnf 安装 CMake,Ubuntu:

sudo apt-get install cmake

Fedora:

sudo dnf install cmake

对于 Ubuntu 16.04 等系统,apt 中的 CMake 版本已经太老了,必须从源码等方式安装 CMake。可以参考这份指南:https://cmake.org/install/。如果要从二进制安装包安装 CMake,首先在 https://cmake.org/download/ 下载对应操作系统和 CPU 架构的二进制安装包,如 x86-64 CPU 架构,Linux 操作系统,3.28.0 版的 CMake,cmake-3.28.0-linux-x86_64.sh,然后执行这个脚本安装:

$ wget https://github.com/Kitware/CMake/releases/download/v3.28.0/cmake-3.28.0-linux-x86_64.sh
$ chmod a+x cmake-3.28.0-linux-x86_64.sh
$ ./cmake-3.28.0-linux-x86_64.sh --help
Usage: ./cmake-3.28.0-linux-x86_64.sh [options]
Options: [defaults in brackets after descriptions]
  --help            print this message
  --version         print cmake installer version
  --prefix=dir      directory in which to install
  --include-subdir  include the cmake-3.28.0-linux-x86_64 subdirectory
  --exclude-subdir  exclude the cmake-3.28.0-linux-x86_64 subdirectory
  --skip-license    accept license
$ ./cmake-3.28.0-linux-x86_64.sh --prefix=$HOME/.local

从源码构建 alsa-lib 和 alsa-utils

这个项目需要 https://git.alsa-project.org/?p=alsa-lib.githttps://git.alsa-project.org/?p=alsa-utils.git 的一些新特性,因此需要从源码构建最新的 ALSA。

警告

在系统范围内安装 alsa-lib 可能会破坏一些音频应用。仅在你知道你在做什么时才这样做。我们建议你在本地目录 ($HOME 目录下) 安装或使用 Docker (请参考 用 Docker 构建 SOF)。

cd "$SOF_WORKSPACE"
git clone git://git.alsa-project.org/alsa-lib
cd alsa-lib
# To install alsa-lib locally
./gitcompile --prefix=$HOME/.local
make install

如果要在系统范围内安装 alsa-lib,则把上面执行的 ./gitcompile --prefix=$HOME/.local 命令替换为 ./gitcompile,同时在执行 make install 前加上 sudo,以便获得根文件系统的写权限:

# To install alsa-lib systemwide
./gitcompile
sudo make install

(可选的) 如果要启用 alsabat 的频率分析,则在配置 alsa-utils 之前安装 FFT 库,Ubuntu:

sudo apt-get install libfftw3-dev libfftw3-doc

Fedora:

sudo dnf install fftw3-devel

克隆,构建,并安装 alsa-utils。

cd "$SOF_WORKSPACE"
git clone git://git.alsa-project.org/alsa-utils
cd alsa-utils
# To install alsa-utils locally
./gitcompile --prefix=$HOME/.local \
             --with-alsa-inc-prefix=$HOME/.local/include \
             --with-alsa-prefix=$HOME/.local/lib \
             --with-systemdsystemunitdir=$HOME/.local/lib/systemd \
             --with-udev-rules-dir=$HOME/.local/lib/udev
make install

如果要在系统范围内安装 alsa-utils,则把上面执行的 ./gitcompile --prefix=$HOME/.local . . . 命令替换为 ./gitcompile,同时在执行 make install 前加上 sudo 以便获得根文件系统的写权限:

# To install alsa-lib systemwide
./gitcompile
sudo make install

如果你遇到了 alsa-lib 的链接错误,则可以加个 libdir 参数重新构建它。

cd ../alsa-lib
./gitcompile --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu/
sudo make install
cd ../alsa-utils
./gitcompile --prefix=/usr --with-curses=ncurses --disable-xmlto --disable-bat
sudo make install

注意

如果 gitcompile 脚本不工作,则可以参考 INSTALL 文件手动构建。

创建或给 LD_LIBRARY_PATH 环境变量附加内容。

export LD_LIBRARY_PATH=$HOME/.local/lib:$LD_LIBRARY_PATH

第 3 步. 从源码构建工具链

通过 crosstool-ng 为 Intel Bay Trail,Cherry Trail,Haswell,Broadwell,Apollo Lake,Cannon Lake,Ice Lake,Jasper Lake,Tiger Lake 平台和 NXP i.MX8/i.MX8X/i.MX8M 平台构建 xtensa 交叉编译工具链。构建工具链可能需要大约一个小时,但只需要执行一次,且它不需要依赖 Docker 镜像。

更多信息请参考 https://crosstool-ng.github.io/

crosstool-ng

克隆这些 git 仓库,并分别切换到 sof-gcc10.2sof-gcc10x 分支。

cd "$SOF_WORKSPACE"
git clone https://github.com/thesofproject/xtensa-overlay
git clone https://github.com/thesofproject/crosstool-ng
git -C xtensa-overlay/ checkout  sof-gcc10.2
git -C crosstool-ng/   checkout  sof-gcc10x

构建 crosstool-ng 并把它安装到它自己的源码目录。

cd crosstool-ng/
./bootstrap
./configure --prefix=$(pwd)
make
make install

工具链

crosstool-ng 根目录下有许多配置文件,如:

crosstool-ng$ ls config-*gcc10.2*
config-acp_6_3-gcc10.2-gdb9  config-imx8m-gcc10.2-gdb9     config-mt8195-gcc10.2-gdb9
config-apl-gcc10.2-gdb8.3    config-imx8ulp-gcc10.2-gdb9   config-rmb-gcc10.2-gdb9
config-apl-gcc10.2-gdb9      config-imx-gcc10.2-gdb9       config-rn-gcc10.2-gdb9
config-byt-gcc10.2-gdb9      config-lx7hifi4-gcc10.2-gdb9  config-vangogh-gcc10.2-gdb9
config-cnl-gcc10.2-gdb9      config-mt8186-gcc10.2-gdb9
config-hsw-gcc10.2-gdb9      config-mt8188-gcc10.2-gdb9

这些配置文件中的每一个都引用 ../xtensa-overlay/ 下的文件,并指向不同的 ./builds/xtensa-*-elf 子目录。将想要构建的目标平台的配置文件拷贝到 .config,并为目标平台构建交叉编译器。注意,./ct-ng build 需要网络连接来下载 gcc 组件。其它步骤最多需要几分钟,依赖于你的网络连接和系统性能,构建所有的工具链可能需要大约一个小时。

通过如下脚本为部分目标平台构建工具链:

#!/usr/bin/bash

unset LD_LIBRARY_PATH

# byt = Bay Trail / Cherry Trail
# hsw = Haswell/Broadwell
# apl = Apollo Lake
# cnl = Cannon Lake, Ice Lake, Jasper Lake, and Tiger Lake
# imx = i.MX8/i.MX8X
# imx8m = i.MX8M

SOF_WORKSPACE=$HOME/data/work_sof
cd "${SOF_WORKSPACE}"/crosstool-ng

# Omit the toolchains you don't want to save (a lot of) time
time for i in byt hsw apl cnl imx imx8m; do
  cp config-$i-gcc10.2-gdb9 .config &&
     time ./ct-ng build || break
done

具体的目标平台在 for 语句中指定。替换上面的 for 语句构建所有的工具链:

# ... or just build all toolchains
time for i in config*gcc10.2-gdb9; do
   cp "$i" .config && time ./ct-ng build || break
done

./ct-ng 是一个 Linux 内核风格的 Makefile;因此下面的示例命令可用于修复一些过时的 config-*-gcc10.2-gdb9 文件,或者从中寻找缺失的默认值:

./ct-ng help
cp config-apl-gcc10.2-gdb9 .config
./ct-ng oldconfig V=1
diff -u config-apl-gcc10.2-gdb9 .config

./ct-ng 命令在执行之前,需要先 unset 环境变量 LD_LIBRARY_PATH,否则报如下错误:

~/data/work_sof/crosstool-ng$ ./ct-ng build 
[INFO ]  Performing some trivial sanity checks
[ERROR]  Don't set LD_LIBRARY_PATH. It screws up the build.
[ERROR]   
[ERROR]  >>
[ERROR]  >>  Build failed in step '(top-level)'
[ERROR]  >>
[ERROR]  >>  Error happened in: CT_Abort[scripts/functions@487]
[ERROR]  >>        called from: CT_TestAndAbort[scripts/functions@507]
[ERROR]  >>        called from: main[scripts/crosstool-NG.sh@58]
[ERROR]  >>
[ERROR]  >>  For more info on this error, look at the file: 'build.log'
[ERROR]  >>  There is a list of known issues, some with workarounds, in:
[ERROR]  >>      https://crosstool-ng.github.io/docs/known-issues/
[ERROR]  >>
[ERROR]  >> NOTE: Your configuration includes features marked EXPERIMENTAL.
[ERROR]  >> Before submitting a bug report, try to reproduce it without enabling
[ERROR]  >> any experimental features. Otherwise, you'll need to debug it
[ERROR]  >> and present an explanation why it is a bug in crosstool-NG - or
[ERROR]  >> preferably, a fix.
[ERROR]  >>
[ERROR]  >> NOTE: You configuration uses non-default patch sets. Please
[ERROR]  >> select 'bundled' as the set of patches applied and attempt
[ERROR]  >> to reproduce this issue. Issues reported with other patch
[ERROR]  >> set selections (none, local, bundled+local) are going to be
[ERROR]  >> closed without explanation.
[ERROR]  >>
[ERROR]  >>  If you feel this is a bug in crosstool-NG, report it at:
[ERROR]  >>      https://github.com/crosstool-ng/crosstool-ng/issues/
[ERROR]  >>
[ERROR]  >>  Make sure your report includes all the information pertinent to this issue.
[ERROR]  >>  Read the bug reporting guidelines here:
[ERROR]  >>      http://crosstool-ng.github.io/support/
[ERROR]   
[ERROR]  (elapsed: 28505387:07.64)
[00:00] / make: *** [ct-ng:261:build] 错误 1

$SOF_WORKSPACE 中创建各个工具链的符号链接,以在期望的位置安装它们:

ls builds/
# xtensa-apl-elf  xtensa-byt-elf   xtensa-cnl-elf   xtensa-hsw-elf  xtensa-imx-elf  xtensa-imx8m-elf
cd "$SOF_WORKSPACE"
for i in crosstool-ng/builds/xtensa-*; do ln -s "$i"; done

移除临时的构建文件 (每个工具链大约 7GB):

rm -rf $SOF_WORKSPACE/crosstool-ng/.build

注意

Haswell 和 Broadwell 使用相同的工具链:xtensa-hsw-elf

Bay Trail 和 Cherry Trail 使用相同的工具链:xtensa-byt-elf

Cannon Lake,Ice Lake,Jasper Lake 和 Tiger Lake 使用相同的工具链:xtensa-cnl-elf

i.MX8 和 i.MX8X 使用相同的工具链:xtensa-imx-elf

附加的头文件

为了获得一些必须的头文件,克隆如下的 newlib 仓库,并切换到 xtensa 分支:

cd "$SOF_WORKSPACE"
git clone https://github.com/jcmvbkbc/newlib-xtensa
cd newlib-xtensa
git checkout -b xtensa origin/xtensa

newlib 是 SOF 使用的标准 C 库实现。临时地将工具链的路径添加进 PATH 环境变量。当使用下一节描述的高级的 “每日” 构建脚本时,这不是必须的。只有在一次性地构建 newlib 库,或手动调用 CMake 时是必须的。换句话说,你不需要永久性地修改你的 PATH 环境变量,这会干扰到其它的,非 SOF 的工作。

for i in "${SOF_WORKSPACE}"/xtensa-*-elf; do PATH="$PATH:$i"/bin; done

为每个工具链构建并安装 newlib 库:

#!/usr/bin/bash

SOF_WORKSPACE=$HOME/data/work_sof
XTENSA_ROOT="${SOF_WORKSPACE}"/xtensa-root
cd "${SOF_WORKSPACE}"/newlib-xtensa
time for toolchain in ../xtensa-*-elf; do
  ./configure --target="${toolchain#../}" --prefix="$XTENSA_ROOT" &&
  make && make install || break;
  rm etc/config.cache
done
ls "$XTENSA_ROOT"

可以看到:

share           xtensa-byt-elf  xtensa-hsw-elf    xtensa-imx-elf
xtensa-apl-elf  xtensa-cnl-elf  xtensa-imx8m-elf

这应该会花费几分钟。

注意

--prefix= 的值为一个绝对路径。根据你的环境变量定义 XTENSA_ROOT

必须的头文件现在位于 "$SOF_WORKSPACE"/xtensa-root,至此 xtensa DSP 的交叉编译工具链搭建完毕。

第 4 步. 构建并签名固件二进制文件

SOF 环境搭建完成之后,克隆 sof 仓库:

cd "$SOF_WORKSPACE"
git clone --recursive https://github.com/thesofproject/sof
cd sof

将示例配置文件 installer/sample-config.mk 拷贝到 installer/config.mk,然后选择一个平台列表,并在后面的文件中提供一个可选的目标主机名。运行安装程序:

make -C installer/ [ -j 4 ]

installer/config.mk 配置文件看起来像下面这样:

# To customize the installation, copy this file to config.mk and edit
# it. Leave undefined to use default values.

# As usual with Make, all these can also be passed as either CLI
# arguments or environment variables.  Warning: undefined is NOT the
# same as blank!

# You MUST "make cleanall" after changing anything here

# Everything is installed by default. To install and deploy fewer
# patforms override the default lists like this:
# UNSIGNED_list :=
SIGNED_list := imx8 imx8m

# The default FW_DESTDIR is the local /lib/firmware/intel directory
# _remote := test-system.local
# FW_DESTDIR     := root@${_remote}:/lib/firmware/intel
# USER_DESTDIR   := ${_remote}:bin/

# Passed to ./scripts/xtensa-build-all.sh -i
# Ignored by incremental builds, MUST cleanall after changing this
# IPC_VERSION    := IPC4

# Define this empty for a plain sof/ directory and no sof -> sof-v1.2.3
# symbolic links. This is _only_ to override the top-level directory
# name; for sof_versions.h see version.cmake and try sof/.tarball-version
# SOF_VERSION :=
#
SOF_VERSION := $(shell git describe --tags )
# SOF_VERSION := v1.6.14

# Uncomment this to have the build_*_?cc/ directories at the top-level
BUILDS_ROOT := ${CURDIR}/..

# The build is not deterministic; use this to reduce noise when testing
# the installer/ itself
# BUILD_ONLY_ONCE := true

平台列表在 SIGNED_list 中指定。make 命令的 -C 参数用于在执行之前先切换目录。make 命令默认查找构建配置文件的顺序为 "GNUmakefile"、"makefile"、"Makefile",也可以用 -f [makefile path] 参数为 make 命令指定 makefile 的路径。SOF 项目中用了 "GNUmakefile",而不是更常见的 "makefile" 或 "Makefile"。

SOF 的 installer/GNUmakefile 文件会包含 config.mk,以获得其中的配置。如果在 makefile 中未设置 .DEFAULT_GOAL,那么 make 的默认目标是不以点号 '.' 开头的第一个目标。不过 SOF 的 makefile 设置了 .DEFAULT_GOALinstaller/GNUmakefile 默认构建的目标如下:

.DEFAULT_GOAL := stage
 . . . . . .
stage: signed unsigned ldicts aliases topologies tools
 . . . . . .
#
# 1. Stages all *.ri files
#
# 2. Create symbolic links, including (broken) intel-signed symbolic
#    links that must be fixed in a final release, otherwise the release
#    is incomplete. To check all symlinks: file $(find -type l)
#

# '%' is the platform name
SIGNED_FWS := ${SIGNED_list:%=${COMMUNITY}/sof-%.ri}
# $(info SIGNED_FWS = ${SIGNED_FWS})
signed: ${SIGNED_FWS}
${SIGNED_FWS}: ${COMMUNITY}/sof-%.ri:    \
               ${BUILDS_ROOT}/build_%_${TOOLCHAIN}/sof.ri     \
         | ${COMMUNITY} ${INTEL_SIGNED}
    install ${INSTALL_OPTS} $< $@
    ln -sfT     intel-signed/sof-$*.ri ${STAGING_SOF_VERSION}/sof-$*.ri

# '%' is the platform name
UNSIGNED_FWS := ${UNSIGNED_list:%=${STAGING_SOF_VERSION}/sof-%.ri}
# $(info UNSIGNED_FWS = ${UNSIGNED_FWS})
unsigned: ${UNSIGNED_FWS}
${UNSIGNED_FWS}: ${STAGING_SOF_VERSION}/sof-%.ri:   \
                 ${BUILDS_ROOT}/build_%_${TOOLCHAIN}/sof.ri
    install ${INSTALL_OPTS} $< $@


BUILD_SOF_RIS := \
      ${UNSIGNED_list:%=${BUILDS_ROOT}/build_%_${TOOLCHAIN}/sof.ri} \
        ${SIGNED_list:%=${BUILDS_ROOT}/build_%_${TOOLCHAIN}/sof.ri}

# When the build is not deterministic use this to reduce noise when testing
# this Makefile.
# Also very useful with XCC, see next comment.
ifneq (true,${BUILD_ONLY_ONCE})
.PHONY: ${BUILD_SOF_RIS}
endif

# Incremental builds are not possible with XCC because the entire
# toolchain requires $XTENSA_SYSTEM but CMake does not support
# build-time environment variables. In the future we could move the
# XTENSA_SYSTEM values out of xtensa-build-all.sh and into some shared
# config file included here.
${BUILD_SOF_RIS}: ${BUILDS_ROOT}/build_%_${TOOLCHAIN}/sof.ri: | ${BUILDS_ROOT}
    cd ${BUILDS_ROOT} && bdir="$$(dirname $@)" &&  \
      if [ -e $${bdir}/build.ninja -o -e $${bdir}/Makefile ] && \
          [ xcc != "${TOOLCHAIN}" ] ; then \
        cmake --build $${bdir} -- bin; else \
      $(CURDIR)/../scripts/xtensa-build-all.sh -i "${IPC_VERSION}" $*; fi

make 命令会调 cmakesof/scripts/xtensa-build-all.sh 脚本构建 SOF。当 {BUILDS_ROOT}/build_%_{TOOLCHAIN} 目录下,存在 build.ninjaMakefile 文件时,调用 cmake,否则调用 sof/scripts/xtensa-build-all.sh 脚本。{BUILDS_ROOT}/build_%_{TOOLCHAIN} 目录如 sof/build_imx8m_gcc

第一次执行 make 命令时,'{BUILDS_ROOT}/build_%_{TOOLCHAIN}' 目录还不存在,也就更不用说 build.ninjaMakefile 文件了,则 make 命令将调用 sof/scripts/xtensa-build-all.sh 脚本。sof/scripts/xtensa-build-all.sh 脚本创建构建环境,如:

for platform in "${PLATFORMS[@]}"
do

    printf '\n   ------\n   %s\n   ------\n' "$platform"

    HAVE_ROM='no'
    DEFCONFIG_PATCH=''
    PLATFORM_PRIVATE_KEY=''

    source "${SOF_TOP}"/scripts/set_xtensa_params.sh "$platform" ||
            die 'set_xtensa_params.sh failed'

    test -z "${PRIVATE_KEY_OPTION}" || PLATFORM_PRIVATE_KEY="${PRIVATE_KEY_OPTION}"

    if [ -n "$XTENSA_TOOLS_ROOT" ]
    then
        XTENSA_TOOLS_DIR="$XTENSA_TOOLS_ROOT/install/tools/$TOOLCHAIN_VER"
        XTENSA_BUILDS_DIR="$XTENSA_TOOLS_ROOT/install/builds/$TOOLCHAIN_VER"

        # make sure the required version of xtensa tools is installed
        if [ -d "$XTENSA_TOOLS_DIR" ]
            then
                XCC="xt-xcc"
            else
                XCC="none"
                >&2 printf 'WARNING: %s
\t is not a directory, reverting to gcc\n' "$XTENSA_TOOLS_DIR"
        fi
    fi

    # CMake uses ROOT_DIR for includes and libraries a bit like
    # --sysroot would.
    ROOT="$SOF_TOP/../xtensa-root/$HOST"

    if [ "$XCC" == "xt-xcc" ]
    then
        TOOLCHAIN=xt
        ROOT="$XTENSA_BUILDS_DIR/$XTENSA_CORE/xtensa-elf"
        # CMake cannot set (evil) build-time environment variables at configure time:
# https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#how-can-i-get-or-set-environment-variables
        export XTENSA_SYSTEM=$XTENSA_BUILDS_DIR/$XTENSA_CORE/config
        printf 'XTENSA_SYSTEM=%s\n' "${XTENSA_SYSTEM}"
        PATH=$XTENSA_TOOLS_DIR/XtensaTools/bin:$OLDPATH
        COMPILER="xcc"
    else
        TOOLCHAIN=$HOST
        PATH=$SOF_TOP/../$HOST/bin:$OLDPATH
        COMPILER="gcc"
        DEFCONFIG_PATCH=""
        printf 'My PATH=%s\n' "$PATH"
    fi

    BUILD_DIR=build_${platform}_${COMPILER}
    printf "Build in %s\n" "$BUILD_DIR"

    # only delete binary related to this build
    rm -fr "$BUILD_DIR"
    mkdir "$BUILD_DIR"
    cd "$BUILD_DIR"

    printf 'PATH=%s\n' "$PATH"
    ( set -x # log the main commands and their parameters
    cmake -DTOOLCHAIN="$TOOLCHAIN" \
        -DROOT_DIR="$ROOT" \
        -DMEU_OPENSSL="${MEU_OPENSSL}" \
        "${MEU_PATH_OPTION}" \
        "${PLATFORM_PRIVATE_KEY}" \
        -DINIT_CONFIG=${PLATFORM}${DEFCONFIG_PATCH}_defconfig \
        -DEXTRA_CFLAGS="${EXTRA_CFLAGS}" \
        "$SOF_TOP"
    )

sof/scripts/xtensa-build-all.sh 脚本执行 scripts/set_xtensa_params.sh 脚本设置平台相关俄参数,导出适当的环境变量,删除已经存在的构建目录,并创建新的,随后执行 cmake 命令。

后续再次执行 make 命令时,由于{BUILDS_ROOT}/build_%_{TOOLCHAIN} 目录下,已经存在 build.ninjaMakefile 文件,则会进行增量编译。

如果指定的平台得到支持,通常是调用 cmake。当指定的平台不支持时,sof/scripts/xtensa-build-all.sh 脚本会输出支持的平台列表,如:

work_sof/sof/installer$ make
UNSIGNED_list =  
SIGNED_list   = byt   
ALIAS_list    =      
cd /media/data/work_sof/sof/installer/.. && bdir="$(dirname /media/data/work_sof/sof/installer/../build_byt_gcc/sof.ri)" &&  \
      if [ -e ${bdir}/build.ninja -o -e ${bdir}/Makefile ] && \
          [ xcc != "gcc" ] ; then \
        cmake --build ${bdir} -- bin; else \
      /media/data/work_sof/sof/installer/../scripts/xtensa-build-all.sh -i "" byt; fi
Error: Unknown platform specified: byt
Known platforms are: imx8m imx8ulp rn rmb vangogh mt8186 mt8195 mt8188 acp_6_3
make: *** [GNUmakefile:192:/media/data/work_sof/sof/installer/../build_byt_gcc/sof.ri] 错误 1

调整示例命令中的 -j 4 为你的 CPU 核数,或者构建失败时可以移除它。

这个构建配置并发地构建多个平台,并将固件和拓扑文件部署到你配置的本地或远程目的地的 /lib/firmware/intel/。它第一次以默认的平台配置构建,然后切换到增量构建,这将保留你所做的任何 make menuconfig 或其它配置更改。下面将介绍这两种构建方法,如果你需要更好地控制构建系统和配置,请继续阅读。否则,你可以跳过接下来的两部分。

安装程序还从 sof/tools/ 子目录构建和部署一些用户空间二进制文件。

注意

安装程序比它所依赖的更底层的 ./scripts/ 脚本快得多,因为它不会每次运行时都删除构建目录。然而,一些 “大” 的配置更改,比如切换到不同的工具链,或一些罕见的构建失败,可能会使 installer-builds/build_* 目录处于一种不恰当的状态。在这种情况下,则删除这些目录并再次运行安装程序。

rm -rf $SOF_WORKSPACE/sof/installer-builds
make -C installer/

重新配置并从头构建

要从头构建 Sound Open Firmware,上面的安装程序 Makefile 依赖 https://github.com/thesofproject/sof/tree/master/scripts/xtensa-build-all.sh 脚本。如果你需要更好地控制构建过程,或调试一些构建问题,你也可以直接使用它。要为所有平台构建固件,则执行:

cd "$SOF_WORKSPACE"/sof/
./scripts/xtensa-build-all.sh -a

注意

这个脚本只有在交叉编译器和 xtensa-root 位于相同的 sof 目录中时才能工作,如上面说明的那样。

截至 2021 年 5 月,你可以指定如下平台参数中的一个或多个:bytchtbdwhswaplsklkblcnlsueicljsltgltgl-himx8imx8ximx8m。例如:

./scripts/xtensa-build-all.sh byt
./scripts/xtensa-build-all.sh byt apl

运行脚本而不带任何参数,可以获得最新的平台列表和帮助消息。你也可以通过 -d 来启用调试构建,通过 -r 来启用 rom 构建,和通过 -j [n] 来加速构建。

./scripts/xtensa-build-all.sh -d byt
./scripts/xtensa-build-all.sh -d -r apl
./scripts/xtensa-build-all.sh -d -r -j 4 apl

注意

xtensa-build-all.sh 脚本使用 rimage 来构建最终的固件镜像。rimage 默认使用 sof 仓库中包含的公钥来签名。然而,如果你需要使用一些其它的外部密钥来签名,你可以在调用构建之前,通过环境变量来指定你的密钥的路径:

export PRIVATE_KEY_OPTION=-DRIMAGE_PRIVATE_KEY=/path_to_key/private.pem

相同的导出机制在通过 Docker 构建时也应该能工作。

增量构建

这是一个 sof 仓库更详细的构建指南。不像 xtensa-build-all.sh,它不会每次都重新构建所有东西。上面的 installer Makefile 依赖它做增量构建。

下面的代码片段假设你的当前目录是 sof 克隆 ("$SOF_WORKSPACE"/sof/) 的根目录。

CMake 推荐在源码树外面构建。其中,这允许你从相同的源码在不同的构建目录中构建不同的配置/平台,而无需从头开始。

注意

-j 参数告诉 make,要并发使用多少个进程。选择一个与你的构建系统匹配的值。

对于 Bay Trail:

mkdir build_byt && cd build_byt
cmake -DTOOLCHAIN=xtensa-byt-elf -DROOT_DIR="$XTENSA_ROOT"/xtensa-byt-elf -DINIT_CONFIG=baytrail_defconfig ..
make help # lists all available targets
make bin -j4 VERBOSE=1

你可以将上面的 byt 替换为 sof/scripts/xtensa-build-all.sh 的帮助输出中列出的任何其它平台。查找与同一脚本或以上脚本中各个平台匹配的工具链。

上面 cmake 命令的执行,需要有一个合适的执行环境,包括 XTENSA_ROOTPATH 等环境变量的适当设置,及准备好的工具链等。使用 make 命令编译时,执行环境由 makesof/scripts/xtensa-build-all.sh 等脚本创建。直接在命令行中执行 cmake 命令,需要手动创建执行环境。PATH 环境变量需要添加工具链的 bin 目录路径,如 $SOF_TOP/../$HOST/binXTENSA_ROOT 环境变量需要指向 $SOF_WORKSPACE/xtensa-root 目录。

-DINIT_CONFIG 用于指定配置文件的名称。sof 的 src/arch/xtensa/configs 目录下包含一些平台预定以的默认配置,如:

/media/data/work_sof/sof$ ls  src/arch/xtensa/configs/
acp_6_3_defconfig  imx8m_defconfig    imx8x_defconfig   mt8188_defconfig  override             renoir_defconfig
imx8_defconfig     imx8ulp_defconfig  mt8186_defconfig  mt8195_defconfig  rembrandt_defconfig  vangogh_defconfig

-DINIT_CONFIG 需要定义为目标平台的配置文件名称。INIT_CONFIGscripts/cmake/kconfig.cmake 文件中处理,如:

if(NOT INIT_CONFIG_found)
# Brand new build directory, search for initial configuration

# Default value when no -DINIT_CONFIG on the command line
set(INIT_CONFIG "initial.config" CACHE STRING "Initial .config file")

# - ".' is the top source directory.
# - "src/arch/${arch}/configs" is for convenience and compatibility with
#   defconfigs.cmake.
# - First found wins.
# - If two archs ever use the same platform_defconfig name then a full
#   path must be used, e.g.: -DINIT_CONFIG=src/arch/myarch/collision_defconfig

set(init_config_search_list ".")
foreach(arch "xtensa" "host")
list(APPEND init_config_search_list "src/arch/${arch}/configs")
endforeach()

find_file(INIT_CONFIG_found
    NAMES ${INIT_CONFIG}
    NO_CMAKE_FIND_ROOT_PATH
    NO_DEFAULT_PATH
    PATHS ${init_config_search_list}
)

else()  # old build directory

if (INIT_CONFIG)
message(WARNING
    "IGNORING '-DINIT_CONFIG=${INIT_CONFIG}!!' "
    "Using up-to-date ${INIT_CONFIG_found} instead."
)
endif()

endif() # new/old build directory

它会在 src/arch/xtensa/configssrc/arch/host/configs 目录下查找配置文件,以获得配置文件的完整路径。

注意

在 cmake 步骤之后,你可以在 build_xxx 目录下使用 'make menuconfig' 自定义你的构建。

FW 二进制构建可以使用 DEBUG 和 ROM 选项。通过 'make menuconfig' 启用它们。

mkdir build_cnl_custom && cd build_cnl_custom
cmake -DTOOLCHAIN=xtensa-cnl-elf -DROOT_DIR="$XTENSA_ROOT"/xtensa-cnl-elf -DINIT_CONFIG=cannonlake_defconfig ..
make menuconfig # select/deselect options and save
make bin -j4

注意

如果你已经安装了 Ninja,你可以使用它来替换 Make。在配置步骤中键入 cmake -GNinja … 即可。

固件构建结果

固件二进制文件位于 build_<platform>/src/arch/xtensa/。安装器把它们拷贝到你的目标机器的 /lib/firmware/intel/sof 目录下。

sof-apl.ri  sof-bdw.ri  sof-byt.ri  sof-cht.ri  sof-cnl.ri  sof-hsw.ri

具体的目标目录,可以在 installer/config.mk 文件中配置。如:

# The default FW_DESTDIR is the local /lib/firmware/intel directory
# _remote := test-system.local
# FW_DESTDIR     := root@${_remote}:/lib/firmware/intel
# USER_DESTDIR   := ${_remote}:bin/

第 5 步. 构建拓扑文件和工具

如果你使用前一节介绍的固件安装器,你可能可以跳过这一节。

从头开始一步重新构建

不带任何参数的 https://github.com/thesofproject/sof/tree/master/scripts/build-tools.sh 构建 https://github.com/thesofproject/sof/tree/master/tools/ 的默认 CMake 目标 "ALL"。

/media/data/work_sof/sof$ cd "$SOF_WORKSPACE"/sof/
/media/data/work_sof/sof$ ./scripts/build-tools.sh 
+ cmake --build /media/data/work_sof/sof/tools/build_tools -- -j 4
[0/1] Re-running CMake...
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/hanpfei/data/work_sof/sof/tools/build_tools
[0/298] Generating abi.h
[1/298] Generating sof-hda-efx-generic-4ch.tplg
saving nhlt as binary in nhlt-sof-hda-efx-generic-4ch.bin
[6/298] Generating production/sof-imx8mp-wm8960-mixer.conf
[7/298] Generating production/sof-imx8-wm8960-cs42888.conf
[8/298] Generating production/sof-imx8mp-wm8960-mixer.tplg
[9/298] Generating production/sof-imx8-wm8960-cs42888.tplg

要查看选项列表,以 -h 选项运行 https://github.com/thesofproject/sof/tree/master/scripts/build-tools.sh

/media/data/work_sof/sof$ ./scripts/build-tools.sh -h 

Configures and builds selected CMake projects in the tools/ directory.
Attention: the list of selected shortcuts below is _not_ exhaustive. To
build _everything_ don't select any particular target; this will build
CMake's default target "ALL".

usage: ./scripts/build-tools.sh [-c|-f|-h|-l|-p|-t|-T]
       -h Display help

       -c Rebuild ctl/
       -l Rebuild logger/
       -p Rebuild probes/
       -T Rebuild topology/ (not topology/development/! Use ALL)
       -t Rebuild test/topology/ (or tools/test/topology/tplg-build.sh directly)

       -C No build, only CMake re-configuration. Shows CMake targets.

WARNING: building tools/ is now incremental by default!
         To build from scratch delete: /media/data/work_sof/sof/tools/build_tools
         or use the -C option.

增量构建

cd "$SOF_WORKSPACE"/sof/tools/
mkdir build_tools && cd build_tools
cmake ..
make -j4

如果你的 cmake --version 是 3.13 或更高,你可能想要使用 -B 选项:

cmake -B build_tools/
make  -C build_tools/ -j4 VERBOSE=1
rm -rf   build_tools/ # no need to change directory ever

拓扑文件和工具构建结果

拓扑文件位于 tools/build_tools/topology 目录下。安装器 Makefile 把它们拷贝到目标机器的 /lib/firmware/intel/sof-tplg/ 目录下。

sof-logger 工具位于 tools/build_tools/logger 目录下。安装器 Makefile 把它们拷贝到你选择的目标目录。

第 6 步. 构建 Linux 内核

Sound Open Firmware 使用 Linux 内核 dev 分支,它必须与其它开发分支 firmware 和 topology 一起工作。这个简短的小节展示了如何在 Ubuntu 上使用少量命令构建经过测试的 Debian 内核包。请注意,这些命令每次都是从头开始重新构建所有内容,这使得对于开发,速度慢得不合适。如果你需要修改内核代码,忽略这里的介绍,看一下 搭建一个基于 Ktest 的环境,kconfig repo 的 README 文件,和 SOF Linux 驱动程序架构

  1. 构建内核的这个分支
sudo apt-get install bison flex libelf-dev
cd "$SOF_WORKSPACE"
git clone https://github.com/thesofproject/linux
cd linux
git checkout topic/sof-dev
make defconfig
git clone https://github.com/thesofproject/kconfig
scripts/kconfig/merge_config.sh .config ./kconfig/base-defconfig ./kconfig/sof-defconfig  ./kconfig/mach-driver-defconfig ./kconfig/hdaudio-codecs-defconfig

或者,你也可以运行 make menuconfig,导航到 Device Drivers > Sound card support > Advanced Linux Sound Architecture,然后选择 Prefer SOF driver over SST on BY/CHT platforms 选项。

  1. 构建内核 deb 包以安装到目标机器上。
make deb-pkg -j 4
  1. 将三个输出 .deb 文件从 $SOF_WORKSPACE 拷贝到目标机器并安装它们。
sudo dpkg -i /absolute/path/to/deb/file
sudo apt-get install -f

参考文档

Build toolchains and SOF from sources

Done.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容