LK build system

The LK build system thinks of the world in four layers.

Projects

Projects are what you ask make to build.
They are a set of modules (typically apps and libraries) built for a Target.

They are defined in project/name.mk.

The Target is selected via TARGET := namein this makefile or an included makefile (in the case where multiple projects share a common configuration). You choose your project by either passing it to make on the commandline (make name) or putting a PROJECT := name directive in local.mk.

Targets

Targets are typically a specific PCB (or family of extremely closely related PCBs, maybe differing just a little, detectable by some revision resistors or the like).

They belong to a Platform and are defined in target/name/rules.mk.

The Platform is selected via PLATFORM := name in this makefile.

Platforms

Platforms typically are Systems-on-Chip (either individual or related families).

They belong to an Architecture and are defined in platform/name/rules.mk.

The Architecture is selected via ARCH := name in this makefile.

Architectures

Architectures are a specific CPU or CPU family (ARM Cortex M3, Intel IA32, etc).

Example Project

An example project is stm32f4-discovery-test.

The Target there is stm32f4-discovery (the ST development board of the same name).

Its Platform is stm32f4xx, a family of ST microcontrollers. STM32_CHIP is set to stm32f407 for things that may be specific to that chip. Some GLOBAL_DEFINES are configured here as well, like HSE_VALUE which is the frequency of the crystal — a platform-specific definition.

The Platform stm32f4xx sets ARCH as arm and ARM_CPU (specific to arm architecture) to cortex-m4, as well as configuring other platform-specific values.

The above configuration information lives in the following files in the lk source tree:

  • project/stm32f4-discovery-test.mk
  • target/stm32f4-discovery/rules.mk
  • platform/stm32f4xx/rules.mk
  • arch/arm/rules.mk

Building Outside The LK Tree

The build system provides a mechanism to overlay additional projects, targets, platforms, apps, libs, etc, from sibling directory hierarchies. This allows you to more easily build and maintain projects that are not part of the main lk tree.

For example, say you have LK checked out in an lk directory, and next to that you have a mystuff directory (a checkout of your own source tree). It can contain your own projects, libraries, and apps, like so:

  • mystuff/project/toaster-oven.mk
  • mystuff/target/toaster-oven/{rules.mk, init.c, …}
  • mystuff/app/toaster-ui/{rules.mk, main.c, …}
  • mystuff/lib/cool-lcd/{rules.mk, lcddriver.c, …}
  • mystuff/lib/pid-controller/…

If you copy lk/makefile to mystuff/makefile and create lk_inc.mk like so:

1
2
3
4
5
6
LOCAL_DIR := mystuff
LKMAKEROOT := ..
LKROOT := lk
LKINC := $(LOCAL_DIR)
DEFAULT_PROJECT ?= toaster-oven
BUILDROOT ?= $(LOCAL_DIR)

You can then cd to mystuff and run make to build your project. You don’t need to modify anything in the main lk tree, so it’s easy to keep that up to date — no need to fork it, merge or rebase your changes, etc.

Details

  • LKMAKEROOT is the relative path from the overlay tree you’re building in to the directory that’s above the lk directory and any overlay tree directories (you can have multiple of these if you like). This variable is the only one that can have .. path elements in it. Such elements used anywhere else will cause the build system to misbehave.
  • LKROOT is the path relative to LKMAKEROOT to LK itself.
  • LKINC is the set of paths relative to LKMAKEROOT to overlay directories.
  • DEFAULT_PROJECT does what it says — sets the project to build if another is not specified when make is invoked.
  • BUILDROOT is relative to LKMAKEROOT and is the directory where build-$(PROJECT) will live, containing the build results.
  • You can also specify your TOOLCHAIN_PREFIX here to point at your chosen cross-compiler for this overlay.

Alternate Approach

If you’d rather run make from the top directory (that contains lk and mystuff), you can copy lk/makefile and set up lk_inc.mk there instead. Just change the value of LKMAKEROOT and BUILDROOT both to . and you’re all set.

使用步骤

build essential

1
1.sudo apt-get install build-essential

for arch arm64 build

1
2
3
4
5
1. mkdir -p gcc_linario_aarch64_toolchain
2. cd gcc_linario_aarch64_toolchain
3. wget -c https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-elf/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-elf.tar.xz
4. tar xf gcc-linaro-7.3.1-2018.05-x86_64_aarch64-elf.tar.xz
5. export PATH=$PATH:`pwd`/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-elf/bin

for arch arm build

1
2
3
4
5
1. mkdir -p arm-eabi-5.3.0-Linux-x86_64
2. cd arm-eabi-5.3.0-Linux-x86_64
3. wget -c http://newos.org/toolchains/arm-eabi-5.3.0-Linux-x86_64.tar.xz
4. tar xf arm-eabi-5.3.0-Linux-x86_64.tar.xz
5. export PATH=$PATH:`pwd`/arm-eabi-5.3.0-Linux-x86_64/bin

install qemu

1.sudo apt-get install qemu
2.安装QEMU之后,命令行输入”qemu- + Tab”可以找到有如下的命令可用:

1
2
3
4
5
6
7
8
9
10
qemu-aarch64              qemu-make-debian-root     qemu-nios2                qemu-sparc32plus          qemu-system-microblazeel  qemu-system-ppc64le       qemu-system-xtensa
qemu-alpha qemu-microblaze qemu-or1k qemu-sparc64 qemu-system-mips qemu-system-ppcemb qemu-system-xtensaeb
qemu-arm qemu-microblazeel qemu-ppc qemu-system-aarch64 qemu-system-mips64 qemu-system-s390x qemu-tilegx
qemu-armeb qemu-mips qemu-ppc64 qemu-system-alpha qemu-system-mips64el qemu-system-sh4 qemu-x86_64
qemu-cris qemu-mips64 qemu-ppc64abi32 qemu-system-arm qemu-system-mipsel qemu-system-sh4eb
qemu-hppa qemu-mips64el qemu-ppc64le qemu-system-cris qemu-system-moxie qemu-system-sparc
qemu-i386 qemu-mipsel qemu-s390x qemu-system-i386 qemu-system-nios2 qemu-system-sparc64
qemu-img qemu-mipsn32 qemu-sh4 qemu-system-lm32 qemu-system-or1k qemu-system-tricore
qemu-io qemu-mipsn32el qemu-sh4eb qemu-system-m68k qemu-system-ppc qemu-system-unicore32
qemu-m68k qemu-nbd qemu-sparc qemu-system-microblaze qemu-system-ppc64 qemu-system-x86_64

可以看到它可以模拟很多种不同的架构。还有像qemu-img其实是一个工具,可以用来生成虚拟盘。
这里我们主要使用qemu-system-aarch64和qemu-system-arm。
3.可以查看qemu版本信息:

1
2
3
$ qemu-system-arm -version
QEMU emulator version 2.11.1(Debian 1:2.11+dfsg-1ubuntu7.7)
Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developers

主要参数说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
1.支持的machine
qemu-system-aarch64 -machine help

其中,virt为:
QEMU 2.11 ARM Virtual Machine (alias of virt-2.11)

2.支持的cpu
qemu-system-aarch64 -machine virt -cpu help

其中,可以看到支持的arm cortex系列有:
cortex-a15
cortex-a53
cortex-a57
cortex-a7
cortex-a8
cortex-a9
cortex-m3
cortex-m4
cortex-r5

3.设置内存
-m [size=]megs[,slots=n,maxmem=size]
configure guest RAM
size: initial amount of guest memory
slots: number of hotplug slots (default: none)
maxmem: maximum amount of guest memory (default: none)

4.设置cpu核数
-smp [cpus=]n[,maxcpus=cpus][,cores=cores][,threads=threads][,sockets=sockets]
set the number of CPUs to 'n' [default=1]
maxcpus= maximum number of total cpus, including
offline CPUs for hotplug, etc
cores= number of CPU cores on one socket
threads= number of threads on one CPU core
sockets= number of discrete sockets in the system
5.设置镜像文件
-kernel bzImage use 'bzImage' as kernel image

示例:

1
2
3
4
5
6
7
qemu-system-arm  -M vexpress-a9 -m 512M -nographic -append "console=ttyAMA0" -kernel  /root/zImage-3.0

-M vexpress-a9 模拟vexpress-a9单板
-m 512M 单板运行物理内存512M
-kernel /root/zImage-3.16 告诉qemu单板运行内核镜像路径
-nographic 不使用图形化界面,只使用串口
-append "console=ttyAMA0" 内核启动参数,这里告诉内核vexpress单板运行,串口设备是哪个tty。

get lk code and build

1
2
3
4
5
6
7
8
9
10
11
12
13
sudo apt-get install git

git clone https://github.com/littlekernel/lk

cd lk/

make list
可以看到列出来的project list

make list_name
编译project list_name,例:
make qemu-virt-a53-test
编译完后,在lk下可以看到build-qemu-virt-a53-test文件夹,里面lk.elf即为生成的镜像文件

我们看一下mk文件里定义了哪些内容:
lk/project/qemu-virt-a53-test.mk

1
2
3
4
5
6
7
8
# main project for qemu-aarch64
MODULES += \
app/shell

include project/virtual/test.mk
include project/virtual/fs.mk
include project/virtual/minip.mk
include project/target/qemu-virt-a53.mk

lk/project/target/qemu-virt-a53.mk

1
2
3
4
5
# main project for qemu-aarch64
ARCH := arm64
ARM_CPU := cortex-a53

include project/target/qemu-virt.mk

lk/project/target/qemu-virt.mk

1
2
3
4
# main project for qemu-virt
TARGET := qemu-virt

WITH_LINKER_GC := 0

lk/project/virtual/fs.mk

1
2
3
4
5
6
7
8
9
# modules related to a file system layer

MODULES += \
lib/fs \
lib/fs/ext2 \
lib/fs/fat32 \
lib/fs/spifs \
lib/fs/spifs/test \
lib/fs/memfs

lk/project/virtual/test.mk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# common libraries for -test variants

MODULES += \
app/shell \
app/stringtests \
app/tests \
lib/aes \
lib/aes/test \
lib/cksum \
lib/debugcommands \
lib/libm \
lib/version \

WITH_CPP_SUPPORT=true

lk/project/virtual/minip.mk

1
2
3
4
5
# modules related to the minip stack

MODULES += \
lib/minip \
app/inetsrv

qemu run

1
qemu-system-aarch64 -machine virt -cpu cortex-a53 -smp 1 -m 512M -kernel build-qemu-virt-a53-test/lk.elf

可以看到有一个窗口弹出,默认为qemu console,Ctrl + Alt + 2切换到运行的系统的console,Ctrl + Alt + 1再切换回来。
在系统的console可以看到打印出来的启动过程:
lk启动过程

help 命令可以查看支持的测试指令。

命令添加参数-nographic -append “root=/dev/ram init=/init console=ttyS0”,可以重定向qemu的打印消息到当前console,这样就可以靠鼠标滚轮查看内核启动消息。

1
qemu-system-aarch64 -machine virt -cpu cortex-a53 -smp 1 -m 512M -nographic -append "root=/dev/ram init=/init console=ttyS0" -kernel build-qemu-virt-a53-test/lk.elf

打印到当前console