住んでいる賃貸アパートのガスが、都市ガス(大阪ガス株式会社)から、いわゆるプロパンガス(帝燃産業株式会社)に切り替わりました。
腐っても国道沿いですし、一応は都市部に分類される地域のはずですから、プロパンから都市ガスに切り替わるならまだしも、その逆というのはあまり聞いたことがないのですが…。
筑波に居た時はプロパンでしたが、ガス代が妙に高かった印象しかありません。今は 3,000〜7,000円程度で済んでいるガス代が、来月以降どれほど跳ね上がるやら、恐ろしい限りです。
何となく都市ガスとプロパンガスって呼んでますが、そもそも何が違うのか?が気になったので、調べてみました。
都市ガスは液化天然ガス(LNG, Liquefied Nature Gas)といってメタンを主成分(90%以上がメタン)とするガスです。メタン 100%だと火力が弱いので、ブタンやプロパンを後から足して、火力を強くするそうです。
我が家に来ていた都市ガスは 13A という、一番発熱量が高く(13)一番燃焼が遅い(A)タイプです。1m^3 のガスを燃焼させると 45MJ の熱量が得られます。
参考: 東京ガス: ガスご利用ガイド/都市ガスの熱量・圧力・成分
ガス器具に「プロパン用」「13A 用」などと書いてある理由は、この発熱量と燃焼速度にあるそうです。例えば 13A 用のガス器具に想定していない燃焼速度のガス(例えば 6C など)を使うと、燃えるのが速すぎて、本来ガスが燃えるべきではない場所で燃えてしまい、器具の異常加熱や事故に繋がります。
一方のプロパンガスは液化石油ガス(LPG, Liquefied Petroleum Gas)といってプロパンを主成分としたブタンとの混合ガスです。プロパン 100%ではないので、プロパンガスという呼び方は本来正しくないようですが、何を今更…な感があります。
我が家に来ている LPG は家庭用なので恐らく「い号液化石油ガス」という、プロパンの含有量が最も高いタイプです。1m^3 のガスを燃焼させると約 100MJ の熱量が得られますので、単純な火力としては都市ガスよりも上です。でも単価が高いから相殺されます。
参考: 日本 LP ガス協会: LP ガスの概要: LP ガスの規格
参考: 経済産業省 〜LP ガスを安全に使うために、LP ガスの基礎知識〜
前々から感じていたのですが、この 2者は非常に相性が悪いと思います…。
例えば git clone してきたリポジトリを ./configure && make とすると、
という訳の分からない挙動をすることがあります。これは git clone 時に Makefile.am などのタイムスタンプが変化してしまい、make が勘違いして、ファイルが更新されたよ!依存するファイルを再作成しなければ!というアクションを起こしてしまうせいです。
これがもし tarball で展開したコードであれば taball 作成時のタイムスタンプが復元されますので、この現象は起きません(tarball の作成者がヘマしていなければ、ですが)。
スマートな解決方法は「make がファイルの変化を検知する方法を変える」ことです。恐らく make がファイルの変化を検知したい理由はたった 1つで、
ただこれだけです。タイムスタンプを使うのは手段の一つに過ぎず、2ファイル間の新旧を判別できれば、タイムスタンプでなくても構わないはずです。
この日記のもとになった Facebook のエントリでは「タイムスタンプではなく、ファイルシステムが持っているブロックのハッシュ値が良いんじゃないか?」というコメントをいただきました。
前回の make 起動時と、今回の make 起動時の全ファイルのハッシュ値を記録しておけば、前回と変化したかどうか?はわかるし、ハッシュ再計算のコストがやや心配ですが、ファイルシステムが持っている値などを使えば抑えられる気がします。後は 2ファイル間の順序関係を知る方法があれば、タイムスタンプの代わりになり得ると思います。
しかし、こんなの誰でも考え付きそうな話ですが、既に作られていたりしませんかねー…?
とはいえ、現状では make 以外の選択肢がありません。その場しのぎではありますが、力ずくで解決してみようと思います。
お題は git clone した後などタイムスタンプがメチャクチャになった状態でも、autotools が再実行されないようにするには、どうすれば良いか?です。
まずは autotools ってそもそも何なのか?を調べてみます。適当に autotools を使っているプロジェクトを持ってきて、autoreconf を実行したときの動きを見ます。環境は Debian 8.0 (Jessie, i386) です。
$ autoreconf --force -v 2>&1 | egrep ^autoreconf autoreconf2.50: Entering directory `.' autoreconf2.50: configure.ac: not using Gettext autoreconf2.50: running: aclocal --force ★★こいつ★★ autoreconf2.50: configure.ac: tracing autoreconf2.50: configure.ac: adding subdirectory component/empty to autoreconf autoreconf2.50: Entering directory `component/empty' autoreconf2.50: configure.ac: not running libtoolize: --install not given autoreconf2.50: running: /usr/bin/autoconf --force ★★こいつ★★ autoreconf2.50: running: /usr/bin/autoheader --force ★★こいつ★★ autoreconf2.50: running: automake --force-missing ★★こいつ★★ autoreconf2.50: Leaving directory `component/empty' autoreconf2.50: Leaving directory `.'
結果を見た感じでは、実行されるツールは 4つ aclocal, autoconf, autoheader, automake です。
次にこれらのツールが再実行される仕組みを追うため、./configure 実行後に生成される Makefile を見てみます。
まずは aclocal から。
top_srcdir = .
srcdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
$(am__aclocal_m4_deps):
ルールによれば aclocal.m4 > configure.ac であれば、つまり aclocal.m4 の方が新しければ aclocal は再実行されません。
ちなみに m4 ディレクトリに追加の .m4 ファイルを入れている場合は am__aclocal_m4_deps に m4 ディレクトリ内の .m4 ファイルが並びます。従って aclocal.m4 > configure.ac, (追加の .m4 ファイル) という関係になります。
続けて autoconf です。
top_srcdir = .
srcdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
$(top_srcdir)/configure: $(am__configure_deps)
$(am__cd) $(srcdir) && $(AUTOCONF)
ルールによれば configure > configure.ac, aclocal.m4 であれば、autoconf は再実行されません。
どんどん行きましょう。続けて autoheader です。
top_srcdir = .
srcdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
$(srcdir)/config.h.in: $(am__configure_deps)
($(am__cd) $(top_srcdir) && $(AUTOHEADER))
rm -f stamp-h1
touch $@
最後に touch $@ しているのが特徴的です。どうも autoheader は生成した内容と、既にあるファイルの内容に差が無ければ config.h.in を一切書き換えない、という妙な作りになっているらしく、この autoheader 再実行ルールが適用されても config.h.in のタイムスタンプが更新されない場合があります。
もしタイムスタンプが更新されないと make は毎回この autoheader 再実行ルールを適用してしまいますので、無駄を避けるために touch して config.h.in のタイムスタンプを強制的に更新し、次回以降の autoheader 再実行を回避していると思われます。
他のツールは強制的に書き換えに行くんですが、なぜ autoheader だけ仕様が違うんだろう…??
ま、それはさておき、ルールによれば config.h.in > configure.ac, aclocal.m4 であれば、autoheader は再実行されません。
最後に automake です。
top_srcdir = .
srcdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
$(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign Makefile
ルールによれば Makefile.in > Makefile.am, configure.ac, aclocal.m4 であれば、automake は再実行されません。
今までのルールをまとめると、下記のようになります。
全部まとめると Makefile.in > Makefile.am, configure, config.h.in > aclocal.m4 > configure.ac であれば autotool は一切、再実行されない、と思われます。
だからどうしたら良いんだ!俺は忙しいんだぞ!!という超短気な人のため、autotools の怒りを避けるためのビルド用のシェルスクリプトも付けておきます。
#!/bin/sh
# Prevent the autotools running...
touch aclocal.m4
touch config.h.in
touch configure
touch Makefile.am
touch src/Makefile.am
### もし他のサブディレクトリに Makefile.am があればそれも
### find -name Makefile.am | xargs touch でも良いかもしれない
touch Makefile.in
touch src/Makefile.in
### もし他のサブディレクトリに Makefile.in があればそれも
### find -name Makefile.in | xargs touch でも良いかもしれない
# Build
./configure
make
本当にこの節しか読まない人に注意しておくと、このスクリプトは現在の autotools の実装に依存していますので、将来 autotools の実装が変わると、動かなくなる可能性が非常に高いです。動かなくなっても泣かないでください。
こういうダーティーハックは個人的には面白いから好きですが、苦労の割には利益が無いと思いました。
数年もすればこの手のハックは動かなくなるので周りに迷惑ですし、後進の人がメンテしようにも意味不明で「シバくぞゴラァ!書いた奴出てこいやー!!」ってキレること請け合いです。
鼻と耳は繋がっているから、鼻にイヤホン挿したら聞こえるというからやってみたけども、何も聞こえませんでした。
ウォークマンを最大音量にすれば聞こえますが、鼻に刺しても挿さなくても聞こえる音量は変わりません。
鼻詰まってるからかな?と思って、鼻かんでからやってみたけどやっぱり聞こえません。
もしかして「うわ、あいつ本当にやってるよ、バーカバーカwww」的な冗談だったのかなあ??
メモ: 技術系?の話は Facebook から転記しておくことにした。
巨大なプロジェクト(Android など)をコンパイルするときに欠かせない ccache というツールがあります。
簡単に説明すると、過去にコンパイルした結果をキャッシュデータとして保存しておき、一致する場合はコンパイルをスキップして、結果をキャッシュデータから引き出してくるツールです。
使い方は大きく分けて 2つあって、1つは環境変数や Makefile などを書き換えてコンパイラの名前を変更する方法です。
例えば今まで gcc hoge.c としていたところを ccache gcc hoge.c と書き換えたり、make としていた部分を CC='ccache gcc' make とします。簡単ですが透過性が無いのが欠点で、そこらじゅうの Makefile を変えて回るのは非常に大変だろうことは、容易に想像できるかと思います。
もう 1つはコンパイラの起動をフックする方法です。ccache はシンボリックリンク経由で起動された場合、シンボリックリンクの名前に該当するコンパイラを探して起動する、という動作をします。やることとしては、
例えば /usr/bin/gcc のコンパイル結果をキャッシュするなら…、
$ which gcc /usr/bin/gcc $ ln -s /usr/bin/ccache ~/bin/gcc $ export PATH=~/bin:$PATH $ which gcc /home/katsuhiro/bin/gcc
このようにします。また ccache -s でどれくらいキャッシュが効いているかを見ることができますので、実際キャッシュ出来ているかどうかを見てみます。
$ echo 'int main;' > a.c $ ccache -s cache directory /home/katsuhiro/.ccache cache hit (direct) 0 cache hit (preprocessed) 0 cache miss 0 files in cache 0 cache size 0 Kbytes max cache size 1.0 Gbytes $ gcc -Wall a.c -c -o a.o a.c:1:5: warning: ‘main’ is usually a function [-Wmain] int main; ^ $ ccache -s cache directory /home/katsuhiro/.ccache cache hit (direct) 0 cache hit (preprocessed) 0 cache miss 1 ★★キャシュから結果を返せなかった★★ files in cache 3 cache size 12 Kbytes max cache size 1.0 Gbytes $ gcc -Wall a.c -c -o a.o a.c:1:5: warning: ‘main’ is usually a function [-Wmain] int main; ^ $ ccache -s cache directory /home/katsuhiro/.ccache cache hit (direct) 1 ★★キャシュから結果を返せた★★ cache hit (preprocessed) 0 cache miss 1 files in cache 3 cache size 12 Kbytes max cache size 1.0 Gbytes
きちんと働いてくれていそうです。
で、今日の本題なんですが、会社で ccache が動かないというので相談を受けて見に行ったら、確かに PATH をどう設定しても「コンパイラが見つからない」というエラーが出ていました。
散々悩んで辿り着いた答えは CCACHE_PATH 環境変数でした。man ccache とすると、しっかり説明が載っています。
この名前だけ聞いて、ああ、あれね?とわかる方は、かなり ccache を使い慣れている方だと思います。恥ずかしながら、わたくし全く知りませんでした…。
先の節で説明した 2つ目の方法で ccache を起動すると、ccache は PATH に列挙されたディレクトリからコンパイラを探そうとします。
しかし実はこの挙動は CCACHE_PATH という環境変数により変えることができて、もし CCACHE_PATH という環境変数が定義されていた場合、ccache は PATH の代わりに CCACHE_PATH に列挙されたディレクトリからコンパイラを探そうとします。
相談されたエラーは間違って CCACHE_PATH が定義してしまい、さらに CCACHE_PATH で何もないディレクトリを指していたため、ccache が「コンパイラが無いですねー?」とエラーを出していたのでした。
$ gcc gcc: fatal error: no input files compilation terminated. $ export CCACHE_PATH=/usr $ gcc ccache: FATAL: Could not find compiler "gcc" in PATH ★★コンパイラが見つからないと言っている★★ $ unset CCACHE_PATH $ gcc gcc: fatal error: no input files compilation terminated.
わかっていれば、何だ、そんなこと…というレベルの話ですが、意外とハマって苦戦したので、思い出として書き残しておきます。
先日(2015年 5月 8日の日記参照)の日記で壊れているのかと思っていた Globalsat BU-353-S4 ですが、実は壊れていませんでした。
GPS 受信機が受信状態を伝える通信方式には、NMEA 0183 という規格に基づいたテキストデータで送ってくるか、GPS の受信機メーカー独自のバイナリデータで送ってくるか、の 2つがあるようです。
恐らく大抵のメーカーは両方に対応しており、NMEA か、メーカー独自バイナリかが選択できます。もちろん Globalsat BU-353-S4 が採用している SiRF Star IV もどちらかを選ぶことができます。
どうも色々いじっているうちにバイナリモードになってしまっていたらしく、NMEA を期待していた GPS のデータ表示アプリなどが「何言ってるのかわからんわ、このデバイス」状態に陥っていました。故障じゃなくて良かったです。
stty -F /dev/ttyUSB0 ispeed 4800 && cat < /dev/ttyUSB0 $GPGSA,A,1,,,,,,,,,,,,,,,*1E $GPGSV,3,1,12,01,00,000,,02,00,000,,03,00,000,,04,00,000,*7C $GPGSV,3,2,12,05,00,000,,06,00,000,,07,00,000,,08,00,000,*77 $GPGSV,3,3,12,09,00,000,,10,00,000,,11,00,000,,12,00,000,*71 $GPRMC,,V,,,,,,,,,,N*53 ...
もし上記のようにテキストデータが受信されれば NMEA モードになっています。もしグチャグチャの字が受信されるときは、ボーレートが間違っているか、バイナリモードになっている可能性が高いです。
GPS データの通信方式を切り替えるには gpsctl というコマンドを使います。GPS デバイスが /dev/ttyUSB0 として認識されているとして、
# to NMEA gpsctl -f -n /dev/ttyUSB0 # to Binary gpsctl -f -b /dev/ttyUSB0
オプション -n は NMEA モードにする、-b はバイナリモードにするという意味で、-f はローレベル(gpsd を介さないという意味らしい)で GPS デバイスにアクセスするという意味です。
ちなみに SiRF Star IV はモード切り替えに数秒〜10秒近くの時間がかかることがあります。さすが「絶対買わない方が良いぜ」と言われるだけのことはある…。
これで終わりだとあまり面白くなかったので、Globalsat BU-353-S4 の通信方式を gpsctl -n 以外で切り替える方法も試してみます。
ありがたいことに Globalsat US のサイトから SiRF バイナリデータの仕様書を入手できますので、NMEA モードへの切り替えコマンドを送ってみようと思います。仕様書のダウンロードはこちらのサイトの「SiRF Binary Protocol Document」からできます。
ちなみに仕様書の「Switch To NMEA Protocol – Message ID 129」にそのまま使える例が載っていますので、これをそのまま送ってみます。
このデータをバイナリエディタなどでファイル(to_nmea というファイル名だとします)に書いておき、
# gpsctl -f -b /dev/ttyUSB0 /dev/ttyUSB0 identified as a SiRF 9GSD4e_4.1.2-B2_RPATCH.02-F-GPS-4R-1301151 01/17/2013 017 at 9600 baud. gpsctl:SHOUT: switching to mode BINARY. falcon:~# stty -F /dev/ttyUSB0 ispeed 9600 && cat < /dev/ttyUSB0 | hexdump -C 00000000 a0 a2 00 29 02 00 00 00 00 00 00 00 00 00 00 00 |...)............| 00000010 00 00 00 00 00 00 00 00 00 00 03 36 02 6a 9c 5a |...........6.j.Z| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 01 9d b0 |................| 00000030 b3 a0 a2 00 09 09 00 00 00 00 00 00 00 00 00 09 |................| ... # cat to_nmea > /dev/ttyUSB0 # stty -F /dev/ttyUSB0 ispeed 9600 && cat < /dev/ttyUSB0 $GPGGA,163721.731,,,,,0,00,,,M,0.0,M,,0000*53 $GPGSA,A,1,,,,,,,,,,,,,,,*1E $GPRMC,163721.731,V,,,,,,,280515,,,N*43 ...
以上のようにバイナリを GPS デバイスに送りつけると、無事 NMEA モードに切り替わります。ちなみに上記の設定例だとボーレートが 4800bps から 9600bps に変わってしまうので注意してください。
合計:
本日:
< | 2015 | > | ||||
<< | < | 06 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | 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 | - | - | - | - |
管理者: Katsuhiro Suzuki(katsuhiro( a t )katsuster.net)
This is Simple Diary 1.0
Copyright(C) Katsuhiro Suzuki 2006-2016.
Powered by PHP 5.2.17.
using GD bundled (2.0.34 compatible)(png support.)