🐥

Clangを使用してみる(hello worldからmicrobitまで)

2021/01/17に公開

はじめに

Clang https://clang.llvm.org/ を使っていろいろなものをビルドしてみます。
まだ、不明点は多いですがmicrobitV1.5のLED点滅まで出来たので書いてみました。
どなたかの参考になれば良いかなと思っています。

確認環境

Ubuntu

$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.1 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.1 LTS"
VERSION_ID="20.04"

Clang

https://releases.llvm.org/download.html
Pre-Built Binaries:
https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/clang+llvm-11.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xz
を使用。
これを展開して、展開されたbinディレクトリにパスを通しておきます。設定例は以下。

$ cat .bashrc
<省略>
export PATH="/home/USERNAME/clang/clang+llvm-11.0.0-x86_64-linux-gnu-ubuntu-20.04/bin:$PATH"
$ . .bashrc
$ clang --version
clang version 11.0.0 (https://github.com/llvm/llvm-project.git 0160ad802e899c2922bc9b29564080c22eb0908c)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /home/USERNAME/clang/clang+llvm-11.0.0-x86_64-linux-gnu-ubuntu-20.04/bin

Hello world

まずは、Hello worldをビルドしてみます。

#include <stdio.h>

int main(void) {
    printf("Hello world\n");
    return 0;
}
$ clang hello.c 
$ ./a.out 
Hello world

できました。

Lua

次に, Lua (https://www.lua.org/) をビルドしてみます
使用するバージョンは 5.4にしています。

src/Makefile を見ると、以下のような記載があります

CC= gcc -std=gnu99
#<省略>
AR= ar rcu

ここを以下のように変更します。

CC= clang -std=gnu99
#<省略>
AR= llvm-ar rcu

makeをします。

lua-5.4.2$ make
<省略>
clang -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_3 -DLUA_USE_LINUX    -c -o lapi.o lapi.c
clang -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_3 -DLUA_USE_LINUX   -c lcode.c
clang -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_3 -DLUA_USE_LINUX    -c -o lctype.o lctype.c
<省略>
clang -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_3 -DLUA_USE_LINUX    -c -o linit.o linit.c
llvm-ar rcu liblua.a lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o lauxlib.o lbaselib.o lcorolib.o ldblib.o liolib.o lmathlib.o loadlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o linit.o 
ranlib liblua.a
clang -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_3 -DLUA_USE_LINUX    -c -o lua.o lua.c
clang -std=gnu99 -o lua   lua.o liblua.a -lm -Wl,-E -ldl 
clang -std=gnu99 -O2 -Wall -Wextra -DLUA_COMPAT_5_3 -DLUA_USE_LINUX    -c -o luac.o luac.c
clang -std=gnu99 -o luac   luac.o liblua.a -lm -Wl,-E -ldl 
<省略>

srcディレクトリにLuaが作成されるので、実行してみます。

$ src/lua
Lua 5.4.2  Copyright (C) 1994-2020 Lua.org, PUC-Rio
> print("hello")
hello
> 

動くようです。

microbit

次はクロスコンパイルをしてみます。
以下のコードをClangでビルドしてみます。

https://github.com/dwelch67/microbit/tree/master/blinker01

修正箇所

変更点すべてを以下におきました。
これで make で出来る binファイルを microbitにダウンロードすると、LEDが点滅します。

https://github.com/SaitoYutaka/microbit-1/commit/7fbbe58c3c73b1ff30d4fe370a37fc5b030422d1

オプション

ターゲットの指定

gccだと、-mcpuをでターゲットを指定するようですが、
clangの場合は -target オプションを指定するようです。
ドキュメントは以下。
https://clang.llvm.org/docs/CrossCompilation.html

Target Triple
The basic option is to define the target architecture.
For that, use -target <triple>. If you don’t specify the target,
CPU names won’t match (since Clang assumes the host triple), and
the compilation will go ahead, creating code for the host platform, which
will break later on when assembling or linking.

The triple has the general format <arch><sub>-<vendor>-<sys>-<abi>, where:
  * arch = x86_64, i386, arm, thumb, mips, etc.
  * sub = for ex. on ARM: v5, v6m, v7a, v7m, etc.
  * vendor = pc, apple, nvidia, ibm, etc.
  * sys = none, linux, win32, darwin, cuda, etc.
  * abi = eabi, gnu, android, macho, elf, etc.

microbitV1.5の場合は以下のようになるのでしょうか。

-target armv6-none-none-eabi

Linker script

Makefileのみの修正だと以下のエラーが出ます。

$ make
clang -nostdlib -target armv6-none-none-eabi -c flash.s
clang -Wall -Werror -O2 -nostdlib -ffreestanding -target armv6-none-none-eabi -mthumb -c notmain.c -o notmain.o
clang -fno-exceptions -fno-unwind-tables -nostdlib -target armv6-none-none-eabi -o notmain.elf -T flash.ld flash.o notmain.o
ld.lld: error: no memory region specified for section '.ARM.exidx'
clang-11: error: ld.lld command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:26: notmain.bin] エラー 1

今回はただ動けばよかったので(細かいオプションについてはおいおい調べるとして)
.ARM.exidxセクションは破棄するようにしました

    /DISCARD/ :
    {
        *(.ARM.exidx)
    }

DISCARDについてのドキュメントは以下。

https://sourceware.org/binutils/docs-2.35/ld/Output-Section-Discarding.html#Output-Section-Discarding

flash.s で出る warning

flash.s をアセンブルすると、以下のワーニングが出ます。

$ make
clang -nostdlib -target armv6-none-none-eabi -c flash.s
flash.s:3:1: warning: new target does not support arm mode, switching to thumb mode
.cpu cortex-m0
^

よくわからないのでコメントアウト (これから調べる)。

まとめ

とりあえず、クロスコンパイルまで出来たが、
まだまだ調べなきゃいけないところはたくさんありそう。

Discussion