kernel config 生成(略記)のためのシェルスクリプト
この記事は、 Gentoo Advent Calendar 2016 の6日目の記事です。
昨日の記事は Gentoo on Windows 10 (Gentoo Advent Calender 2016 5日目)でした。
概要
そろそろ普段使いのラップトップが壊れそうなので、別マシンへの移行の準備をしておきたさが高まっています。 Windows 8.1 を gentoo で上書きして以来、これまで様々な設定をしてきましたが、 /etc にあるファイルの多くはコピーで済まされる設定ファイル[0]なので、移行にあたってそこまで問題になりません。
問題なのは、カーネルの .config です。 ハードウェア由来の設定が多く項目も多いため、安直にコピーしてちょっと改変すれば使えるというものでもありません。 そこで、以下のようなスクリプトが欲しくなったため、簡単に書いてみたというお話です。
- 設定の理由がわかる(コメントが書ける)
-
値の無効化(
CONFIG_FOO=n
)ができる - 興味のない項目は、何も書かずともよろしく設定しておいてほしい
- 記述した設定に無効なもの(あるいは上書きされたもの)があれば、警告してほしい
対象読者
大雑把には、既に gentoo を使っていたりカーネルをコンパイルしている人向けです。
- gentoo を使っていて、カーネルの .config をそこそこの頻度で弄っている人
- 複数台のマシンで gentoo を使っている人
- その他 distro でも、カーネルを野良でビルドしたい人
残念ながら gentoo の布教記事ではございません。
merge_config.sh
……と思って作ろうとしていましたが、よくよく調べてみると、 Linux カーネルのソース(gentoo であれば /usr/src/linux など)の scripts/kconfig/merge_config.sh に、かなり近い目的のものがありました。
中身を読んでみると、ファイル名のとおり、設定ファイルとして有効なファイル同士の merge 用途のものであり、コメントやインデント、省略記法などは使えないようです。
そこで方針を変えて、書きやすい設定を merge_config.sh
で使えるよう変換して吐き出すスクリプト(というか実質正規表現)を書くことにしました。
追加の要件は以下のような感じです。
- インデントを使える
- コメントを書いても無効/不正扱いされない
CONFIG_FOO=n
のように書いても警告されないCONFIG_
のプレフィックスを省略できる
成果物
小さなコードなので、ライセンスは CC0 とします。 (要するにパブリックドメインです。)
#!/bin/sh
# These codes are licensed under CC0.
# https://creativecommons.org/publicdomain/zero/1.0/deed.ja
# Set up parameters.
DATETIME="$(date '+%F-%H%M%S')"
: ${SRC_DIR:=/usr/src/linux}
cd "$(dirname "$0")"
DIR="$(pwd)"
CONFFILE_SRC="${DIR}/config"
CONFFILE_TEMP="${DIR}/.temp.$(basename "${CONFFILE_SRC}")"
sed -r -n \
-e 's/^\s*(CONFIG_)?([A-Za-z0-9_]+=.+)$/CONFIG_\2/' \
-e 's/^\s*# (CONFIG_[A-Za-z0-9_]+) is not set$/\1=n/' \
-e '/^CONFIG_/!d' -e 's/^(CONFIG_[^=]+)=n$/# \1 is not set/' \
-e 'p' \
"${CONFFILE_SRC}" | sort -u >"${CONFFILE_TEMP}"
# `merge_config.sh` should be executed in the kernel source directory.
cd "${SRC_DIR}"
cp -f .config ".config-${DATETIME}"
# -n: use allnoconfig instead of alldefconfig
# -r: list redundant entries when merging fragments
./scripts/kconfig/merge_config.sh -r "${CONFFILE_TEMP}"
rm "${CONFFILE_TEMP}"
というか実質 sed スクリプト。
つかいかた
- スクリプトを保存して x フラグを立てる
- スクリプトと同じディレクトリに config というファイルを作って設定を書く
-
sudo ./genconfig.sh
-
カーネルコンパイル。
私の場合:
sudo genkernel --makeopts="-j4" --splash --no-clean --oldconfig all
[1]
ソースコードのディレクトリはデフォルトで /usr/src/linux
ですが、 SRC_DIR=/path/to/linux/source ./genconfig.sh
のようにすれば別の場所を使うことができます。
そのディレクトリのパーミッションによっては、 sudo
は必要ないかもしれません。
config
ファイルの内容
文法はシンプルです。
- 空白文字によりインデント可能
#
で行コメント-
ただし
^\s*# (CONFIG_[A-Za-z0-9_]+) is not set$
にマッチする行は# \1 is not set
に変換される # CONFIG_FOO is not set
のような行を保存するためです
-
ただし
CONFIG_FOO=bar
やFOO=bar
はCONFIG_FOO=bar
に変換される-
要するに
CONFIG_
を省略可能
-
要するに
CONFIG_FOO=n
は# CONFIG_FOO is not set
に変換されるmerge_config.sh
に「設定が反映されていない」という警告を出されるのを防ぐためです
で、たとえば実際に私が使っている設定(の抜粋)は以下のようになります。
# www-client:google-chrome-46.0.2490.80_p1: # > CONFIG_COMPAT_VDSO causes segfaults (bug #556286) ## config COMPAT_VDSO ## def_bool n ## prompt "Disable the 32-bit vDSO (needed for glibc 2.3.3)" COMPAT_VDSO=n # www-client/google-chrome-54.0.2840.71: # > USER_NS is required for sandbox to work ## config USER_NS ## bool "User namespace" USER_NS=y # media-sound/pulseaudio-7.0: # > A preallocated buffer-size of 2048 (kB) or higher is recommended for the HD-audio driver! ## config SND_HDA_PREALLOC_SIZE ## int "Pre-allocated buffer size for HD-audio driver" SND_HDA_PREALLOC_SIZE=2048 ## config TMPFS ## bool "Tmpfs virtual memory file system support (former shm fs)" TMPFS=y ## config TMPFS_POSIX_ACL ## bool "Tmpfs POSIX Access Control Lists" TMPFS_POSIX_ACL=y # sys-apps/lm_sensors-3.4.0_p20160725: # > sensors-detect requires CONFIG_I2C_CHARDEV to be enabled. ## config I2C_CHARDEV ## tristate "I2C device interface" I2C_CHARDEV=m # Intel CPU. ## config SENSORS_CORETEMP ## tristate "Intel Core/Core2/Atom temperature sensor" SENSORS_CORETEMP=m
config
の例(抜粋)CONFIG_COMPAT_VDSO
や CONFIG_I2C_CHARDEV
など、名前からは何故これを有効/無効にしたのかわからないような設定は結構ありますが、こうしてコメントとインデントで整理して書いてやることで、設定の意図や必要性がある程度明確にわかるようになります。
私は面倒だったので使いませんでしたが、 vim などであれば fold marker を使って折り畳みできるようにすれば、より読み易くなるかもしれません。
解説
merge_config.sh
先述の通りですが、大雑把に言うと、既に .config として使えるファイルを複数指定すると、それらを merge して、ついでに指定されなかった項目を自動でよろしく設定してくれるものです。
そして、私のスクリプトがあてにしている、自動でよろしく設定する部分は、シェルスクリプトではなく make
によって行われます[2]。
# Use the merged file as the starting point for:
# alldefconfig: Fills in any missing symbols with Kconfig default
# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set
make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
$ALLTARGET
は、デフォルトでは alldefconfig
ですが、 -n
オプションを付けて merge_config.sh
を起動すると allnoconfig
となります。
make alldefconfig
名前そのままですが、 alldefconfig
は、与えられた config において未指定の項目に、デフォルト値を設定します。
同様に allnoconfig
は、与えられた config において未指定の項目のすべてに、 n
(no) を設定します。
他にも、 allyesconfig
とか randconfig
とかいろいろあります。
詳しくは make help
とかで見られます。
$ pwd /usr/src/linux-4.8.11-gentoo $ make help Cleaning targets: clean - Remove most generated files but keep the config and enough build support to build external modules mrproper - Remove all generated files + config + various backup files distclean - mrproper + remove editor backup and patch files Configuration targets: config - Update current config utilising a line-oriented program nconfig - Update current config utilising a ncurses menu based program menuconfig - Update current config utilising a menu based program xconfig - Update current config utilising a Qt based front-end gconfig - Update current config utilising a GTK+ based front-end oldconfig - Update current config utilising a provided .config as base localmodconfig - Update current config disabling modules not loaded localyesconfig - Update current config converting local mods to core silentoldconfig - Same as oldconfig, but quietly, additionally update deps defconfig - New config with default from ARCH supplied defconfig savedefconfig - Save current config as ./defconfig (minimal config) allnoconfig - New config where all options are answered with no allyesconfig - New config where all options are accepted with yes allmodconfig - New config selecting modules when possible alldefconfig - New config with all symbols set to default randconfig - New config with random answer to all options listnewconfig - List new options olddefconfig - Same as silentoldconfig but sets new symbols to their default value kvmconfig - Enable additional options for kvm guest kernel support xenconfig - Enable additional options for xen dom0 and guest kernel support tinyconfig - Configure the tiniest possible kernel (以下略)
make help
もし私のスクリプトで allnoconfig
を使いたい場合、 ./scripts/kconfig/merge_config.sh
の呼び出しで -n
を追加しましょう。
./scripts/kconfig/merge_config.sh -n -r "${CONFFILE_TEMP}"
まとめ
-
カーネルコンフィグ管理を手助けする簡単なスクリプトを書いた
make oldconfig
やgenkernel --menuconfig --oldconfigall
で積み重ねてきた秘伝のタレを棄てて、設定はレシピから作りましょう
-
gentoo でカーネルをコンパイルすると言うとビビる人がいますが、実際のところコンフィグ作って
make
すればおしまいなので、こわくないです-
なんなら項目ぜんぶ
y
(yes) とかm
(module) とかにしとけば基本どうにかなりそう (コンパイル時間延びるけど)
-
なんなら項目ぜんぶ
- gentoo と LFS の他にカーネルコンパイルが必要そうな distro を知りませんが、この記事の内容は gentoo でなくとも適用できます。 gentoo AdC なのにごめんなさい。
おまけ
portage のログ
/var/log/portage/elog/summary.log に、過去 portage で emerge されたパッケージのメッセージが記録されています。 これを見て検索をかければ、どのパッケージがどのような設定を要求しているか、ある程度[3]わかるでしょう。
vim で見易いよう、簡単な syntax を用意しておきました。 ご活用ください。

