Linuxというかlinux-nextですが、リポジトリ内のファイルをオリジナルから変更してビルドした場合、バージョン情報の最後に -dirtyが付きます。あれはどうやっているのだろう??と気になりました。
Makefileを眺めていると、scripts/setlocalversionというスクリプトでローカルバージョンを付与しているように見えます。
試しにcleanなリポジトリでscripts/setlocalversionを実行すると、-next-20191009のようなlocalversionのみ(※)が表示され、ファイルを適当に書き換えてから実行すると、-next-20191009-dirtyになりました。このスクリプトで当たりっぽいです。
もしLinux Upstreamカーネルで試す場合は、CONFIG_LOCALVERSION_AUTOをyにして、make prepareを実行する必要があります。そうしないとscripts/setlocalversionを実行しても "+" しか表示されません。
(※)この文字列はトップディレクトリのlocalversion-nextというファイルに書いてあります。
スクリプトsetlocalversionを追いかけてみるとgit --no-optional-locks status -uno --porcelainで変更を検知して、-dirtyを出力するかどうか決めていました。オプション --porcelainのヘルプを見ると「スクリプトなどで処理しやすい形式でstatusを出力する」とのことです。へえー、こんなのあるんだ。初めて知りました。
オプション --no-optional-locksはロックを取らずに実行するという意味です。ヘルプ曰く、バックグラウンドでstatusを実行する際に、他のgit statusプロセスと衝突するので、指定した方が良いとのこと。手動で使うことはなさそうだし、気にしなくて良いでしょう。
オプション-unoは --untracked-files=noの省略形です。効果は実際に見た方が早いです。以下をご覧ください。
#### scripts/setlocalversionを書き換え $ vim scripts/setlocalversion #### 未追跡ファイルaaaを作成 $ touch aaa
上記の変更を加えたうえで、オプション -unoなし、オプション -unoありで、それぞれ実行してみます。
$ git status --porcelain M scripts/setlocalversion ?? aaa $ git status -uno --porcelain 下記と同じ $ git status --untracked-files=no --porcelain M scripts/setlocalversion
見た目で明らかだとは思いますが、オプション -unoが指定されていない場合は、未追跡のファイルaaaも表示されますが、-unoを指定すると未追跡のファイルは無視します。
スクリプト内でGitリポジトリが変更されたか?されていないか?を判定する必要は、普通の人はほぼ無いと思うんですけど……、もし必要が生じたら、sedとかgrepとかでゴチャゴチャやらずに、オプション --porcelainを使いましょう。
最近、会社でCI/CDで自動化のマネごとを始めました。といっても大したことはなくて、ビルドしてDebianやRPMパッケージを作って、Webサーバーにぶっこむだけです。
Nightlyビルドのパッケージを作成する際に、パッケージ名の最後にGitのコミットIDを付加しようと思ったのですが、方法が分かりません。調べてみるとrev-parseというコマンドを使うそうです。知らなかった。
$ git rev-parse HEAD 5ab7d0ae0c170fc0409d564fe945aac5ce54f86c $ git rev-parse --short HEAD 5ab7d0ae0c1
ID全部だと長すぎるため --shortオプションを使うとより良いです。
あの台風15号(Faxai)(2019年9月8日の日記参照)を超える、かつてない規模の台風19号(Hagibis)が来るということで、窓にガラス飛散防止でダンボールを貼ってみたり、食料、水を買い込んで備えていました。
都内だと多摩川沿いの一部堤防のない地域が水浸し、東日本だと長野、宮城が洪水で大変なことになっているそうで、東京の治水事業には感謝しかありません。
我が家からはやや遠いですが、最寄りの大きな川といえば多摩川です。水位が大変なことになっていて、思わずスクリーンショットを撮ってしまいました……。
我が家は北と東に窓がありまして、台風15号のときは北からガンガン風と雨が吹き付けていたため、あまりの風圧に、雨が窓サッシの隙間から侵入していました。壁に飛来物が当たり、ものすごい音もしていました(窓の真横に当たり、窓にはギリギリ当たらず本当に幸運だった)。今回はどうやら西、ないし、南から吹き付けていたようで、15号のときほど被害はありませんでした。
今回は全体的に幸運でしたが、災害への備えは日頃からやっておいて損はないですね。
家の外にある家財は車くらいしかないので、台風が過ぎた後に見に行ってみましたが、特に飛来物が当たった形跡もなく、何ともなかったです。良かった良かった。
目次: RISC-V
相変わらず空き時間にRISC-Vのエミュレータを書いています。RV64IMACくらいが必要なのですが、意外と命令の種類が多くていっぺんにやるのは面倒なので、HiFive Unleashedのファームウェアを動かしてみて、足りない命令から実装していくスタイルで開発しています。
HiFive Unleashedの電源を入れたときに真っ先に起動してくるファームウェアというかブートローダはZSBL(Zeroth Stage Boot Loader), FSBL(First Stage Boot Loader)という名前です。
なんと親切なことにソースコードが公開されています(GitHub - Freedom U540-C000 Bootloader Codeのリンク)。素晴らしいですね……。
なぜかUnleashedから引っこ抜いてきたバイナリと、手元でコンパイルしたZSBL, FSBLのバイナリが一致しません。何か間違っているのかも?ちょっと気になります。しかしながら、ソースコードが公開されている意義は非常に大きいです。
メモリマップも公開されています。SiFive Freedom U540 SoCのサイトからダウンロードできます。
U540のマニュアルによると、リセット直後のPCは0x1004で、その後はMSELの値を見て、適切な場所に飛ぶとあります。MSELというのは、Unleashedボード上のDIPスイッチのことです。購入後、変えていなければ状態だと全部ON、つまり0xfになっていると思います。
リセット直後に実行される領域の周辺バイナリをダンプしてみましょう。ダンプには拙作のmemaccess(GitHubへのリンク)を使っています。
# ma db 0x1000 0x40 00001000 0f 00 00 00 97 02 00 00 03 a3 c2 ff 13 13 33 00 00001010 b3 82 62 00 83 a2 c2 0f 67 80 02 00 00 00 00 00 00001020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00001030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00001040
何かが書いてあるようですが、RISC-Vのバイナリがスラスラ読めるほど達人ではないので、ファイルにダンプして逆アセンブルします。
$ riscv64-unknown-elf-objdump -EL -D -b binary -m riscv:rv64 --adjust-vma=0x1000 reset.bin reset.bin: file format binary Disassembly of section .data: 0000000000001000 <.data>: 1000: 0000000f fence unknown,unknown 1004: 00000297 auipc t0,0x0 1008: ffc2a303 lw t1,-4(t0) # 0x1000 100c: 00331313 slli t1,t1,0x3 1010: 006282b3 add t0,t0,t1 1014: 0fc2a283 lw t0,252(t0) 1018: 00028067 jr t0 ...
先頭が変な命令に見えますが、これは命令ではなくMSELです。値は先程も言ったとおり0xfです。実行されるのは0x1004からです。大した量でもないし、1行毎に見ていきます。
参考として、アドレス0x1178に何が書いてあるか示しておきます。付近の領域0x1100〜0x1180にはMSELの値に応じたジャンプ先のアドレスが書いてあります。MSELが他の値になったらどこにジャンプするか、眺めてみると面白いかと思います。
# ma dd 0x1100 0x80 00001100 00001004 00000000 20000000 00000000 00001110 30000000 00000000 40000000 00000000 00001120 60000000 00000000 00010000 00000000 00001130 00010000 00000000 00010000 00000000 00001140 00010000 00000000 00010000 00000000 00001150 00010000 00000000 00010000 00000000 00001160 00010000 00000000 00010000 00000000 00001170 00010000 00000000 00010000 00000000 ★0x1178には0x10000が書いてある 00001180
マニュアルの言うとおり、MSELが0xfの場合、リセット後ZSBLにジャンプ、アドレスで言うと0x10000にジャンプすることが確認できました。
以降も同様に0x10000付近をダンプし、逆アセンブルしたり、エミュレータに実行させてみたりして、開発を進めています。今はZSBLは通過して、FSBLの先頭の方まで実行できるようになりました。いうなれば、砂山にトンネルを掘っているような気分でしょうか、なかなか面白いです。
通常は逆アセンブルだけだと処理の意図を掴むことが難しいですけども、その点U540はソースコードが読めるため、当たりを付けることが比較的容易です。しばらくは素敵なおもちゃになりそうなボードです。
ここしばらく更新されていなかったlinux-nextが約10日ぶりに更新(9/4の次が9/15)されたので、喜んでgit fetchしてTinker Boardのカーネルを書き換えたところ、ウンともスンとも言わなくなってしまいました。
質の悪いことにエラーメッセージも何も出さずにハングアップするため、起動しなくなった原因がさっぱりわかりません。
仕方ないので頑張ってgit bisectし、起動しなくなった原因のコミットを見つけましたが、実は9/17にLKMLにて既に指摘済みで、直し方まで検討されていました(LKMLへのリンク)。今までの苦労は何だったのか。
結果だけ見ると、最初にLKMLのメールスレッドに気づいていればbisectなんて不要でした。しかし、一切エラーメッセージを出さずにハングするので、検索のヒントがありません。ノーヒントでLKMLの当該メールスレッドを探せたか?と考えてみると、ちょっと難しい気がします。
いわゆる鶏と卵の問題ですね……。
シェルからmakeに渡す環境変数とmake変数の関係を知らなくて、かなりハマったのでメモしておきます。
まず、どういう関係か説明します。下記のようなMakefileを2つ用意します。
$ tree . |-- Makefile `-- sub `-- Makefile
VAR_A = aaa
VAR_B = bbb
all:
@echo "In parent"
@echo "VAR_A: '$(VAR_A)'"
@echo "VAR_B: '$(VAR_B)'"
@echo "VAR_C: '$(VAR_C)'"
make -C sub
all:
@echo "In sub"
@echo "VAR_A: '$(VAR_A)'"
@echo "VAR_B: '$(VAR_B)'"
@echo "VAR_C: '$(VAR_C)'"
親Makefileは変数VAR_A, VAR_Bを書き換え、子sub/Makefileを再帰的に呼び出します。各Makefileでは変数の値を表示しています。
では、トップディレクトリにてmakeを実行してみましょう。
$ make In parent VAR_A: 'aaa' ★VAR_Aは設定した値になっている★ VAR_B: 'bbb' ★VAR_Bは設定した値になっている★ VAR_C: '' ★VAR_Cは特に書き換えていないので空★ make -C sub make[1]: Entering directory '/home/katsuhiro/share/falcon/projects/c/makefile_env_var/sub' In sub VAR_A: '' ★VAR_Aは渡されない★ VAR_B: '' ★VAR_Bは渡されない★ VAR_C: '' ★VAR_Cは渡されない★ make[1]: Leaving directory '/home/katsuhiro/share/falcon/projects/c/makefile_env_var/sub'
ご覧の通り、親のMakefileで値を設定したVAR_AやVAR_Bといった変数は、子のsub/Makefileに「引き継がれません」。
外部からmakeに変数を渡すには、下記の2つの方法があります。
私は今まで、この2つの渡し方に何も差はないと思っていたのですが、実は全く動きが違いました。
下記のようにVAR_A, VAR_Cを環境変数として与えると、子Makefile側の結果がかなり変わります。
$ VAR_A=A VAR_C=C make In parent VAR_A: 'aaa' ★VAR_Aは親が設定した値になる★ VAR_B: 'bbb' VAR_C: 'C' ★VAR_Cは特に書き換えていないので、渡された値のまま★ make -C sub make[1]: Entering directory '/home/katsuhiro/share/falcon/projects/c/makefile_env_var/sub' In sub VAR_A: 'aaa' ★VAR_Aが渡される、Aではなく親が設定した値aaaになっている★ VAR_B: '' VAR_C: 'C' ★VAR_Cが渡される、値は変わらず★ make[1]: Leaving directory '/home/katsuhiro/share/falcon/projects/c/makefile_env_var/sub'
何も渡さなかった場合の実行結果と異なり、子のsub/MakefileにもVAR_A, VAR_Cが渡されます。もし、親Makefileが変数の値を書き換えた場合は、書き換えた値が子Makefileに渡されます。
この動作は知りませんでした。特に子プロセスへの変数の渡し方が変わる点が衝撃的です。
下記のようにVAR_A, VAR_Cをmakeに渡すと、環境変数として渡す場合とは違う結果になります。
$ make VAR_A=A VAR_C=C In parent VAR_A: 'A' ★VAR_Aは親が設定した値にならない★ VAR_B: 'bbb' VAR_C: 'C' make -C sub make[1]: Entering directory '/home/katsuhiro/share/falcon/projects/c/makefile_env_var/sub' In sub VAR_A: 'A' ★VAR_Aが渡される、VAR_Aは親が設定した値にならない★ VAR_B: '' VAR_C: 'C' ★VAR_Cが渡される、値は変わらず★ make[1]: Leaving directory '/home/katsuhiro/share/falcon/projects/c/makefile_env_var/sub'
環境変数で渡した場合と同様に、子Makefileに変数の内容が渡されます。その点は同じです。しかし、親Makefileで行っているaaaという値の代入が無効化され、渡される値が全く違います。
この動作も知りませんでした……。私はMakefileやmakeとは長い付き合いですし、動きも何となくわかっていた気分になっていましたが、勘違いだったようです。makeは難しすぎます。
この動きによって、何が困ったかを紹介しておきます。同じ状況に陥る人は、まずもっていないと思いますけど、ご参考まで。
現象としては「makeでビルドすると成功するが、debuild(Debianのパッケージング作成スクリプト)経由でビルドすると失敗する」です。この現象から原因が予想できた人、あなたは凄い(少なくとも私より凄い)です!この先は読む必要はございません。
下記のような感じの、ちょっと変わったMakefileを使っているソフトウェアをビルドしていました。
もう一つ大事な点は、親Makefileが使っているLDFLAGSを、子 ./configureに渡すと「そんなライブラリはないというエラー」になってしまう欠点があることです。
じゃあビルドエラーが起きるのか?というとそうではなく、先ほどご紹介した通り、何も指定せずにmakeを起動すれば、親Makefileの変数は、子 ./configureに渡りませんから、makeだけ実行すればエラーを起こさずビルドできるのです。
一見、正常にビルドできて問題ないように見えますが、このソフトウェアを *.debにパッケージングしようとするとハマります。Debianのパッケージ作成スクリプトdebuildは下記のような動作をするからです。
そろそろ何が起きるか予想が付くでしょう。そう、こうなるんです。
この華麗なコンボが決まって、makeとするとビルドが成功し、debuild経由だとビルドが失敗する、謎のビルド環境ができあがります。
こんなバグ、初見で分かる、はずもなし。
Makefileは大抵の人には難しすぎます。Makefileを手で書いているといつか地獄に落ちますよ、CMakeとかautomakeを使いましょう。便利だよ!
< | 2019 | > | ||||
<< | < | 10 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | 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 | - | - |
合計:
本日: