Armadilloフォーラム

ライブラリが見つからないエラー

urasue

2023年1月5日 17時34分

いつもお世話になっております。

C言語で書かれたソースをATDE9でクロスコンパイルしたものをA6Eに転送し、
実行しようとしていますが、ライブラリが無いと言われます。

gcc:arm-linux-gnueabihf-gcc

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
 
int main(int argc,char *argv[])
{
        struct stat f_st;
        stat("hoge.txt",&f_st);
        return 0;
}
armadillo:/home/atmark# ldd ./ini_test
        /lib/ld-linux-armhf.so.3 (0xb6eb3000)
        libc.so.6 => /lib/ld-linux-armhf.so.3 (0xb6eb3000)
Error relocating ./ini_test: __xstat: symbol not found

stat関数を利用する場合、リンクするライブラリが必要なのでしょうか。

コメント

アットマークテクノの古賀です。

urasueさん:
>C言語で書かれたソースをATDE9でクロスコンパイルしたものをA6Eに転送し、
>実行しようとしていますが、ライブラリが無いと言われます。

armadillo:/home/atmark# ldd ./ini_test
        /lib/ld-linux-armhf.so.3 (0xb6eb3000)
        libc.so.6 =>/lib/ld-linux-armhf.so.3 (0xb6eb3000)
Error relocating ./ini_test: __xstat: symbol not found

>stat関数を利用する場合、リンクするライブラリが必要なのでしょうか。

いえ。これは、Base OS がベースにしている Alpine Linux の標準 C ライブラリが、Debian などで現在一般的なものとは異なるためです。Alpine Linux では、標準 C ライブラリに musl libc を使用しています:
 https://ja.wikipedia.org/wiki/Musl
 https://musl.libc.org/

そのため、Base OS 上で直接動作させるプログラムや、A6E 標準搭載のゲートウェイコンテナなどの Alpine コンテナ上で動作するプログラムを、C 言語で実装する場合は、musl libc をリンクするようにビルドしないといけません(ゲートウェイコンテナは、Alpine Linux のユーザーランドを使用しています)。
musl libc をリンクするようにビルドする方法としては、A6E 用や G4 用に提供している「Alpine Linuxルートファイルシステムビルドツール」のスクリプトを使い、開発環境入りの armv7 アーキテクチャ用 Apline コンテナをセットアップして、そのコンテナ上でビルドする、というのがお手軽です。
 https://armadillo.atmark-techno.com/resources/software/armadillo-iot-a6…
ビルド環境をコンテナにすることで、コンテナのホスト環境(ここでは ATDE)を「汚さず」に、開発用のライブラリなどをコンテナ内に封じ込め、持ち運びが簡単になります。仮想マシンに基づく環境である ATDE よりも、コンテナの方が軽量だからです。

「Alpine Linuxルートファイルシステムビルドツール」(build-rootfs)を使った、開発環境入りの Alpine コンテナのセットアップ手順は、次の通りです:

1.) 弊社サイトの「Armadillo-IoT ゲートウェイ A6E 開発用ツール」のページから、「Alpine Linuxルートファイルシステムビルドツール」のアーカイブを ATDE にダウンロードする:
 https://armadillo.atmark-techno.com/resources/software/armadillo-iot-a6…

$ wget https://armadillo.atmark-techno.com/files/downloads/armadillo-iot-a6e/tool/build-rootfs-v3.16-at.7.tar.gz

2.) ダウンロードしたアーカイブを展開して、セットアップスクリプトを実行する:

$ tar xf build-rootfs-v3.16-at.7.tar.gz
$ cd build-rootfs-v3.16-at.7/submodules/containers
$ sudo ./build.sh
...

これにより、Base OS 搭載の Armadillo シリーズの各 CPU アーキテクチャごとの、開発環境入り Alpine コンテナのコンテナイメージがセットアップされます。docker の image ls コマンドを実行すると、セットアップされたコンテナイメージ一覧を表示できます:

$ sudo docker image ls
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
alpine-3.16-aarch64   latest    075b1c000971   4 minutes ago   218MB
alpine-3.16-armv7     latest    1e5978cd4870   4 minutes ago   153MB
alpine-3.16-x86_64    latest    a7fcc0fc4020   5 minutes ago   207MB
amd64/alpine          3.16      bfe296a52501   8 weeks ago     5.54MB
arm32v7/alpine        3.16      cebecc12fbb5   8 weeks ago     3.79MB
arm64v8/alpine        3.16      2b4661558fb8   8 weeks ago     5.29MB

このうち、'alpine-3.16-armv7' が、A6E の CPU アーキテクチャに対応した Alipne コンテナイメージです(※'3.16' の部分は、今後、ベースの Alpine Linux のバージョンが更新されると変わります)。また、お手元の ATDE で、既に「Alpine Linuxルートファイルシステムビルドツール」を使ってルートファイルシステムをビルドしていらっしゃる場合には、コンテナイメージがセットアップされていますので、上記の build.sh の実行は不要です。
このコンテナイメージを使ってコンテナインスタンスを作成・起動すると、QEMU を使ってコンテナインスタンスが動作します。つまり、alpine-xx-armv7 のコンテナイメージであれば、QEMU の armv7 エミュレータで動作しますから、コンテナ上で armv7 アーキテクチャのプログラムが動作しますし、クロスビルドではなく、セルフビルドで armv7 用のプロブラムをビルドできる、というわけです。実機に依存しない動作のプログラムであれば、動作確認もコンテナ上で行うことができます。

以下は、"a6edev" という名前のコンテナインスタンスを作って、そのコンテナ内でプログラムをビルド・実行する場合の手順例です:

$ cd
$ sudo docker run -it --name a6edev --platform "linux/armhf" --mount type=bind,src="$PWD",target=/home/builder/atmark alpine-3.16-armv7 /bin/sh
※ここからコンテナ内での実行となります
/ # su builder
/ $ cd && cd atmark
~/atmark $  vi ini_test.c
(C 言語のソースコードを作成)
~/atmark $ gcc -o ini_test ini_test.c
~/atmark $ ./ini_test
~/atmark $ ldd ini_test
	/lib/ld-musl-armhf.so.1 (0x40000000)
	libc.musl-armv7.so.1 => /lib/ld-musl-armhf.so.1 (0x40000000)
~/atmark $ exit
/ # exit
※コンテナインスタンスの実行が終了し、ホスト環境に戻ります

上記例で作成したコンテナインスタンスは、以後 docker start と docker exec で再び起動できます。

$ sudo docker start a6edev && sudo docker exec -it a6edev /bin/sh

いかがでしょうか?

【補足】ところで、arm-linux-gnueabihf-gcc を使い、ATDE 上で直接クロスビルドして出来た、libc.so をリンクしたバイナリを A6E 上で動かす方策として、A6E に Debian のコンテナイメージをセットアップして Debian コンテナ内で動かす、というのがあります。Debian のコンテナイメージは大きいので、最初に動かす際にイメージをダウンロードするのに時間がかかりますが、イメージのセットアップ後は、Alpine ベースのコンテナと同様に動かせます。

例として、Base OS の /mnt ディレクトリを同じパス名でマウントして使用する Debian bullseye コンテナを動かす場合は、A6E (Base OS) の /etc/atmark/containere/ に次の内容の conf ファイルを作り、podman_start を実行すればよいです:

set_image docker.io/debian:bullseye
 
add_volumes /mnt:/mnt
 
# replace with a more useful command
set_command sleep infinity

この conf ファイルの名前が debian.conf であれば、'podman_start debian' を実行するとコンテナインスタンスが作成・起動します。そして、ATDE でクロスビルドしたバイナリを USB メモリに入れて、Base OS の /mnt にマウントしておけば、同じパスでコンテナ内からアクセスできます。

※USB メモリを Base OS からマウントする
# mount /dev/sda /mnt
※Debian コンテナインスタンスを作成・起動する
# podman_start debian
...
※debian コンテナでシェルを実行
# podman exec -it debian /bin/sh
※ここからコンテナ内での実行
# ls /mnt/ini_test
# ldd /mnt/ini_test
        linux-vdso.so.1 (0xbef8c000)
        libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6e83000)
        /lib/ld-linux-armhf.so.3 (0xb6f94000)
# /mnt/ini_test
# exit
※コンテナのシェル実行を終了し、Base OS に戻る

以上、参考になりましたら幸いです。

古賀様

ご回答ありがとうございます。
Alpine Linuxはmusl libcを使用しているとの事、承知いたしました。
ATDE9上にAlpineのコンテナ環境を作りコンパイルしたところ、実機上で正常に動作いたしました。
コンテナでのビルド環境構築は便利ですね。ありがとうございました。