au BufRead,BufNewFile */portage/elog/summary.log set filetype=portage-summary-log
if exists("b:current_syntax")
finish
endif
syn case match
syn spell notoplevel
syn match logPackageAtom excludenl '[a-z-_]\+/[a-zA-Z0-9_\.-]\+' contained containedin=logPackageLine
syn match logPackageLine excludenl '^>>> Messages generated by process .*:$' contains=logPackageAtom
syn match logKernelConfig excludenl 'CONFIG_[A-Z0-9_]\+' containedin=ALL
syn match logQA excludenl '^QA: .*$'
syn match logQANoticeLabel excludenl '^QA Notice:'me=e-1
syn match logWarning excludenl '^WARN: .*'
syn match logError excludenl '^ERROR: .*'
hi link logPackageAtom Keyword
hi link logPackageLine Comment
hi link logKernelConfig Identifier
hi link logQA Label
hi link logQANoticeLabel Label
hi link logWarning Label
hi link logError Label
let b:current_syntax = "portage-summary-log"
次に欲しい機能
現状でそこそこ満足なので、今のところこれ以上リソースを注ぐつもりはありませんが、改良点があるとしたら以下の点です。
複数ファイルのマージ
先述のとおり merge_config.sh
は複数ファイルのマージ機能を持っているので、たとえば設定ファイルを基礎用、ハードウェア用、各パッケージ用、各マシン特有設定など、複数に分割して管理できるようにするのは難しくないでしょう。
私がそれをしなかったのは、単にファイルをスクリプトの引数でとれるようにすると、パスの解決がちょっと面倒かもと思ったからです。
でも今よく考えたら readlink
とかで絶対パス取得できそうなのでそのうち実装するかも。
依存性解析
たとえば CONFIG_FOO
が前提条件として CONFIG_BAR
を要求している場合、そっちも勝手に有効化してくれたら嬉しいです。
ですが実際には、 m
にするか y
にするか、或いは複数の OR 条件がある場合どれを満たすべきか、など自由度が高めなので、全自動にはできそうにありません。
あと、依存関係を取得するには Kconfig を読むことになるので、シェルスクリプトだと荷が重いかもしれません。 不可能ではないでしょうが、私なら別の言語を使います。
追記1 (2016/12/06 00:12): kernel-config-check.py
kernel config checkには kernel-config-check.py とか / “kernel config 生成(略記)のためのシェルスクリプト - 何とは言わない天然水飲みたさ” https://blog.cardina1.red/2016/12/06/kernel-config-shellscript/
kernel-config-check.py
というものを公開している方がいらっしゃるようで、これを使うと、インストール済のパッケージが要求するカーネルオプションを網羅できるようです。
すごい!
便利!
圧倒的感謝!!