Closed39

Strlcpyがない (gcc imageに)

トーテムトーテム

docker でCファイルをコンパイルしようとしたら、strlcpyがなかった。
(標準なんじゃないんか!!)
GNU libcライブラリをインストールすれば、何とかなるっぽい。

トーテムトーテム

make installしたら、よくわからんエラー出た。

Makeconfig:43: *** objdir must be defined by the build-directory Makefile.  Stop.

ネットで検索する限り、設定忘れらしい。適当に調べた感じ設定の仕方は見つからんかったー。

クローンしたファイルに、READMEがあったため、閲覧。

INSTALLファイルにインストール方法が書いているらしい。助かる。
ん?そういえば、さっきのmake installする前のセクションに設定がうんたらって書いてあるページがあったような。

うん、あった。設定方法がないんじゃなくて読み飛ばしておりました。
https://sourceware.org/glibc/manual/latest/html_node/Configuring-and-compiling.html

トーテムトーテム

ビルド用の空のディレクトリを作って、そのディレクトリをカレントディレクトリにして、クローンしたディレクトリの'configure'を実行する必要があるらしい。

トーテムトーテム

gawkとbisonをインストールした後、ふたたび、configureを実行。
またエラー。

*** On GNU/Linux systems the GNU C Library should not be installed into 
*** /usr/local since this might make your system totally unusable.      
*** We strongly advise to use a different prefix.  For details read the FAQ.
*** If you really mean to do this, run configure again using the extra  
*** parameter `--disable-sanity-checks'.

今度は--prefix=/usrオプションを付けて実行。
うまくいったみたい。

config.status: creating config.make
config.status: creating Makefile
config.status: creating config.h
config.status: executing default commands
root@ef1964b9a3b0:/app/test/glibc-build# ls
Makefile  bits  config.h  config.log  config.make  config.status

ここで、make installすればいいのかにゃ?
make install
きたくさい。
待機。

トーテムトーテム

・・・数分後
と思ったら、数時間後・・・。
(途中でmake install -j8に変更)
はい、エラーw

make[2]: *** [Makefile:1332: /app/test/glibc-build/elf/ld.so] Error 1
make[2]: Leaving directory '/app/test/glibc/elf'
make[1]: *** [Makefile:484: elf/subdir_lib] Error 2
make[1]: Leaving directory '/app/test/glibc'
make: *** [Makefile:12: install] Error 2
トーテムトーテム

ネットで調べた感じ、windowsのディレクトリにバインドした下でコンパイルしたことで、大文字と小文字の区別がなくなってエラーが出てるっぽいorz
以下のURLで紹介されている通りにやればよさそう。
https://learn.microsoft.com/ja-jp/windows/wsl/case-sensitivity
fsutil.exe file setCaseSensitiveInfo <path> enableコマンドを実行して大文字と小文字の区別を有効に。。。
エラー。
エラー: ディレクトリが空ではありません。
つまりやり直し。
きついから、一旦コンテナ削除して、別コンテナでglibcをインストールした後、別イメージで固めようかな、、、タハハ。

トーテムトーテム

とりあえずコンテナの起動。
docker run -dit --init --rm --name gcc gcc cat
docker exec -it gcc bashで接続

さっきの依存しているプログラムをインストール

apt-get update && apt-get install -y \
	gawk \
	bison
トーテムトーテム

今度は、wgetをつかって、なるべく簡潔にインストールしたい。そのあと、手順をDockerfileに固めたい。公式サイトに現在の安定バージョンは2.39って書いてあるので、今回はそれを選択。今回は特にgzipとして保存する。ftpサーバーから対象のファイルを選択して、リンクのコピーを行い張り付けた。

トーテムトーテム

wget <url>https://ftp.gnu.org/gnu/glibc/glibc-2.39.tar.gz
(なぜか<url>を https://ftp.gnu.org/gnu/glibc/glibc-2.39.tar.gz で置き換えると投稿できなかった。よーわからんぬ。)
2.39バージョンのglibがダウンロードされる。
tar xzf glibc-2.39.tar.gzダウンロードしたファイルを解凍。
mkdir glib-buildビルド用のディレクトリを作成。
../glibc-2.39/configure --prefix=/usrシステム全体にインストールするするための設定を行う。
make install -j8を実行。
なんか今回はめっちゃ早い。さっきは、3秒に1ファイルぐらいだったのに・・・。
さっきは、途中で電源設定いじったり、一回ctrl+cで中断したり、したのが問題だったのか・・・?
それか、ルーターをIPv6対応のにしたからか?バインドしてないから?ポートフィルタリング溶かしてるから?なんでかはよくわからんな。とりますぐ終わりそうでうれしい。あ、あと配信見ながらコンパイルしていたからだろうか・・・?
なんてことを打ち込んでいるうちに終了・・・。さっきまでのはいったい何だったんだ。

トーテムトーテム

と思ったら、またエラー。なんぞ?

make[2]: *** No rule to make target '/root/glib-build/mathvec/libmvec.so.1', needed by '/usr/lib64/libm.so'.  Stop.
make[2]: *** Waiting for unfinished jobs....
make[2]: Leaving directory '/root/glibc-2.39/math'
make[1]: *** [Makefile:484: math/subdir_install] Error 2
make[1]: Leaving directory '/root/glibc-2.39'
make: *** [Makefile:12: install] Error 2
トーテムトーテム

とりあえず、make
またエラー。読むの疲れたから、make checkしてみる。

トーテムトーテム

うーん、なんか遅いので一旦ディレクトリ削除して、
configure
make -j8
make -j8 check
を実行。
すると、makeは通ったものの、checkの時点で、エラーが。
修正方法が見つからなかったので一旦スルーして、
make -j8 installを実行。
するとしばらくすると、*** stack smashing detected *** terminatedというエラーが出て終了した。
そのあとはlsしてもechoしても同じエラー。
コンテナから離れたら接続できなくなっちゃった。
調べたら、スタックオーバーランで強制終了しているらしい。けどずっと強制終了ってどういうコト?ナニモ調査ができぬ・・・。
おとなしく、make -j8 check で止まっておけば・・・。
とりあえず、再実行してみる。

トーテムトーテム

今更ながら、GNU libc ではなく、BSD libcを入れないといけないようである。orz

トーテムトーテム

よく探したら、gccのイメージにBSDライブラリが入ってた。
ヘッダーファイルをインストールして、動的ライブラリへの検索パスを通せば晴れてstrlcpyが使えるようになりそう。
けど、どうやって?

トーテムトーテム

動的ライブラリのパスについては、/etc/ld.so.confにあるみたい。
中身を見るとinclude /etc/ld.so.conf.d/*のようになってたので、/etc/ld.so.conf.d以下の設定ファイルをすべて読み込むようである。
読み込みたいライブラリlibbsd.so.0は、/usr/lib/x86_64-linux-gnu/にあった。
設定ファイルの一つに/usr/lib/x86_64-linux-gnuの行があったので、ライブラリの検索には引っかかってるように見える。

find / -name "string.h"を実行したら、3件見つかったが、
cat $(find / -name "string.h") | grep 'strlcpy'で、strlcpyの宣言を探したが見つからなかった。
apt search libbsdで見つかったパッケージをそれっぽいものをいくつかインストールして確認したところ、libbsd-devがヘッダーファイルをインストールするものらしい。
インストールを実行apt install -y libbsd-dev

トーテムトーテム

インクルードパスを通す前に、ちゃんと動的ライブラリが使えるかどうかをチェックする。

次のようにして、`main.c`を作成。
echo '
#include <stdio.h>
#include <string.h>
size_t strlcpy(char *dst, const char *src, size_t siz);
int main(void) {
    strlcpy(NULL, NULL, 0);
    return 0;
}
' > main.c

gcc main.cを実行。コンパイルエラー。

/usr/bin/ld: /tmp/cc550dlV.o: in function `main':
main.c:(.text+0x14): undefined reference to `strlcpy'
collect2: error: ld returned 1 exit status

さっきの設定ファイルがちゃんと設定されていなかったのかと思い確認したが問題なさそう。
引数で指定してコンパイル。
gcc main.c -L /usr/lib/x86_64-linux-gnu/ -l bsd
コンパイルエラーはなかった。
生成されたファイルを実行./a.out
セグフォは起きたが、実行はできた。

つまり、ライブラリへのパスが通ってないように見える。

トーテムトーテム

gcc main.c -l bsdでも実行。問題なくコンパイルができた。
検索パスは指定されているが、libbsdを自動的に読み込む設定になっていないようである。

トーテムトーテム

libbsdを自動的に読み込む設定はよくわからなかったからやーめた!
pkg-config とか使うと割と簡単にはなるっぽいけど、省略するような設定は見つけられなかった。

トーテムトーテム

apt update && apt install -y libbsd-devを実行すると、ヘッダーファイル類がインストールされる。

#include <bsd/string.h>のようにして、読み込むとstrlcpyをコンパイルできるようになる。
実際のサンプルコード(main.c)

#include <stdio.h>
#include <bsd/string.h>

int main(void) {
    strlcpy(NULL, NULL, 0);
    return 0;
}

コンパイル

gcc -l bsd main.c

実行

./a.out

結果

Segmentation fault
トーテムトーテム

コンテナ立ち上げるたびに、インストールするのは面倒なので、Dockerfileを作成

apt update時にダウンロードしたファイルは削除したい。
find / -not -path "/proc/**" -fprint old.filesapt update前のファイル一覧をold.filesに書き出した後、同様に次のコマンドを実行して保存する。/proc/**は関係ないので無視する。
find / -not -path "/proc/**" -fprint new.files
その後、diffして何が違うか見る。
diff old.files new.files
/var/lib/apt/listsにファイルが増えていたため、これを削除して、apt install libbsd-devができるかどうか、apt updateができるかどうかを確認したところ問題なかった。
ので、rm -rf /var/lib/apt/lists/*を最後に実行する。

もしもapt isntall libbsd-devをした後にも不要なファイルが増えるなら削除したいので、同様に確かめる。
消しても問題ない(gcc を使ってコンパイルできる)と判断できるファイルがlogファイルとmanファイルぐらいしかなかったため、削除するのはやーめた。

DockerfileのベストプラクティスにCMDは毎回書けよ見たいなことが書いてあったような気がするので、一応書いておく。なぜ、catにしているかは、bashだとSIGTERMを受け取っても終了しないため。

FROM gcc

RUN apt update && apt install -y \
    libbsd-dev && \
    rm -rf /var/lib/apt/lists/*

CMD [ "cat" ]

トーテムトーテム

インデントおかしい気もするけど、面倒なのでスキップ。

docker image build . -t libbsd:latestで、適当に名前とタグをつけてビルド。
docker run -it --init libbsd bashで、起動。
再び、さっきのファイルをコンパイルして、動作確認。
次のようなdocker-compose.ymlファイルを作成。(例)

services:
  gcc:
    container_name: hoge
    image: libbsd:latest
    build:
      context: ./docker/libbsd
    volumes:
      - type: bind
        source: ./
        target: /app
    init: true
    tty: true
    command: "cat"

docker compose up -dで立ち上げて、
docker compose -it exec gcc bashで接続。
さっきコンパイルできることは確認したので、同じイメージかどうかをざっくりと検証。apt list | grep 'libbsd-dev'

これで、何とかstrlcpyが使えるようになった。
ただ、bsd/string.hのように読み込まないといけないので、移植性は低いような気もする。
bsdlibがインストールできない環境が本番環境だったら大変そうなので気を付けないと・・・。
今の環境はただの趣味だけど。

トーテムトーテム

lddで生成した実行ファイルがどんな共有ライブラリとリンクしているかを確認したら、libcや他のものも混じっていた。ならば、どうにかして、-l bsdなどのオプションを設定しなくてもコンパイルできるようになるだろうと思った。

gcc -vでコンパイルの詳細が見れた。
中に、-lcの指定があった。つまり、どうにかして設定する方法がある・・・はず。
他にも Configured withを発見。パスを確認したがソースコードは見つからなかった。
man gccを見る感じ特にそれらしいオプションは見つけられなかった。
多分、gccをインストールする際に設定したのだと思われる。

gcc の公式サイトから、Installationを踏んだら、それらしきページを見つけた。
https://gcc.gnu.org/install/configure.html
多分、この大量のオプションの中に-lcを指定するオプションがあるので、そこで一緒に-lbsdをしようと思う。

トーテムトーテム

お!次の関数を作成したら、gccコマンドをオーバーライドできた!!

gcc() {
    command gcc $(pkg-config --cflags libbsd-overlay) $* $(pkg-config --libs libbsd-overlay);
}
トーテムトーテム

/etc/profileにこの関数を書き込んでみたけど、うまく反映されなかった。なぜに?

とりあえず、ちゃんと反映された、/root/.bashrcに書き込んだ。

FROM gcc

RUN apt update && apt install -y \
	libbsd-dev && \
	rm -rf /var/lib/apt/lists/*

RUN echo ' \
	function gcc() { \
    	command gcc $(pkg-config --cflags libbsd-overlay) $* $(pkg-config --libs libbsd-overlay); \
	}; \
	' >> /root/.bashrc

CMD [ "cat" ]
トーテムトーテム

やったー!コンパイルされた―!

いぇええいい!

だがしかし・・・makeファイルでは反映されず・・・どうしてだよおおおおお!

トーテムトーテム

まあ、ちょっとは楽になったということで良しとしましょうかねぇ・・・

トーテムトーテム

むむ、もしや--with-stage1-ldflagsらへんを使うとライブラリを指定できる感じか?!

トーテムトーテム

pkg-config --libs --cflags libbsd-overlayを実行すると
-DLIBBSD_OVERLAY -isystem /usr/include/bsd -lbsd
のように取得できる。
この内容より、システムディレクトリを/usr/include/bsd
リンカーのオプションを-lbsdにして、-DLIBBSD_OVERLAYをおそらくプリプロセス時に指定すればいいと思われる。ちなみに、通常時に同じオプションを指定してコンパイルできることは確認済み。

--with-native-system-header-dirが使えそう。

gccのコマンドを参考に、以下の行を追加してビルドしてみる。
extraConfigureArgs=''
extraConfigureArgs="$extraConfigureArgs --with-native-system-header-dir=/usr/include/bsd"
extraConfigureArgs="$extraConfigureArgs --with-boot-ldflags="-lbsd -static-libstdc++ -static-libgcc""

トーテムトーテム

どうしてもうまくいかない。

まだ早かったようなので、また別の機会にでも頑張るとする。

このスクラップは2ヶ月前にクローズされました