ZFS は NFS をサポートしているので、一応使えることを確認しました。
zfs-fuse ではなくて、以前 「zfsを使ってみた」で説明したように ZFS on Linux をインストールしています。
NFSサーバー側の設定
例えば、 tank/home パーティションを作り、 /export/home にマウントし、さらに NFS で共有という例でやってみます。
パーティションを作る。
# zfs create tank/home
マウントポイントを変更
# zfs set mountpoint=/export/home tank/home
RHEL/CentOS の場合、NFS server は標準でインストールされていると思いますが、もしインストールされていなければ、
# yum install nfs-utils
でインストールします。
nfs サービスが起動していることを確認しておきます。
ただし、設定自体は ZFS のプロパティで行うので、 /etc/exports の編集は不要です。
あとは、以下のような感じで sharenfs オプションを指定します。
# zfs set sharenfs="rw=@192.168.11.2,root_squash"
192.1681.11.2 の部分はクライアント側のIPアドレスに置きかえてください。/etc/hostsのホスト名でもOKです。
どうも no_root_squash がデフォルトになっているらしく、
root_squash の指定をしておかないと、クライアントのroot が サーバー側でもroot扱いになってしまう。
したがって sharenfs=on はセキュリティ上脆弱なので、やめておいた方がよいでしょう。
あとはクライアント側からは、以下のような感じでマウントできます。
# mount -t nfs 192.168.11.1:/export/home /mnt/
一応やってはみましたが、自分は NFSv4 を使いたいので、zfs の NFS機能は使わないかも。
2012年12月19日水曜日
Kerberos の ticket lifetime を変更する
Kerberos のチケットのlifetime を短くするのは簡単にできるのに、長くするのはできないなぁと思っていたら、チケットの有効期限は以下の4つの minimum 値で決まるらしい。
(1) サーバー側(KDC) のkdc.conf
RHEL/CentOSなら
/var/kerberos/krb5kdc/kdc.conf の
[realms]セクションのmax_life 設定。
Ubuntuなら
/etc/krb5kdc/kdc.conf にあります。
(2)クライアント側 の /etc/krb5.conf
[libdefaults] セクションの ticket_lifetime 設定
(3)ユーザープリンシパル の maxlife
kadmin: modprinc -maxlife 3day user01
などで変更
(4)サービスプリンシパルの maxlife
kadmin: modpronc -maxlife 3day krbtgt/MYDOMAIN.COM
などで変更します。
なお、addprinc で新しくプリンシパルを作成した時の maxlife の初期値は
kdc.conf の max_life 設定で決まるようです。
(1) サーバー側(KDC) のkdc.conf
RHEL/CentOSなら
/var/kerberos/krb5kdc/kdc.conf の
[realms]セクションのmax_life 設定。
Ubuntuなら
/etc/krb5kdc/kdc.conf にあります。
(2)クライアント側 の /etc/krb5.conf
[libdefaults] セクションの ticket_lifetime 設定
(3)ユーザープリンシパル の maxlife
kadmin: modprinc -maxlife 3day user01
などで変更
(4)サービスプリンシパルの maxlife
kadmin: modpronc -maxlife 3day krbtgt/MYDOMAIN.COM
などで変更します。
なお、addprinc で新しくプリンシパルを作成した時の maxlife の初期値は
kdc.conf の max_life 設定で決まるようです。
2012年12月18日火曜日
2012年12月15日土曜日
2012年12月4日火曜日
2012年11月15日木曜日
2012年11月13日火曜日
2012年11月8日木曜日
2012年11月5日月曜日
RHEL on RAID1 (Intel RST)
以前、「Linuxインストール on RAID5 (Intel RST)」という記事で、RAID5を組んで Linuxをインストールしましたが、別のPCをセットアップする機会があったので、今回はRAID1 を組んでみました。
・ マザー : Intel 「DZ68DB」
・ SSD : Intel 「335 Series SSDSC2CT240A4K5」 × 2台
なんだかんだ言って、マザーは Intel 純正が安心でよいですね。
再び、DiskBのケーブルをつないで、起動させてみます。
Intel Rapid Storage Technology Option ROM の表示では
Status = Degrade となり
DiskB の方は offline member と表示されます。
気にせず、そのまま RHEL を起動します。
・ マザー : Intel 「DZ68DB」
・ SSD : Intel 「335 Series SSDSC2CT240A4K5」 × 2台
なんだかんだ言って、マザーは Intel 純正が安心でよいですね。
前回、RAID5を組んでいるので、手慣れたものです。
BIOS に入り、
Configuration
→ SATA Drives
→ Chipset SATA Mode
で RAID を選択。
BIOSを抜けて、
Ctrl + I を同時押して (Ctrl を押しながら I を押すとダメ)
Intel Rapid Storage Technology Option ROM の設定画面に入ります。
1. Create RAID Volume を選んで、RAID1 を選択です。
続いて、OSをインストールします。Windows はあまり興味が無いので、Linux をインストールします。
各ディストリビューションごとのインストール方法は「Linuxインストール on RAID5 (Intel RST)」で書きました。
今回は RHEL Client v6.3 64bit を入れました。特にRAIDを意識せずに、普通にインストールするだけです。
さて、ここから。
RAID1をいったんぶっ壊して、再構築してみることにします。
RAID1 を構成するディスクを DiskA, DiskB と名付けてます。
まず、DiskBのケーブルを抜いて、DiskA だけで起動させてみます。
まず、DiskBのケーブルを抜いて、DiskA だけで起動させてみます。
普通に起動しました。
ミラーリングですから、まあそうでしょう。
再び、DiskBのケーブルをつないで、起動させてみます。
Intel Rapid Storage Technology Option ROM の表示では
Status = Degrade となり
DiskB の方は offline member と表示されます。
気にせず、そのまま RHEL を起動します。
RHELの
アプリケーション
→ システムツール
→ ディスク・ディスクユーティリティ
でディスクの状態が見れます。
RAIDアレイの項目を見ると、
状態: デグレード状態
アクション: リカバリ中
と表示されています。
自動的に、再構築してくれているみたいです。
再構築にはある程度時間がかかります。
途中で再起動しても大丈夫のようです。
となっています。
自動的に、再構築してくれているみたいです。
再構築にはある程度時間がかかります。
途中で再起動しても大丈夫のようです。
Intel Rapid Storage Technology Option ROMの設定画面に入ると、今度は
Status = Rebuild
Voluemes with "Rebuild" status will be rebuilt within the operating system.
となっています。
1時間ほどで再構築は終了。
確認のため、今度は DiskAのケーブルを抜き、DiskBだけで起動されてみます。
全く問題なし。
再び、 DiskA のケーブルをつなぐと、また勝手に再構築してくれます。
素晴らしいですね。
確認のため、今度は DiskAのケーブルを抜き、DiskBだけで起動されてみます。
全く問題なし。
再び、 DiskA のケーブルをつなぐと、また勝手に再構築してくれます。
素晴らしいですね。
2012年10月16日火曜日
VirtualBox 設定
最初の一回しかやらないので、うっかり忘れやすいのでメモ。
VirtualBox を便利に使うためにやっておくべき設定。
GuestAddiions はインストールしておく。
・ホスト⇔ゲスト間でコピー&ペースト
設定 -> 一般 -> クリップボードの共有 で双方向 を選択
・ホスト⇔ゲスト間でフォルダ共有
設定 -> 共有フォルダー
で追加。
自動マウントにチェックを入れると /media/以下にマウントされた。
特に /etc/fstab などゲストOS側での設定は不要でした。
(ゲストOSがUbuntuの場合に確認)
VirtualBox を便利に使うためにやっておくべき設定。
GuestAddiions はインストールしておく。
・ホスト⇔ゲスト間でコピー&ペースト
設定 -> 一般 -> クリップボードの共有 で双方向 を選択
・ホスト⇔ゲスト間でフォルダ共有
設定 -> 共有フォルダー
で追加。
自動マウントにチェックを入れると /media/以下にマウントされた。
特に /etc/fstab などゲストOS側での設定は不要でした。
(ゲストOSがUbuntuの場合に確認)
2012年10月10日水曜日
LinuxカーネルのMakefileを解析する その8
前回からまたまた間があきました。
今回の話題は O= を付けた時の動作についてです。
ソースを見ていて、あれっ、どうやって動いてるんだっけ?という部分がありましたので記載しておきます。
例えば、Kernel のソースツリーで
$ make O=dir/to/store/output/files/ defconfig vmlinux
とやってみると、
ソースツリーを一切汚すことなく、
dir/to/store/output/files/ に出力結果を置いてくれます。
トップの Makefile の動きは 「LinuxカーネルのMakefileを解析する その1」で解説しました。
今回注目するのは script/Makefile.build です。
例えば、*.c から *.o を生成するサフィックスルールを見てみます。
Makefile.build の300行目過ぎにそれがあります。
今回の話題は O= を付けた時の動作についてです。
ソースを見ていて、あれっ、どうやって動いてるんだっけ?という部分がありましたので記載しておきます。
例えば、Kernel のソースツリーで
$ make O=dir/to/store/output/files/ defconfig vmlinux
とやってみると、
ソースツリーを一切汚すことなく、
dir/to/store/output/files/ に出力結果を置いてくれます。
トップの Makefile の動きは 「LinuxカーネルのMakefileを解析する その1」で解説しました。
今回注目するのは script/Makefile.build です。
例えば、*.c から *.o を生成するサフィックスルールを見てみます。
Makefile.build の300行目過ぎにそれがあります。
# Built-in and composite module parts
$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
これは $(src)/%.c から $(obj)/%.o を生成してくれるルールを表しています。
Makefile.build の先頭に
src := $(obj)
がありますので、src と obj は同じディレクトリを指しています。
O= 指定がないときは、それでいいのですが、O= 指定ありの時は、 *.c と違うディレクトリに *.o を作りたいわけです。
obj と src が同じなのに、どうやって動いてるんだろう??としばらく悩みましたが、その答えはトップの Makefile の 150行目過ぎにある
VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
export srctree objtree VPATH
にあります。
VPATHに $(srctree) が追加されています。
VPATHというのは、make がサフィックスルールにおいて検索するパスを指定するものです。
Cコンパイラでいうところの -I オプションみたいなものといういえばいいでしょうか。
$(obj)/*.o を生成するときに、 $(src)/*.c を探しますが、見つかりません。
次にVPATHで指定されたパスを探しにいき、$(srctree)/$(src)/*.c を使うわけです。
VPATHというのは、私は使わない方がいいと思っている機能なので(どのファイルをコンパイルしているかわかりにくくなる)、うっかり失念しておりました。
2012年10月9日火曜日
make 3.80 と make 3.81 の違い
経験的に以下のような書き方ができることは知っていたけど、
これが許されるのはGNU make version 3.81以降のようだ。
case文みたく、重なりがないことが明らかな場合は以下のようにする方が見やすそうだ。
ifeq ($(FOO),a)
$(warning FOO is a)
else ifeq ($(FOO),b)
$(warning FOO is b)
else ifeq ($(FOO),c)
$(warning FOO is c)
else ifeq ($(FOO),d)
$(warning FOO is d)
endif
make version 3.80 の場合、上記は以下のようにエラーになってしまう。
Makefile:5: FOO is a
Makefile:6: `else' 疑似命令の後ろに無関係な文字列があります
Makefile:8: `else' 疑似命令の後ろに無関係な文字列があります
Makefile:8: *** 一つの条件部につき一つしか `else' を使えません。中止。
ポータビリティのことを考えるなら、以下のように書いた方がよさそうだ。
ifeq ($(FOO),a)
$(warning FOO is a)
else
ifeq ($(FOO),b)
$(warning FOO is b)
else
ifeq ($(FOO),c)
$(warning FOO is c)
else
ifeq ($(FOO),d)
$(warning FOO is d)
endif
endif
endif
endif
しかしこれだと、インデントがないと、わけがわからなくなるな。
ネストが深くなると大変そうだ。
case文みたく、重なりがないことが明らかな場合は以下のようにする方が見やすそうだ。
ifeq ($(FOO),a)
$(warning FOO is a)
endif
ifeq ($(FOO),b)
$(warning FOO is b)
endif
ifeq ($(FOO),c)
ifeq ($(FOO),c)
$(warning FOO is c)
endif
ifeq ($(FOO),d)
ifeq ($(FOO),d)
$(warning FOO is d)
endif
ARM クロスコンパイラをビルドする
普通は Menter Graphics (旧CodeSourcery)からビルド済みのコンパイラをダウンロードする人が多いと思いますが。。
arm-linux-gnueabi-gcc をソースからビルドしてみました。物好きですな。
まずは各種ソースの tarball を入手します。
入手元を併記します。
(1) binutils-2.21.1.tar.bz2 - http://www.gnu.org/software/binutils/ から入手
(2) gcc-4.6.3.tar.bz2 - http://gcc.gnu.org/ から入手
(3) gmp-4.3.2.tar.bz2 - http://gcc.gnu.org/ から入手 (infrastructure の下)
(4) mpc-0.8.1.tar.gz - http://gcc.gnu.org/ から入手 (infrastructure の下)
(5) mpfr-2.4.2.tar.bz2 - http://gcc.gnu.org/ から入手 (infrastructure の下)
(6) linux-3.0.45.tar.bz2 - http://www.kernel.org/ から入手
(7) eglibc-2.13.tar.bz2 - http://www.eglibc.org/ から入手
(7) は公式サイトでtarball を配布してないようなので、
$ svn co svn://svn.eglibc.org/branches/eglibc-2_13 eglibc-2.13
のようにチェックアウトし、
$ tar jcf eglibc-2.13.tar.bz2 eglibc-2.13
のようにして、固めておきました。
ビルドの仕方は
eglibc/libc/EGLIBC.cross-building
に書いてあるので、それに沿ってやるだけなのですが、
ステップ数が多いので、シェルスクリプトにしたものを最後につけておきます。
最後のシェルスクリプトを例えば、 install_gcc.sh などのファイル名で保存し、上記7個の tarball と同じディレクトリに置く。
$ ./install_gcc.sh
で実行するだけ。
同じディレクトリの arm-built-from-src の中に一式出来上がる。
速いマシンだと1時間以内に完了します。
$ ./install_gcc.sh -T /path/to/install/directory
のようにインストール先を指定するオプションも用意してあること。
(補足1)
make 3.82 だとEGLIBC のビルドでコケるので、 make 3.81 を使う。
(「make 3.82 glibc」でググるとこのあたりのことが出てくる。)
(補足2)
eglibc のビルドに GNU awk が必要。
最近のUbuntuだとデフォルト mawk が入っていたりするので apt-get install gawk で入れる。
(補足3)
eglibc はあえて古めの 2.13 を使っている。
2.14 以降だと、rpc/rpc.h などのヘッダーがなくなっていて、あとあと面倒なので。
「glibc rpc/rpc.h」でググるとこのあたりの事情が出てくるが、ちゃんと追いかけてません。
(補足4)
gcc を解凍したディレクトリで
$ contrib/download_prerequisites
とすると、gmp, mpfr, mpc をダウンロードしてくれるが、
ここでは、最初にまとめてtarball を準備しておく方法をとった。
--- シェルスクリプトここから ---
arm-linux-gnueabi-gcc をソースからビルドしてみました。物好きですな。
まずは各種ソースの tarball を入手します。
入手元を併記します。
(1) binutils-2.21.1.tar.bz2 - http://www.gnu.org/software/binutils/ から入手
(2) gcc-4.6.3.tar.bz2 - http://gcc.gnu.org/ から入手
(3) gmp-4.3.2.tar.bz2 - http://gcc.gnu.org/ から入手 (infrastructure の下)
(4) mpc-0.8.1.tar.gz - http://gcc.gnu.org/ から入手 (infrastructure の下)
(5) mpfr-2.4.2.tar.bz2 - http://gcc.gnu.org/ から入手 (infrastructure の下)
(6) linux-3.0.45.tar.bz2 - http://www.kernel.org/ から入手
(7) eglibc-2.13.tar.bz2 - http://www.eglibc.org/ から入手
(7) は公式サイトでtarball を配布してないようなので、
$ svn co svn://svn.eglibc.org/branches/eglibc-2_13 eglibc-2.13
のようにチェックアウトし、
$ tar jcf eglibc-2.13.tar.bz2 eglibc-2.13
のようにして、固めておきました。
ビルドの仕方は
eglibc/libc/EGLIBC.cross-building
に書いてあるので、それに沿ってやるだけなのですが、
ステップ数が多いので、シェルスクリプトにしたものを最後につけておきます。
最後のシェルスクリプトを例えば、 install_gcc.sh などのファイル名で保存し、上記7個の tarball と同じディレクトリに置く。
$ ./install_gcc.sh
で実行するだけ。
同じディレクトリの arm-built-from-src の中に一式出来上がる。
速いマシンだと1時間以内に完了します。
$ ./install_gcc.sh -T /path/to/install/directory
のようにインストール先を指定するオプションも用意してあること。
(補足1)
make 3.82 だとEGLIBC のビルドでコケるので、 make 3.81 を使う。
(「make 3.82 glibc」でググるとこのあたりのことが出てくる。)
(補足2)
eglibc のビルドに GNU awk が必要。
最近のUbuntuだとデフォルト mawk が入っていたりするので apt-get install gawk で入れる。
(補足3)
eglibc はあえて古めの 2.13 を使っている。
2.14 以降だと、rpc/rpc.h などのヘッダーがなくなっていて、あとあと面倒なので。
「glibc rpc/rpc.h」でググるとこのあたりの事情が出てくるが、ちゃんと追いかけてません。
(補足4)
gcc を解凍したディレクトリで
$ contrib/download_prerequisites
とすると、gmp, mpfr, mpc をダウンロードしてくれるが、
ここでは、最初にまとめてtarball を準備しておく方法をとった。
--- シェルスクリプトここから ---
#!/bin/bash # version gmp=gmp-4.3.2 mpfr=mpfr-2.4.2 mpc=mpc-0.8.1 binutils=binutils-2.21.1 gcc=gcc-4.6.3 eglibc=eglibc-2.13 linux=linux-3.0.45 # constant variables tarballtop=$(pwd) worktop=$(pwd) tools=$worktop/arm-built-from-src target=arm-none-linux-gnueabi sysroot=$tools/$target/libc linux_arch=arm # # helper functions # msg () { echo ";" echo ";" echo ";;;;; $1 ;;;;;" echo ";" echo ";" } usage () { cat <&2 usage: install_gcc.sh [-t tarballtop] [-w worktop] [-T tools] [targets...] Valid targets are: binutils Build and install binutils gcc1 Build and install the first gcc linuxhdr Install Linux kernel headers eglibchdr Install EGLIBC headers gcc2 Build and install the second gcc eglibc Build and install eglibc gcc3 Build and install the third gcc all Do all of above in above order If no target is given, "install_gcc all" shall be run. EOF } optcheck () { if [ -z $2 ] || [ $(echo $2 | cut -c 1) != "/" ]; then echo "error: specify absolute pass for $1 option" exit 1 fi } unpack () { # search *.tar.gz, *.tar.bz2, *.tar.xz, *.tgz, *.tbz2 *.tar # in this order. # If found, the tarball shall be uncompressed. for suffix in tar.gz tar.bz2 tar.xz tgz tbz2 tar; do tarball=$tarballtop/$1.$suffix if [ -f $tarball ]; then case $suffix in tar.gz) taropt=-zxf ;; tar.bz2) taropt=-jxf ;; tar.xz) taropt=-Jxf ;; tgz) taropt=-zxf ;; tbz2) taropt=-jxf ;; tar) taropt=-xf ;; *) echo "error: something wrong. fix me." >&2 ; exit 1 ;; esac echo "uncompressing $tarball ..." tar $taropt $tarball return fi done echo "error: tarball not found. Abort." >&2 exit 1 } gcc_prerequisites () { # $1: relative or absolute path to gcc source directory # sanity check if [ -z $1 ]; then echo "error: gcc_prerequisites was called without args" >&2 exit 1 fi gccdir=$1 if [ ! -d $gccdir ]; then echo "error: directory \'$gccdir\' not found" exit 1 fi # cd $gccdir # ./contrib/download_prerequisites # Instead of doing above, do following: unpack $gmp unpack $mpfr unpack $mpc mv $gmp $mpfr $mpc $gccdir/ ln -s $gmp $gccdir/gmp ln -s $mpfr $gccdir/mpfr ln -s $mpc $gccdir/mpc } install_binutils () { srcdir=$binutils objdir=obj-binutils cd $worktop rm -rf $srcdir $objdir unpack $srcdir mkdir -p $objdir cd $objdir $worktop/$srcdir/configure \ --target=$target \ --prefix=$tools \ --with-sysroot=$sysroot make make install cd $worktop rm -rf $srcdir $objdir } install_gcc1 () { srcdir=$gcc objdir=obj-gcc1 cd $worktop rm -rf $srcdir $objdir unpack $srcdir gcc_prerequisites $srcdir mkdir -p $objdir cd $objdir $worktop/$srcdir/configure \ --target=$target \ --prefix=$tools \ --without-headers --with-newlib \ --disable-shared --disable-threads --disable-libssp \ --disable-libgomp --disable-libmudflap \ --disable-libquadmath \ --enable-languages=c PATH=$tools/bin:$PATH make PATH=$tools/bin:$PATH make install cd $worktop rm -rf $srcdir $objdir } install_linuxhdr () { srcdir=$linux cd $worktop rm -rf $srcdir unpack $srcdir cd $srcdir make headers_install \ ARCH=$linux_arch CROSS_COMPILE=$target- \ INSTALL_HDR_PATH=$sysroot/usr cd $worktop rm -rf $srcdir } install_eglibchdr () { srcdir=$eglibc objdir=obj-eglibc-headers cd $worktop rm -rf $srcdir $objdir unpack $srcdir mv $srcdir/ports $srcdir/libc mkdir -p $objdir cd $objdir BUILD_CC=gcc \ CC=$tools/bin/$target-gcc \ CXX=$tools/bin/$target-g++ \ AR=$tools/bin/$target-ar \ RANLIB=$tools/bin/$target-ranlib \ $worktop/$srcdir/libc/configure \ --prefix=/usr \ --with-headers=$sysroot/usr/include \ --host=$target \ --disable-profile --without-gd --without-cvs --enable-add-ons make install-headers install_root=$sysroot \ install-bootstrap-headers=yes make csu/subdir_lib mkdir -p $sysroot/usr/lib cp csu/crt1.o csu/crti.o csu/crtn.o $sysroot/usr/lib $tools/bin/$target-gcc -nostdlib -nostartfiles -shared -x c /dev/null \ -o $sysroot/usr/lib/libc.so cd $worktop rm -rf $srcdir $objdir } install_gcc2 () { srcdir=$gcc objdir=obj-gcc2 cd $worktop rm -rf $srcdir $objdir unpack $srcdir gcc_prerequisites $srcdir mkdir -p $objdir cd $objdir $worktop/$srcdir/configure \ --target=$target \ --prefix=$tools \ --with-sysroot=$sysroot \ --disable-libssp --disable-libgomp --disable-libmudflap \ --disable-libquadmath \ --enable-languages=c PATH=$tools/bin:$PATH make PATH=$tools/bin:$PATH make install cd $worktop rm -rf $srcdir $objdir } install_eglibc () { srcdir=$eglibc objdir=obj-eglibc cd $worktop rm -rf $srcdir $objdir unpack $srcdir mv $srcdir/ports $srcdir/libc mkdir -p $objdir cd $objdir BUILD_CC=gcc \ CC=$tools/bin/$target-gcc \ CXX=$tools/bin/$target-g++ \ AR=$tools/bin/$target-ar \ RANLIB=$tools/bin/$target-ranlib \ $worktop/$srcdir/libc/configure \ --prefix=/usr \ --with-headers=$sysroot/usr/include \ --host=$target \ --disable-profile --without-gd --without-cvs --enable-add-ons PATH=$tools/bin:$PATH make PATH=$tools/bin:$PATH make install install_root=$sysroot cd $worktop rm -rf $srcdir $objdir } install_gcc3 () { srcdir=$gcc objdir=obj-gcc3 cd $worktop rm -rf $srcdir $objdir unpack $srcdir gcc_prerequisites $srcdir mkdir -p $objdir cd $objdir $worktop/$srcdir/configure \ --target=$target \ --prefix=$tools \ --with-sysroot=$sysroot \ --enable-__cxa_atexit \ --disable-libssp --disable-libgomp --disable-libmudflap \ --enable-languages=c,c++ make make install cd $worktop rm -rf $srcdir $objdir } # stop immediately if an error occurres set -e # process options while [ $# -gt 0 ] ; do case "$1" in -t) optcheck $1 $2; shift; tarballtop=$1 ;; -w) optcheck $1 $2; shift; worktop=$1 ;; -T) optcheck $1 $2; shift; tools=$1; sysroot=$tools/$target/libc ;; -*) (echo error: $1: unknown option ; echo ) >&2 ; usage ; exit 1 ;; *) break;; esac shift done if [ $# -eq 0 ] ; then set all fi # process targets while [ $# -gt 0 ] ; do case "$1" in binutils) msg binutils ; install_binutils ;; gcc1) msg gcc1 ; install_gcc1 ;; linuxhdr) msg linuxhdr ; install_linuxhdr ;; eglibchdr) msg eglibchdr ; install_eglibchdr ;; gcc2) msg gcc2 ; install_gcc2 ;; eglibc) msg eglibc ; install_eglibc ;; gcc3) msg gcc3 ; install_gcc3 ;; all) set binutils gcc1 linuxhdr eglibchdr gcc2 eglibc gcc3; continue ;; *) (echo error: $1: unknown target ; echo ) >&2 ; usage ; exit 1;; esac shift done
2012年10月4日木曜日
tftp サーバー on Ubuntu12.04.1
Ubuntu 12.04.1 に tftp サーバーを入れた時のメモ。
$ sudo apt-get install tftpd
設定ファイルが /etc/xinetd.d/tftp にあるはず、、なのに何も作ってくれてない。
そこで、 RHEL マシンから設定ファイルを持ってきた。
/etc/xinetd.d/tftp
# default: off
# description: The tftp server serves files using the trivial file transfer \
# protocol. The tftp protocol is often used to boot diskless \
# workstations, download configuration files to network-aware printers, \
# and to start the installation process for some operating systems.
service tftp
{
disable = no
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -s /var/lib/tftpboot
per_source = 11
cps = 100 2
flags = IPv4
}
一箇所ハマった点。
tftp はデフォルトではクライアントからの put での新規ファイル作成はできないようになっている。
(すでに存在するファイルへの上書きはできる。)
そこで、以下のように -c をつけておくと、新規作成もできるはず、、
server_args = -c -s /var/lib/tftpboot
RHEL ではこれでうまくいったが、Ubuntu だと、 -c がついていると、get も put も 「Transfer timed out」になってしまって、さっぱり動きません。
セキュリティ上の配慮なんでしょうか。。
というわけで、新規作成はあきらめることにしました。
とりあえず一番やりたいことは、 u-boot からの kernel ダウンロードだから、get さえできれば、ひとまずはOKです。
$ sudo apt-get install tftpd
設定ファイルが /etc/xinetd.d/tftp にあるはず、、なのに何も作ってくれてない。
そこで、 RHEL マシンから設定ファイルを持ってきた。
/etc/xinetd.d/tftp
# default: off
# description: The tftp server serves files using the trivial file transfer \
# protocol. The tftp protocol is often used to boot diskless \
# workstations, download configuration files to network-aware printers, \
# and to start the installation process for some operating systems.
service tftp
{
disable = no
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -s /var/lib/tftpboot
per_source = 11
cps = 100 2
flags = IPv4
}
一箇所ハマった点。
tftp はデフォルトではクライアントからの put での新規ファイル作成はできないようになっている。
(すでに存在するファイルへの上書きはできる。)
そこで、以下のように -c をつけておくと、新規作成もできるはず、、
server_args = -c -s /var/lib/tftpboot
RHEL ではこれでうまくいったが、Ubuntu だと、 -c がついていると、get も put も 「Transfer timed out」になってしまって、さっぱり動きません。
セキュリティ上の配慮なんでしょうか。。
というわけで、新規作成はあきらめることにしました。
とりあえず一番やりたいことは、 u-boot からの kernel ダウンロードだから、get さえできれば、ひとまずはOKです。
ntpdate と ntp daemon on Ubuntu
Ubuntu 12.04.1 LTS で ntp daemon をインストールした。
Ubuntu では標準で ntpdate がインストールされている。
両者の違いは以下のような感じと思っている。
・ntpdate
実行したときにワンショットで、すぐにサーバーの時刻と同期。
・ntp daemon
起動してもすぐには同期しない。
長期的にずれないようにうまく保ってくれるもの。どういうアルゴリズムなのかはよく知らない。
デフォルトでは、ネットワークがつながった時に
/etc/network/if-up.d/ntpdate から
/usr/sbin/ntpdate-debian
が自動実行されるようになっていると思っている(たぶん)。
ntpdate-debian は簡単なシェルスクリプトなので、中身見てみると、
/etc/default/ntpdate
を設定にして、ntpdate を実行しているようだ。
サーバー名はデフォルトで
NTPSERVERS="ntp.ubuntu.com"
を見るようだ。
会社などプロキシなどの問題がある場合、NTPSERVERSのところを会社指定のntpサーバに書きかえれば、同期してくれるようになった。
ntp daemon はデフォルトで入っていないので、
$ sudo apt-get install ntp
でインストールする必要がある。
/etc/ntp.conf が設定ファイルなので
server のところを必要に応じて書き換える。
ところで、ntpdate と ntp daemon が両方入っていたらどうなるんでしょう。。
ntp daemon がすでに起動しているときに、ntpdate を実行しようとすると
the NTP socket is in use, exiting
とエラーが出て、実行できない。
一方、
システムツール -> システム設定 -> 日付と時刻
で「ネットワーク時刻」をオフからオンに切り替えたときや、
新たにネットワークがつながったときは、
ntp daemon が NTP socket をつかむ前に ntpdate が実行されるように見えます。
よって、ntpdate が最初にガツンと合わせ、その後は ntp daemon がずれないように維持してくれるように見えました。
Ubuntu では標準で ntpdate がインストールされている。
両者の違いは以下のような感じと思っている。
・ntpdate
実行したときにワンショットで、すぐにサーバーの時刻と同期。
・ntp daemon
起動してもすぐには同期しない。
長期的にずれないようにうまく保ってくれるもの。どういうアルゴリズムなのかはよく知らない。
デフォルトでは、ネットワークがつながった時に
/etc/network/if-up.d/ntpdate から
/usr/sbin/ntpdate-debian
が自動実行されるようになっていると思っている(たぶん)。
ntpdate-debian は簡単なシェルスクリプトなので、中身見てみると、
/etc/default/ntpdate
を設定にして、ntpdate を実行しているようだ。
サーバー名はデフォルトで
NTPSERVERS="ntp.ubuntu.com"
を見るようだ。
会社などプロキシなどの問題がある場合、NTPSERVERSのところを会社指定のntpサーバに書きかえれば、同期してくれるようになった。
ntp daemon はデフォルトで入っていないので、
$ sudo apt-get install ntp
でインストールする必要がある。
/etc/ntp.conf が設定ファイルなので
server のところを必要に応じて書き換える。
ところで、ntpdate と ntp daemon が両方入っていたらどうなるんでしょう。。
ntp daemon がすでに起動しているときに、ntpdate を実行しようとすると
the NTP socket is in use, exiting
とエラーが出て、実行できない。
一方、
システムツール -> システム設定 -> 日付と時刻
で「ネットワーク時刻」をオフからオンに切り替えたときや、
新たにネットワークがつながったときは、
ntp daemon が NTP socket をつかむ前に ntpdate が実行されるように見えます。
よって、ntpdate が最初にガツンと合わせ、その後は ntp daemon がずれないように維持してくれるように見えました。
2012年10月2日火曜日
git daemon
git daemon の設定方法をメモっておきます。
Ubuntu と RHEL/CentOS 両方やってみましたが、やり方がちょっと違いますので、分けて説明します。
まずは Ubuntu でのやり方:
Ubuntu 12.04.1 LTSで試しました。
$ sudo apt-get install git-daemon-run
$ sudo sv start git-daemon
でできた。
あとは、export したいgit リポジトリの下に git-daemon-export-ok という空ファイルを作っておく。
Ubuntu だと sv というのがあるんですね。RHELにはないです。
この辺の事情は知りません。。
man sv を読むと、デフォルトで /etc/service の下をサーチするとある。
確かに
/etc/service/git-daemon
というのがある。
これは
/etc/sv/git-daemon ディレクトリへのシンボリックリンクになっている。
/etc/sv/git-daemon/run の内容は以下のようになっていた。
#!/bin/sh
exec 2>&1
echo 'git-daemon starting.'
exec chpst -ugitdaemon \
"$(git --exec-path)"/git-daemon --verbose --reuseaddr \
--base-path=/var/cache /var/cache/git
引き続いて、RHEL/CentOS でのやり方:
RHEL 6.3で試しました。
# yum install git-daemon
でインストールする。
xinetd もついでに依存関係で入る。
/etc/xinetd.d/git の設定ファイルができているので、
ちょこっと編集します。
# default: off
# description: The git dæmon allows git repositories to be exported using \
# the git:// protocol.
service git
{
# disable = yes ← コメントアウト
disable = no ← 追加
socket_type = stream
wait = no
user = nobody
server = /usr/libexec/git-core/git-daemon
# server_args = --base-path=/var/lib/git --export-all --user-path=public_git --syslog --inetd --verbose ←コメントアウト
server_args = --base-path=/var --export-all --user-path=public_git --syslog --inetd --verbose /var/git ←追加
log_on_failure += USERID
}
disable を noにして、server_args の部分を書き換えています。
git clone git://my.git.server/git/hoge.git
で /var/git/hoge.git へアクセスするようになります。
あとは
# service xinetd restart
とします。
git daemon はデフォルト 9418番ポートを listen するので、
ファイアウォールを使っている場合は、9418/tcp を開ける。
Ubuntu と RHEL/CentOS 両方やってみましたが、やり方がちょっと違いますので、分けて説明します。
まずは Ubuntu でのやり方:
Ubuntu 12.04.1 LTSで試しました。
$ sudo apt-get install git-daemon-run
$ sudo sv start git-daemon
でできた。
あとは、export したいgit リポジトリの下に git-daemon-export-ok という空ファイルを作っておく。
Ubuntu だと sv というのがあるんですね。RHELにはないです。
この辺の事情は知りません。。
man sv を読むと、デフォルトで /etc/service の下をサーチするとある。
確かに
/etc/service/git-daemon
というのがある。
これは
/etc/sv/git-daemon ディレクトリへのシンボリックリンクになっている。
/etc/sv/git-daemon/run の内容は以下のようになっていた。
#!/bin/sh
exec 2>&1
echo 'git-daemon starting.'
exec chpst -ugitdaemon \
"$(git --exec-path)"/git-daemon --verbose --reuseaddr \
--base-path=/var/cache /var/cache/git
Debian 系は /var/cache/git の下にリポジトリがあるのを期待している。
なので、 gitweb や git-daemon などの etc ファイルをいちいち書き変えるよりも、
/var/cache/git から本当のリポジトリ置き場へシンボリックリンクを貼っておくのがよいと思う。
/var/cache/git に直にリポジトリを置いてもいいんですが、FHS的には、/var/cache/ 以下はアプリケーションのキャッシュとして使われるということなので、ちょっと気持ち悪い気がする。
--base-path=/var/cache は アクセスするときに、パスの先頭から /var/cache をはぎ取るという意味だから、
/var/cache/git/repo.git をクローンする場合、
$ git clone git://hostname/git/repo.git
みたいな感じでアクセスすればよい。
引き続いて、RHEL/CentOS でのやり方:
RHEL 6.3で試しました。
# yum install git-daemon
でインストールする。
xinetd もついでに依存関係で入る。
/etc/xinetd.d/git の設定ファイルができているので、
ちょこっと編集します。
# default: off
# description: The git dæmon allows git repositories to be exported using \
# the git:// protocol.
service git
{
# disable = yes ← コメントアウト
disable = no ← 追加
socket_type = stream
wait = no
user = nobody
server = /usr/libexec/git-core/git-daemon
# server_args = --base-path=/var/lib/git --export-all --user-path=public_git --syslog --inetd --verbose ←コメントアウト
server_args = --base-path=/var --export-all --user-path=public_git --syslog --inetd --verbose /var/git ←追加
log_on_failure += USERID
}
disable を noにして、server_args の部分を書き換えています。
git clone git://my.git.server/git/hoge.git
で /var/git/hoge.git へアクセスするようになります。
あとは
# service xinetd restart
とします。
git daemon はデフォルト 9418番ポートを listen するので、
ファイアウォールを使っている場合は、9418/tcp を開ける。
2012年10月1日月曜日
git repogitory 自動バックアップ
git の repogitory は絶対に失ってはならない、最重要データの一つである。
そこで、独立した複数台のPCに常にバックアップを取ることを考えた。
cron を使い、定期的に他のマシンへ git push するようにする。
サーバーへは普通は ssh で接続するようになっているケースが多い。
自動バックアップのためにはパスワードなしで ssh 接続できないといけないので、
前回の「公開鍵暗号による ssh接続」の設定を済ませておく。
(秘密鍵を取り出すパスフレーズは空にしておく。)
そして、
$ crontab -e
で定期的に実行したいコマンドを記入する。
記入フォーマットは左のカラムから分、時、日、月、曜日、コマンドとなっている。
例えば、毎時55分になったら、 /var/git/main_repo.git の master ブランチを
backup_server マシン (アカウント名 = my_account) の ~/backup/backup_repo.git へ
pushしたい場合以下のようになる。
55 * * * * cd /var/git/main_repo.git; git push my_account@backup_server:~/backup/backup_repo.git master
↑ブラウザの都合で複数行に見えるかもしれないけど、1行です。
やりながらふと思ったが、
メインのマシンの方で、git daemon を動かしておいて、
バックアップサーバの方から定期的に git pull git://〜
するのでも良かった。
そこで、独立した複数台のPCに常にバックアップを取ることを考えた。
cron を使い、定期的に他のマシンへ git push するようにする。
サーバーへは普通は ssh で接続するようになっているケースが多い。
自動バックアップのためにはパスワードなしで ssh 接続できないといけないので、
前回の「公開鍵暗号による ssh接続」の設定を済ませておく。
(秘密鍵を取り出すパスフレーズは空にしておく。)
そして、
$ crontab -e
で定期的に実行したいコマンドを記入する。
記入フォーマットは左のカラムから分、時、日、月、曜日、コマンドとなっている。
例えば、毎時55分になったら、 /var/git/main_repo.git の master ブランチを
backup_server マシン (アカウント名 = my_account) の ~/backup/backup_repo.git へ
pushしたい場合以下のようになる。
55 * * * * cd /var/git/main_repo.git; git push my_account@backup_server:~/backup/backup_repo.git master
↑ブラウザの都合で複数行に見えるかもしれないけど、1行です。
やりながらふと思ったが、
メインのマシンの方で、git daemon を動かしておいて、
バックアップサーバの方から定期的に git pull git://〜
するのでも良かった。
gut push でメールをとばす
git push でリポジトリが更新されたときに、commitの内容をメールで送信する方法。
ディストリビューションにもよるが、メール送信スクリプトは
/usr/share/git-core/contrib/hooks/post-receive-email
に普通インストールされていると思うので、これをそのまま使うこととする。
送信には sendmail を使用しているので、まずは sendmail ができるようにならないといけない。
MTA の設定はあまり詳しくないが、、、
とりあえずUbuntu でやってみた。
$ sudo apt-get install postfix
でインストール。
途中で選択肢が出てくるので、「インターネットサイト」を選択。
自宅のマシン場合、特に設定なしでも、そのまま使えた。
以下でちゃんとメールが届けばOK。
$ sendmail my.address@gmail.com
To: my.address@gmail.com
From: my.address@gmail.com
Subject: test
test
.
会社の場合、ファイアウォールの問題で、このままだと配送できなかったので、relayhostを設定。
/etc/postfix/main.cf を編集し、
relayhost のところに中継サーバーのIPアドレスを指定する。
IPアドレスで指定しないといけないみたいなので、
会社からこれを使え、と言われているSMTPサーバ名から nslookup で引く。
$ nslookup my.office.smtp.server
で Address : xxx.yyy.zzz.www
みたいにIPアドレスが返ってくるので、
relayhost = xxx.yyy.zzz.www
と指定するとOK。
sendmail が動くようになったので、続いて git の設定。
/usr/share/git-core/contrib/hooks/post-receive-email
にやり方が全部書いてあるので、この通りやるだけですが。。
post-receive-email に実行権限を与える
$ sudo chmod a+x /usr/share/git-core/contrib/hooks/post-receive-email
設定したいgit リポジトリへ移動
$ cd /my/git/repogitory.git/hooks
post-receive-email へ post-receive という名前でシンボリックリンクをはる。
$ ln -s /usr/share/git-core/contrib/hooks/post-receive-email post-receive
送りつけたい宛先を config に設定
$ git config hooks.mailinglist "address@you.want.to.send"
とりあえずこれで送信されます。
あと、お好みでやっておく設定
メールのタイトルが 「UNNAMED PROJECT」になっているので、description にプロジェクト名を記載。
送信元アドレス指定
$ git config hooks.envelopesender do_not_reply_this@foo.org
メール最大行数を指定
$ git config hooks.emailmaxlines 500
ディストリビューションにもよるが、メール送信スクリプトは
/usr/share/git-core/contrib/hooks/post-receive-email
に普通インストールされていると思うので、これをそのまま使うこととする。
送信には sendmail を使用しているので、まずは sendmail ができるようにならないといけない。
MTA の設定はあまり詳しくないが、、、
とりあえずUbuntu でやってみた。
$ sudo apt-get install postfix
でインストール。
途中で選択肢が出てくるので、「インターネットサイト」を選択。
自宅のマシン場合、特に設定なしでも、そのまま使えた。
以下でちゃんとメールが届けばOK。
$ sendmail my.address@gmail.com
To: my.address@gmail.com
From: my.address@gmail.com
Subject: test
test
.
会社の場合、ファイアウォールの問題で、このままだと配送できなかったので、relayhostを設定。
/etc/postfix/main.cf を編集し、
relayhost のところに中継サーバーのIPアドレスを指定する。
IPアドレスで指定しないといけないみたいなので、
会社からこれを使え、と言われているSMTPサーバ名から nslookup で引く。
$ nslookup my.office.smtp.server
で Address : xxx.yyy.zzz.www
みたいにIPアドレスが返ってくるので、
relayhost = xxx.yyy.zzz.www
と指定するとOK。
sendmail が動くようになったので、続いて git の設定。
/usr/share/git-core/contrib/hooks/post-receive-email
にやり方が全部書いてあるので、この通りやるだけですが。。
post-receive-email に実行権限を与える
$ sudo chmod a+x /usr/share/git-core/contrib/hooks/post-receive-email
設定したいgit リポジトリへ移動
$ cd /my/git/repogitory.git/hooks
post-receive-email へ post-receive という名前でシンボリックリンクをはる。
$ ln -s /usr/share/git-core/contrib/hooks/post-receive-email post-receive
送りつけたい宛先を config に設定
$ git config hooks.mailinglist "address@you.want.to.send"
とりあえずこれで送信されます。
あと、お好みでやっておく設定
メールのタイトルが 「UNNAMED PROJECT」になっているので、description にプロジェクト名を記載。
送信元アドレス指定
$ git config hooks.envelopesender do_not_reply_this@foo.org
メール最大行数を指定
$ git config hooks.emailmaxlines 500
Ubuntu 12.04 on RAID5 トラブルシューティング
先日の記事
「Intel RST 設定画面の入り方」
「Linuxインストール on RAID5 (Intel RST)」
に書いたやり方で、SSD 4 台でRAID5を組み、Ubuntu 12.04.1 LTS (alternate install)
をインストールして使い始めた。
使って数日目、以下のようなメッセージを出して起動しなくなった。
udevd[164]: inotify_add_watch(6, /dev/dm-1) failed: No such file or directory
udevd[163]: inotify_add_watch(6, /dev/dm-2) failed: No such file or directory
udevd[163]: inotify_add_watch(6, /dev/dm-1) failed: No such file or directory
とりあえず、エラーメッセージで検索してみると、Ubuntu関連でいろいろヒットした。
試行錯誤の後、とりあえず起動するようになった。
(1) 起動直後に、シフトキーを押しっぱなしにして、grub の画面を出す。
(2) 「Ubuntu, with Linux 3.2.*-**-generic (recovery mode)」を選択。
(3) 「Resume」を選択。
(4) デスクトップまで起動する。
(5) このままだと、再起動後、同じ現象で起動しなくなる。
そこで
$ sudo apt-get install cryptsetup
として、再起動すると、ちゃんとブートするようになった。
cryptsetup のインストールは、検索で出てきた通りやってみたら運良く直ったということなので、理屈は理解していません。
「Intel RST 設定画面の入り方」
「Linuxインストール on RAID5 (Intel RST)」
に書いたやり方で、SSD 4 台でRAID5を組み、Ubuntu 12.04.1 LTS (alternate install)
をインストールして使い始めた。
使って数日目、以下のようなメッセージを出して起動しなくなった。
udevd[164]: inotify_add_watch(6, /dev/dm-1) failed: No such file or directory
udevd[163]: inotify_add_watch(6, /dev/dm-2) failed: No such file or directory
udevd[163]: inotify_add_watch(6, /dev/dm-1) failed: No such file or directory
とりあえず、エラーメッセージで検索してみると、Ubuntu関連でいろいろヒットした。
試行錯誤の後、とりあえず起動するようになった。
(1) 起動直後に、シフトキーを押しっぱなしにして、grub の画面を出す。
(2) 「Ubuntu, with Linux 3.2.*-**-generic (recovery mode)」を選択。
(3) 「Resume」を選択。
(4) デスクトップまで起動する。
(5) このままだと、再起動後、同じ現象で起動しなくなる。
そこで
$ sudo apt-get install cryptsetup
として、再起動すると、ちゃんとブートするようになった。
cryptsetup のインストールは、検索で出てきた通りやってみたら運良く直ったということなので、理屈は理解していません。
2012年9月27日木曜日
2012年9月26日水曜日
2012年9月18日火曜日
2012年9月10日月曜日
2012年8月4日土曜日
2012年8月1日水曜日
Linux のコードが FreeBSDに
FreeBSD のことはよく知らないのですが、FreeBSDのソースをダウンロードしてくると、Linuxと同じようなファイルが含まれています。
ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/9.0-RELEASE
からsrc.txzを取ってきて、解凍すると、
usr/src/sys/ofed/include/linux 以下に
Linux Kernel の include/linux とそっくりなファイル群があります。
ディレクトリ名からして、Linux の方が本家だと想像します。
Linux は GPLライセンス, FreeBSD は BSDライセンスなので、こんなことできるんですかね?
FreeBSDが勝手にLinuxをコピーしているのか、それともLinux Communityに許可もらったのか、事情はよくわかりません。
include/linux/ 以下には他のソフトにもそのまま転用できそうな部品になるコードが結構ある。
たとえば、
include/linux/kernel.h に含まれる container_of マクロ。
include/linux/list.h の連結リストの関数群などなど。
自前のソフト開発で、Linux からコードをコピーするとGPL汚染すると思いますが、FreeBSDに入っている同等コードをコピーすれば、BSDライセンスとして扱ってよいということでしょうか。
企業なんかだと、コピー開示義務があるかどうかの違いは結構大きいと思います。
ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/9.0-RELEASE
からsrc.txzを取ってきて、解凍すると、
usr/src/sys/ofed/include/linux 以下に
Linux Kernel の include/linux とそっくりなファイル群があります。
ディレクトリ名からして、Linux の方が本家だと想像します。
Linux は GPLライセンス, FreeBSD は BSDライセンスなので、こんなことできるんですかね?
FreeBSDが勝手にLinuxをコピーしているのか、それともLinux Communityに許可もらったのか、事情はよくわかりません。
include/linux/ 以下には他のソフトにもそのまま転用できそうな部品になるコードが結構ある。
たとえば、
include/linux/kernel.h に含まれる container_of マクロ。
include/linux/list.h の連結リストの関数群などなど。
自前のソフト開発で、Linux からコードをコピーするとGPL汚染すると思いますが、FreeBSDに入っている同等コードをコピーすれば、BSDライセンスとして扱ってよいということでしょうか。
企業なんかだと、コピー開示義務があるかどうかの違いは結構大きいと思います。
Linux ライクな autoconf.h を簡単に作る
Linux の Makefile においては、.config ファイルの内容から
include/config/auto.conf
と
include/generated/autoconf.h
が作られる。
前者はすべての Makefile から include され、
後者は -include include/generated/autoconf.h としてすべてのCのソースに渡される。
Makefile でも Cのソースでも、同じ設定内容を参照できるようにするというアイデアは素晴らしいと思う。
自前のソフトでも同様のことをしたいが、Linux の scripts/kconfig/conf を使うほどでもないという場合、以下のように make の簡単なコードでほぼ同等のことをできる。
Makefile の実装例:
include .config
auto.conf: .config
@ ($(foreach v, $(filter CONFIG_%, $(.VARIABLES)), \
$(if $($v), echo $v='$($v)';))) > $@
autoconf.h: .config
@ ($(foreach v, $(filter CONFIG_%, $(.VARIABLES)), \
$(if $($v), echo \#define $v $(if $(filter y,$($v)),1,'$($v)');))) > $@
include/config/auto.conf
と
include/generated/autoconf.h
が作られる。
前者はすべての Makefile から include され、
後者は -include include/generated/autoconf.h としてすべてのCのソースに渡される。
Makefile でも Cのソースでも、同じ設定内容を参照できるようにするというアイデアは素晴らしいと思う。
自前のソフトでも同様のことをしたいが、Linux の scripts/kconfig/conf を使うほどでもないという場合、以下のように make の簡単なコードでほぼ同等のことをできる。
Makefile の実装例:
include .config
auto.conf: .config
@ ($(foreach v, $(filter CONFIG_%, $(.VARIABLES)), \
$(if $($v), echo $v='$($v)';))) > $@
autoconf.h: .config
@ ($(foreach v, $(filter CONFIG_%, $(.VARIABLES)), \
$(if $($v), echo \#define $v $(if $(filter y,$($v)),1,'$($v)');))) > $@
例えば、
CONFIG_FOO=y
CONFIG_BAR="abcdef"
CONFIG_BUZ=0x100
# CONFIG_QUX is not set.
という内容の .config を食わせてみる。
実行結果は以下の通り。
$ make auto.conf
$ make autoconf.h
$ cat auto.conf
CONFIG_FOO=y
CONFIG_BUZ=0x100
CONFIG_BAR="abcdef"
$ cat autoconf.h
#define CONFIG_FOO 1
#define CONFIG_BUZ 0x100
#define CONFIG_BAR "abcdef"
sed などで、 .config を parse してもよいのだが、make の .VARIABLES に定義済み変数が全部入っているので、そこから CONFIG_ で始まるものを抽出すれば簡単である。
.config 中で =y のものは、 autoconf.h では 1 に define される。
本家 Linux では =m のものは autoconf.h の方では (変数名)_MODULE が定義されるが、今回のサンプルには実装していない。
make の ifdef はわかりにくい
シェルにおいて
$ FOO=
とすると、シェル変数 FOO は空ではあるが、定義はされている。
変数 FOO を未定義にするには
$ unset FOO
としなければならない。
つまり、シェルスクリプトで、「変数が空」であることと、「変数が未定義」であることは明確に違う。
一方、make においてはこのあたりが紛らわしいというか、非常にわかりにくいと思うので、整理しておきたい。
make には ifdef という構文があるが、これの挙動を見てみる。
(実験1)
以下の内容の Makefile を用意する。
FOO=
all:
ifdef
@echo FOO is defined.
else
@echo FOO is NOT defined.
endif
実行すると以下のようになる。
$ make
FOO is NOT defined.
FOO=
のように、空文字を代入した場合、 ifdef は FOO を未定義だと判定した。
なるほど〜、makeにおいては
空の変数は未定義の扱いになる。
そして、make には unset がないから、変数を未定義に戻すには、空文字を代入すればいいんだ、と理解したくなるかもしれない。
だが、これは違う。
(実行2)
次の内容の Makefile を用意する。
FOO=
FOO ?= 1
BAR ?= 1
all:
@echo FOO = $(FOO)
$ FOO=
とすると、シェル変数 FOO は空ではあるが、定義はされている。
変数 FOO を未定義にするには
$ unset FOO
としなければならない。
つまり、シェルスクリプトで、「変数が空」であることと、「変数が未定義」であることは明確に違う。
一方、make においてはこのあたりが紛らわしいというか、非常にわかりにくいと思うので、整理しておきたい。
make には ifdef という構文があるが、これの挙動を見てみる。
(実験1)
以下の内容の Makefile を用意する。
FOO=
all:
ifdef
@echo FOO is defined.
else
@echo FOO is NOT defined.
endif
実行すると以下のようになる。
$ make
FOO is NOT defined.
FOO=
のように、空文字を代入した場合、 ifdef は FOO を未定義だと判定した。
なるほど〜、makeにおいては
空の変数は未定義の扱いになる。
そして、make には unset がないから、変数を未定義に戻すには、空文字を代入すればいいんだ、と理解したくなるかもしれない。
だが、これは違う。
(実行2)
次の内容の Makefile を用意する。
FOO=
FOO ?= 1
BAR ?= 1
all:
@echo FOO = $(FOO)
@echo BAR = $(BAR)
この実行結果は以下のようになる。
$ make
FOO =
BAR = 1
?= というのは、変数が未定義の時のみ、右辺の値を代入してくれる。
実験結果を見ると、
?= は BAR は未定義と判定したが、FOO は定義済みと判定したことになる。
(実験3)
以下の内容の Makefile を用意する。
FOO=
all:
@echo $(filter FOO, $(.VARIABLES))
実行結果は
$ make
FOO
となる。
.VARIABLES という makeの変数には、使用中の変数が全部入っている。
大量の変数が入っているのだが、その中に FOO も含まれていることがわかる。
つまり、 .VARIABLES には中身が空の変数も含めて、定義済みの変数がリストされている。
(実験1)〜(実験3)からわかることは、
makeにおいても、「変数が空」であることと「変数が未定義」であることは区別している。
(ただ、シェルと違って、いったん定義された変数を未定義に戻すことはできない。)
?= は変数が「未定義」であれば右辺値が代入される。
注意しておきたいことは、(実験1)からわかるように、 ifdef は「定義されているか」を判定するのではなく、「空でないかどうか」を判定するものだ。
これは、ひじょーーーーーに紛らわしい。
この ifdef の仕様は失敗じゃないの?と思う。
つまり
ifdef FOO
は
ifndef ($(FOO),)
と同じなのだ。
だから、 ifdef 自体、別になくても構わないし、私は使わない。
ifndef ($(FOO),)
を使うほうが、誤解がないから。
登録:
投稿 (Atom)