autom4te
アップルパイ
リンゴが2個100円とかで手に入る。規格品以外の跳ね出しだから安い。大体は美味しく食べられるんだけど、中には、味がボケてて、食べる気がしないのもある。そういうのは、100%果汁ジュースにしちゃうんだけど、たまにはアップルパイに挑戦すると女房が言い出した。
パイ生地は、パンプキンパイ用に常備してる。かぼちゃもホクホクじゃないと、スープになったり、パイにしたりしてるからね。
で、アップルパイ用に、レモンとブランデーを買いに行かされましたよ。調理用ってかケーキ用に売ってるのね、知らなかった。
初めてにしては上出来。また、作ってね。
C語のマクロ
rubyのソースrandom.cを見ていたら
#if ! defined HAVE_GETRANDOM && defined __linux__ && defined __NR_getrandom # ifndef GRND_NONBLOCK # define GRND_NONBLOCK 0x0001 /* not defined in musl libc */ # endif
こんな書きかたをしたマクロが出てきた。何が目新しいかと言うと、# ifndefとか# defineみたいに、間に、空白を入れてる事。今迄は、ぴったりくっつけるものとばかり思ってた。 ネストを表現する為に、字下げしてるのね。
それもこれも、プリプロセッサーが良きに図らってくれるから。そもそも、プリプロセッサーが働くと#な行は、取り除かれてしまうからね。また、#が存在する行だけに注目すればいいので、解析が楽になるって事もあるな。
そもそも、# を、コメント記号に決めたのは、世界最古のインタープリタshell scriptに違いない。だから、OSにも取入れられている(#! /usr/bin/ruby みたいな奴)。 この流れを汲んでいるんだな。設計はあの人だしね。
で、こういう風になってるやつの、#if … #elif … #endif みたいなのの構造を追跡しようとすると、ちと面倒。
sakae@deb:/tmp$ grep -n '#' random.c | sed -E -e 's/# +/#/' | egrep '(#if|#el|#end)' : 478:#if 0 479:#elif defined MAC_OS_X_VERSION_10_7 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7 488:#if 0 494:#endif 499:#elif defined(HAVE_ARC4RANDOM_BUF) 503:#if (defined(__OpenBSD__) && OpenBSD >= 201411) || \ 508:#else 510:#endif 512:#elif defined(_WIN32) 550:#elif defined HAVE_GETRANDOM 573:#else 575:#endif
emacsで簡単に追跡出来無いものかしら。
autoconf
autoconfした時に、どのように動くか追ってみる
vbox$ sh -x /usr/local/bin/autoconf-2.69 : + test -f configure.ac + test -f configure.in + infile=configure.ac + test -z + test -z + outfile=configure + test -z configure + eval set x --language=autoconf --output="$outfile" "$infile" + set x --language=autoconf --output=configure configure.ac + shift + false + exec /usr/local/bin/autom4te-2.69 --language=autoconf --output=configure configure.ac
省略した部分では、随分と色々なチェックをしてたぞ。
vbox$ sh -x /usr/local/bin/autom4te-2.69 --language=autoconf --output=configure configure.ac + eval case $# in 0) exec /usr/bin/perl -S "$0";; *) exec /usr/bin/perl -S "$0" "$@";; esac + exec /usr/bin/perl -S /usr/local/bin/autom4te-2.69 --language=autoconf --output=configure configure.ac
最後はperlさんの登場だ。もうすっかり忘れているぞ。 取り敢えず、下記でも動く事を確認。
vbox$ autom4te-2.69 -l autoconf -o zzz configure.ac
トレースしたいな。 pkg_add p5-Devel-Trace
で、トレーサーを導入。
vbox$ perl -d:Trace -S autom4te-2.69 -l autoconf -o zzz configure.ac
トレースログは3万5千行にもなった。少しソース読んで、perldebug - Perl のデバッグの世話になった方がいいかな?
perl 一夜漬
perlなんて、オイラー的には20年以上も前の言語だ。今更思い出せってか? そんなの一夜漬でいいだろう。
とほほのperl入門 さんはいまだに健在。何かの折に必要になるからね。
ちょいとマニュアルを引くなら
sakae@deb:~$ perldoc -f push
かな。それから、ドットで文字列が結合される。 $_
が暗黙的に使われる。ifは後置出来るぐらいかなあ。
FreeBSDは長らくperl依存症にかかって苦しんでいたけど、努力のかいがあって抜け出せた。OpenBSDは、 pkg_add
が利用してて、ずっとperlに依存。動いているならそれでいいじゃんって態度。自分たちでメンテしてるから、どうにでもなるって思ってる節がある。
腰が座らないのはリナ。流行のpythonがディストリの中心になってるけど、最新に追従するのは辛いだろうよ。FreeBSDはそれがいやでperlをOSから排除したんだった。ユーザーは自衛策で、どんどんOS添付のpythonを見切っているね。
まあ、どうでもいいけど。
本棚をのぞいたら、ほこりを被ったperlポケット・リファレンスなんてのが出てきた。んで、パラパラしてたら、デバッガーの説明が載ってたよ。
sakae@pen:/tmp/t$ perl -d autom4te -l autoconf -o zz configure.ac Loading DB routines from perl5db.pl version 1.57 Editor support available. Enter h or 'h h' for help, or 'man perldebug' for more help. main::(autom4te:5): eval 'case $# in 0) exec /usr/bin/perl -S "$0";; *) exec /usr/bin/perl -S "$0" "$@";; esac' main::(autom4te:6): if 0; DB<1> S main main::BEGIN main::__ANON__[autom4te:362] main::files_to_options main::freeze main::handle_m4 main::handle_output main::handle_traces main::load_configuration main::parse_args main::trace_format_to_m4 main::up_to_date main::warn_forbidden
こんな風に定義されてるサブルーチンを確認出来るとな。これイカシてるな。
DB<2> b main::parse_args DB<3> L autom4te: 308: my @language; break if (1)
ブレークポイントを折角名前で指定したのに、リストをみると消えてる。複数設定したら、ワケワカメ必定だ。
DB<3> c main::parse_args(autom4te:308): my @language; DB<3> n main::parse_args(autom4te:309): do { DB<3> v 306 # definitions. Beware that there can be several --language 307 # invocations. 308:b my @language; 309==> do { 310: @language = (); 311: use Getopt::Long; 312: Getopt::Long::Configure ("pass_through", "permute"); 313: GetOptions ("l|language=s" => \@language); 314 315: foreach (@language) DB<3> n main::parse_args(autom4te:310): @language = (); DB<3> main::parse_args(autom4te:312): Getopt::Long::Configure ("pass_through", "permute"); DB<3> main::parse_args(autom4te:313): GetOptions ("l|language=s" => \@language); DB<3> main::parse_args(autom4te:315): foreach (@language) main::parse_args(autom4te:316): { main::parse_args(autom4te:317): error "unknown language: $_" DB<3> x @language 0 'autoconf'
なんか、日が暮れてしまいそう。
サブルーチンから戻るには、 r すれば良いのは、見付けた。じゃ、下記のようにmapでグダグダやってる場合とか、foreachのループを素早く抜け出すには?
main::(te:95): my @m4_builtin = `echo dumpdef | $m4 2>&1 >/dev/null`; DB<1> main::(te:96): map { s/:.*//;s/\W// } @m4_builtin; DB<1> main::(te:96): map { s/:.*//;s/\W// } @m4_builtin; DB<1> c 120 main::(te:120): my %m4_builtin_alternate_name; main::(te:121): @m4_builtin_alternate_name{"$_", "m4_$_"} = ("m4_$_", "$_")
裏技っぽいけど、c n行 してやればいい。これで、抜けてくれる。なお、抜けて止るべき行は、実行可能な行のみが許されている。v を叩いて、実行文を探そう。長いコメントがあったりすると辟易する事間違いなし。
autom4te -v
ってな事で、マニュアルを眺めていたら、おしゃべりモードを発見。
vbox$ ./te -v -l autoconf -o zz configure.ac >LOG 2>&1
おしゃべりが過ぎるので、取り敢えず、録音した。ああteてやつは、/usr/local/bin/autom4te を手元に持ってきたものだ。
te: the trace request object is: te: $VAR1 = bless( [ te: '0', te: 0, te: [ te: '/usr/local/share/autoconf-2.69' te: ], te: [ te: '/usr/local/share/autoconf-2.69/m4sugar/m4sugar.m4', te: '/usr/local/share/autoconf-2.69/m4sugar/m4sh.m4', te: '/usr/local/share/autoconf-2.69/autoconf/autoconf.m4', te: 'configure.ac' te: ], te: { te: 'AC_CANONICAL_TARGET' => 1, te: '_m4_warn' => 1, : te: 'AC_CANONICAL_HOST' => 1 te: } te: ], 'Autom4te::Request' );
LOGの中身の冒頭部分。なにか、これらのファイルから必要そうなデータを取り出してきましたよって風だ。そして次にあったのは、m4を起動してるやつだ。長いので、分かり易いように整理してみた。(一行野郎なんだけど、分かり易いように行に分解)
/usr/bin/m4 -g -D__gnu__ -I/usr/local/share/autoconf-2.69 -daflq -oautom4te.cache/traces.0t -tAC_CANONICAL_BUILD -tAC_CANONICAL_HOST : -tm4_sinclude -tsinclude /usr/local/share/autoconf-2.69/m4sugar/m4sugar.m4 /usr/local/share/autoconf-2.69/m4sugar/m4sh.m4 /usr/local/share/autoconf-2.69/autoconf/autoconf.m4 configure.ac > autom4te.cache/output.0t
m4sugar.m4やらconfigure.acを材料に変換してね。結果はキャッシュの中のoutput.0に。 指定した複数のマクロを追跡しながら、trace.0へ入れろとな。
traces.0
m4trace:/usr/local/share/autoconf-2.69/m4sugar/m4sugar.m4:2878: -1- m4_sinclude([m4sugar/version.m4]) m4trace:/usr/local/share/autoconf-2.69/m4sugar/m4sugar.m4:2878: -1- sinclude([m4sugar/version.m4]) : m4trace:configure.ac:4: -1- AC_SUBST_TRACE([PACKAGE_VERSION]) m4trace:configure.ac:4: -1- m4_pattern_allow([^PACKAGE_VERSION$]) m4trace:configure.ac:4: -1- AC_SUBST([PACKAGE_STRING], [m4_ifdef([AC_PACKAGE_STRING], ['AC_PACKAGE_STRING'])])
output.0には、変換結果が格納されているんだけど、まだこれは中間結果みたい。
- case `(set -o) 2>/dev/null` in @%:@( + case `(set -o) 2>/dev/null` in #( *posix*) : - set -o posix ;; @%:@( + set -o posix ;; #(
マイナス記号がついてるのは、outputのデータ、プラス記号の方は最終的なconfigureだ。
-v オプションを付けた時、どういう経路でデータが表示されるかは追求出来ていないけど、表示用のそれを見付けた。BPを貼って追跡。
DB<3> b Autom4te::ChannelDefs::verb DB<4> c Autom4te::ChannelDefs::verb(/usr/local/share/autoconf-2.69/Autom4te/ChannelDefs.pm:235): 235: my ($msg, %opts) = @_; DB<4> T @ = DB::DB called from file '/usr/local/share/autoconf-2.69/Autom4te/ChannelDefs.pm' line 235 . = Autom4te::ChannelDefs::verb('formatting traces for `/tmp/am4tUOT3dC/dependencies\': include, m4_include') called from file 'te' line 710 . = main::handle_traces(ref(Autom4te::Request), '/tmp/am4tUOT3dC/dependencies','include', '$1', 'm4_include', '$1') called from file 'te' line 889 $ = main::up_to_date(ref(Autom4te::Request)) called from file 'te' line 992 : DB<4> c te: formatting traces for `/tmp/am4tUOT3dC/dependencies': include, m4_includeAutom4te::ChannelDefs::verb(/usr/local/share/autoconf-2.69/Autom4te/ChannelDefs.pm:235): 235: my ($msg, %opts) = @_; DB<4> T @ = DB::DB called from file '/usr/local/share/autoconf-2.69/Autom4te/ChannelDefs.pm' line 235 . = Autom4te::ChannelDefs::verb('up_to_date (autom4te.cache/traces.0): up to date') called from file '/usr/local/share/autoconf-2.69/Autom4te/FileUtils.pm' line 232 $ = Autom4te::FileUtils::up_to_date_p('autom4te.cache/traces.0', '/usr/local/sha re/autoconf-2.69/m4sugar/m4sugar.m4', '/usr/local/share/autoconf-2.69/m4sugar/m4 sh.m4', '/usr/local/share/autoconf-2.69/autoconf/autoconf.m4', 'configure.ac', ' /usr/local/share/autoconf-2.69/autoconf/autoupdate.m4', '/usr/local/share/autoco nf-2.69/autoconf/autoupdate.m4', '/usr/local/share/autoconf-2.69/autoconf/autosc an.m4', '/usr/local/share/autoconf... called from file 'te' line 907 $ = main::up_to_date(ref(Autom4te::Request)) called from file 'te' line 992 : DB<4> c te: formatting traces for `/tmp/am4tUOT3dC/warnings': _m4_warn Autom4te::ChannelDefs::verb(/usr/local/share/autoconf-2.69/Autom4te/ChannelDefs.pm:235): 235: my ($msg, %opts) = @_; DB<4> T @ = DB::DB called from file '/usr/local/share/autoconf-2.69/Autom4te/ChannelDefs.pm' line 235 . = Autom4te::ChannelDefs::verb('reading /tmp/am4tUOT3dC/warnings') called fromfile '/usr/local/share/autoconf-2.69/Autom4te/FileUtils.pm' line 361 $ = Autom4te::FileUtils::contents('/tmp/am4tUOT3dC/warnings') called from file 'te' line 1008
スタックトレースは T ってコマンドなんだけど、慣れないと表示がみにくいな。余計な英語の説明は必要無いと思うぞ。
vbox$ grep -n verb te 147: -v, --verbose verbosely report processing 517: verb "creating $output"; 530: verb "forbidden tokens: $forbidden"; 531: verb "forbidden token : $_ => $forbidden{$_}" 533: verb "allowed tokens: $allowed"; 710: verb "formatting traces for `$output': " . join (', ', sort keys %trace); 996:verb "the trace request object is:\n" . $req->marshall;
perlは変に括弧を省略出来るんで、サブルーチン呼出がきわだたないな。rubyもこの流儀だったんだね。
autom4te -d
debugオプションが用意されてて、それをつけると一時ファイルが削除されなくなるそうだ。/tmp/am4XXXXXX/ の中に作成されてる。
patterns
forbid:^dnl$: forbid:^_?AS_: allow:^SHELL$ allow:^PATH_SEPARATOR$ allow:^PACKAGE_NAME$
traces.m4
divert(-1) changequote([, ]) # _at_MODE(SEPARATOR, ELT1, ELT2...) # ---------------------------------- # List the elements, separating then with SEPARATOR. # MODE can be: # `at' -- the elements are enclosed in brackets. : define([_at_at], [at_ifelse([$#], [1], [], [$#], [2], [[[$2]]], [[[$2]][$1]$0([$1], at_shift(at_shift($@)))])]) : define([at_flatten], [at_patsubst(at_patsubst([[[$1]]], [\\ ]), [[ ]+], [ ])]) define([at_args], [at_shift(at_shift(at_shift(at_shift(at_shift($@)))))]) define([at_at], [_$0([$1], at_args($@))]) : # Copy the builtins. define([at_undivert], defn([undivert])) define([at_ifelse], defn([ifelse])) :
これらが、どのように使われるか調べると、autoconfとm4の橋渡しが理解出来る(かな)。
perldoc and Pod
autom4teの下請けスクリプトとして、下記のようなものが用意されてる。
[sakae@fb /usr/local/share/autoconf-2.69/Autom4te]$ ls C4che.pm Configure_ac.pm Getopt.pm ChannelDefs.pm FileUtils.pm Request.pm Channels.pm General.pm XFile.pm
それぞれを開いてみると Perl Pod形式で、マニュアルが埋め込まれている事がわかる。折角なのでそれらのマニュアルを読んでみる。
[sakae@fb /usr/local/share/autoconf-2.69/Autom4te]$ perldoc ChannelDefs.pm NAME Autom4te::ChannelDefs - channel definitions for Automake and helper functions SYNOPSIS use Autom4te::ChannelDefs; print Autom4te::ChannelDefs::usage (), "\n"; prog_error ($MESSAGE, [%OPTIONS]); error ($WHERE, $MESSAGE, [%OPTIONS]); error ($MESSAGE); fatal ($WHERE, $MESSAGE, [%OPTIONS]); fatal ($MESSAGE); verb ($MESSAGE, [%OPTIONS]); DESCRIPTION This package defines channels that can be used in Automake to output diagnostics and other messages (via "msg()"). It also defines some : FUNCTIONS "usage ()" Return the warning category descriptions. : "verb ($MESSAGE, [%OPTIONS])" "--verbose" messages.
ワケワカメなコードを読むより、こちらの方が生産的と思うぞ。General.pmを参照したら、
DESCRIPTION This perl module provides various general purpose support functions used in several executables of the Autoconf package. Global Variables $debug Set this variable to 1 if debug messages should be enabled. Debug messages are meant for developers only, or when tracking down an incorrect execution. $verbose Enable verbosity messages. These messages are meant for ordinary users, and typically make explicit the steps being performed.
こんな説明が出てた。これで、automete -v した時のカラクリが分った事にしておこうな。 これ以上の深入りは無駄ってもんです。