Buildrootエラーで悩まされた結果、pkg-configの事がちょっとわかった話

# はじめに

Zynqで動作するボードでNervesを動作させるために、奮闘していた時に、Buildrootのエラーに遭遇しました。

結果的には、対象のパッケージのバグだったんですが、調査した過程を記事にしておきます。

類似した問題に遭遇した方に、参考になれば幸いです。

# 状況

次のような比較的平凡な、buildrootの設定でu-bootのをビルドしていました。

```
BR2_TARGET_UBOOT=y
BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y
BR2_TARGET_UBOOT_BOARD_DEFCONFIG="xilinx_zynq_virt"
# BR2_TARGET_UBOOT_FORMAT_BIN is not set
BR2_TARGET_UBOOT_FORMAT_REMAKE_ELF=y
BR2_TARGET_UBOOT_PATCH="${NERVES_DEFCONFIG_DIR}/u-boot"
```

以下のエラーが発生しました。

```
/usr/bin/ld: cannot find -luuid: No such file or directory
collect2: error: ld returned 1 exit status
make[3]: *** [scripts/Makefile.host:95: tools/mkeficapsule] Error 1
make[2]: *** [Makefile:1894: tools] Error 2
make[1]: *** [package/pkg-generic.mk:283: /home/masa/nerves/nerves_system_zynq_ebaz4205/.nerves/artifacts/nerves_system_zynq_ebaz4205-portable-0.0.1/build/uboot-2022.04/.stamp_built] エラー 2
make: *** [Makefile:23: _all] エラー 2
```

# 調査

ビルド時のログを確認してみます。
`make V=1`でビルドすると、詳細なログが出力されます。

```
$ make V=1
～～～省略～～～
/usr/bin/make -f ./scripts/Makefile.build obj=tools
  ./scripts/check-of.sh .config ./scripts/of_allowlist.txt
  /usr/bin/gcc -O2 -isystem /home/masa/nerves/nerves_system_zynq_ebaz4205/.nerves/artifacts/nerves_system_zynq_ebaz4205-portable-0.0.2/host/include -Wp,-MD,tools/.mkeficapsule.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -std=gnu11   -DCONFIG_FIT_SIGNATURE -DCONFIG_FIT_SIGNATURE_MAX_SIZE=0xffffffff -DCONFIG_FIT_CIPHER -include ./include/compiler.h -idirafterinclude -idirafter./arch/arm/include -I./scripts/dtc/libfdt -I./tools -DUSE_HOSTCC -D__KERNEL_STRICT_NAMES -D_GNU_SOURCE  -o tools/mkeficapsule tools/mkeficapsule.c   -lgnutls -luuid
/usr/bin/ld: cannot find -luuid: No such file or directory
collect2: error: ld returned 1 exit status
make[3]: *** [scripts/Makefile.host:95: tools/mkeficapsule] Error 1
make[2]: *** [Makefile:1894: tools] Error 2
make[1]: *** [package/pkg-generic.mk:283: /home/masa/nerves/nerves_system_zynq_ebaz4205/.nerves/artifacts/nerves_system_zynq_ebaz4205-portable-0.0.2/build/uboot-2022.04/.stamp_built] エラー 2
make: *** [Makefile:23: _all] エラー 
```

このコマンドが何をしているか整理してみます。

今回のビルドでは、クロスコンパイルを行っていています。ホストはX86_64で、ターゲットはARMです。
実行されているのは、`/usr/bin/gcc`です。
ホスト用のコンパイラーです。
u-bootのツールで、ホストで実行するツールをコンパイルしている時に発生したもになります。

gccの引数に`-luuid`が指定されていますが、-Lオプションみあたりません。

`-L`オプションでライブラリーのパスを指定していないため、ライブラリーが見つからないようです。

# 原因

いろいろ試行錯誤の末、原因は分かったんですが、
原因を先に書いてしまうと、u-bootのMakefileに不備があるため、ビルド時にエラーになっていました。
ビルド環境の問題かと思ったんですが、そうではなかったです。

ビルド対象のu-bootは、`uboot-2022.04`で、少し古いバージョンだからなんですかね？
`https://github.com/Xilinx/u-boot-xlnx.git`の`xilinx-v2024.1`で試してみたところ、問題なくビルドできたことから、違いを調べてみて、この結論に至りました。

`xilinx-v2024.1`の`tools/Makefile`の`-luuid`に関する記述を調べてみると、以下のようになっていました。
```
HOSTLDLIBS_mkeficapsule += \
	$(shell pkg-config --libs uuid 2> /dev/null || echo "-luuid")
```

ライブラリの場所をpkg-configで調べて、追加するようになっています。`uboot-2022.04`には、この記述がありませんでした。
生成されたオブジェクトがリンクしてるファイルを調べると、ちゃんとlibuuidが含まれてます

```
libuuid.so.1 => <～～省略～～>/host/lib/libuuid.so.1
```

```
$ cd <path to builroot>/build/uboot-xilinx-v2024.1/tools
$ ldd mkeficapsule
        linux-vdso.so.1 (0x00007ffddf3dd000)
        libgnutls.so.30 => /lib/x86_64-linux-gnu/libgnutls.so.30 (0x00007fa0e9835000)
        libuuid.so.1 => /home/masa/nerves/nerves_system_zynq_ebaz4205/.nerves/artifacts/nerves_system_zynq_ebaz4205-portable-0.0.2/host/lib/libuuid.so.1 (0x00007fa0e982c000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa0e9603000)
        libp11-kit.so.0 => /lib/x86_64-linux-gnu/libp11-kit.so.0 (0x00007fa0e94c8000)
        libidn2.so.0 => /lib/x86_64-linux-gnu/libidn2.so.0 (0x00007fa0e94a7000)
        libunistring.so.2 => /lib/x86_64-linux-gnu/libunistring.so.2 (0x00007fa0e92fb000)
        libtasn1.so.6 => /lib/x86_64-linux-gnu/libtasn1.so.6 (0x00007fa0e92e3000)
        libnettle.so.8 => /lib/x86_64-linux-gnu/libnettle.so.8 (0x00007fa0e929d000)
        libhogweed.so.6 => /lib/x86_64-linux-gnu/libhogweed.so.6 (0x00007fa0e9255000)
        libgmp.so.10 => /lib/x86_64-linux-gnu/libgmp.so.10 (0x00007fa0e91d3000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fa0e9a37000)
        libffi.so.8 => /lib/x86_64-linux-gnu/libffi.so.8 (0x00007fa0e91c6000)
```

# ホストビルド時に使われるライブラリ

ホストビルド時に使われるライブラリは、`host/lib/pkgconfig`に記述されています。
uuidについては、uuid.pcに記述されています。

```
$ cat host/lib/pkgconfig/uuid.pc 
prefix=/home/masa/nerves/nerves_system_zynq_ebaz4205/.nerves/artifacts/nerves_system_zynq_ebaz4205-portable-0.0.2/host
exec_prefix=/home/masa/nerves/nerves_system_zynq_ebaz4205/.nerves/artifacts/nerves_system_zynq_ebaz4205-portable-0.0.2/host
libdir=/home/masa/nerves/nerves_system_zynq_ebaz4205/.nerves/artifacts/nerves_system_zynq_ebaz4205-portable-0.0.2/host/lib
includedir=/home/masa/nerves/nerves_system_zynq_ebaz4205/.nerves/artifacts/nerves_system_zynq_ebaz4205-portable-0.0.2/host/include

Name: uuid
Description: Universally unique id library
Version: 2.39.1
Requires:
Cflags: -I${includedir}/uuid
Libs: -L${libdir} -luuid
```

たしかに```/host/lib```が指定されています。

pkg-configの動作を確認しておきます。
```
$ export PKG_CONFIG_PATH=$(pwd)/host/lib/pkgconfig
$ pkg-config --libs uuid
-L/home/masa/nerves/nerves_system_zynq_ebaz4205/.nerves/artifacts/nerves_system_zynq_ebaz4205-portable-0.0.2/host/lib -luuid
```

`-L<ライブラリの場所>`となっています。これでうまくビルドできています。

# ターゲットビルド時に使われるライブラリ

`PKG_CONFIG_PATH`を設定しないで、`./host/bin/pkg-config`を実行すると、以下のように表示され、ターゲット用のライブラリーが表示されるようです。

```
$ unset PKG_CONFIG_PATH
$ ./host/bin/pkg-config --libs uuid
-L./host/bin/../arm-buildroot-linux-gnueabihf/sysroot/usr/lib -luuid 
```

# まとめ

- 今回のエラーは、ビルドに使った、u-bootのMakefileに不備があって、ビルド時にエラーになっていました。
- 修正されたu-bootでは、問題なくビルドでき、修正内容から、ライブラリーの場所を指定していることがわかりました。
- クロス開発環境では、ホスト用とターゲット用の環境が区別されているので、どちらの問題かを見極めることが重要です。