目次
Debian システム上でプログラミングを学ぶ人がパッケージ化されたソースコードを読み込めるようになるための指針を示します。以下はプログラムに関する特記すべきパッケージと対応する文書パッケージです。
オンラインリファレンスは manpages
と manpages-dev
パッケージをインストールした後で "man name
" とタイプすると利用可能です。GNU
ツールのオンラインリファレンスは該当する文書パッケージをインストールした後で "info
program_name
" とタイプすると使えます。一部の GFDL 文書は DFSG に準拠していないと考えられているので
main
アーカイブに加えて contrib
や
non-free
アーカイブを含める必要があるかもしれません。
バージョン コントロール システム ツールの使用を考えましょう。「Git」を参照下さい。
警告 | |
---|---|
" |
注意 | |
---|---|
ソースから直接コンパイルしたソフトウェアープログラムは、システムプログラムとかち合わないように、" |
ヒント | |
---|---|
"99ボトルのビールの歌" 作成のコード例はほとんど全てのプログラム言語に関する理解のための非常に好適です。 |
シェルスクリプトは実行ビットがセットされたテキストファイルで、以下に示すフォーマットのコマンドを含んでいます。
#!/bin/sh ... command lines
最初の行はこのファイル内容を読み実行するシェルインタープリタを指定します。
シェルスクリプトを読むのは Unix 的なシステムがどのように機能しているのかを理解する最良の方法です。ここでは、シェルプログラムに関する指針や心がけを記します。失敗から学ぶために "シェルの失敗" (https://www.greenend.org.uk/rjk/2001/04/shell.html) を参照下さい。
シェル対話モード (「シェルプロンプト」と「Unix 的テキスト処理」を参照下さい) と異なり、シェルスクリプトは変数や条件文やループを繁用します。
多くのシステムスクリプトは POSIX シェル (表1.13「シェルプログラムのリスト」を参照下さい) のどれで解釈されるか分かりません。
デフォールトの非インタラクティブなシェル "/usr/bin/sh
" は
/usr/bin/dash
をさしているシムリンクで、多くのシステムプログラムで使われます。
デフォルトのインタラクティブなシェルは /usr/bin/bash
です。
全ての POSIX シェル間でポータブルとするために bashisms や
zshisms
を使うシェルスクリプトを書くのを避けます。checkbashisms
(1) を使うとこれがチェックできます。
表12.1 典型的 bashizms のリスト
推薦: POSIX | 回避すべき: bashism |
---|---|
if [ "$foo" = "$bar" ] ; then … |
if [ "$foo" == "$bar" ] ; then … |
diff -u file.c.orig file.c |
diff -u file.c{.orig,} |
mkdir /foobar /foobaz |
mkdir /foo{bar,baz} |
funcname() { … } |
function funcname() { … } |
8進表記: "\377 " |
16進表記: "\xff " |
"echo
"
コマンドはその実装がシェルビルトインや外部コマンド間で相違しているので以下の注意点を守って使わなければいけません。
"-n
" 以外のどのコマンドオプション使用も避けます。
文字列中にエスケープシーケンスはその取扱いに相違があるので使用を避けます。
注記 | |
---|---|
" |
ヒント | |
---|---|
出力文字列にエスケープシーケンスを埋め込む必要がある場合には、" |
特別なシェルパラメーターがシェルスクリプト中ではよく使われます。
表12.2 シェル変数のリスト
シェル変数 | 変数値 |
---|---|
$0 |
シェルまたはシェルスクリプトの名前 |
$1 |
最初 (1番目) のシェル引数 |
$9 |
9番目のシェル引数 |
$# |
シェル引数の数 |
"$*" |
"$1 $2 $3 $4 … " |
"$@" |
"$1" "$2" "$3" "$4" … |
$? |
最新のコマンドの終了状態 |
$$ |
このシェルスクリプトの PID |
$! |
最近スタートしたバックグラウンドジョブの PID |
覚えておくべき基本的なパラメーター展開を次に記します。
表12.3 シェル変数展開のリスト
パラメーター式形 | var が設定されているときの値 |
var が設定されていないときの値 |
---|---|---|
${var:-string} |
"$var " |
"string " |
${var:+string} |
"string " |
"null " |
${var:=string} |
"$var " |
"string " (合わせて "var=string " を実行) |
${var:?string} |
"$var " |
"string " をstderr に出力
(エラーとともに exit する) |
ここで、これら全てのオペレーターのコロン ":
" は実際はオプションです。
":
" 付き = 演算子は存在と非ヌル文字列をテストします
":
" 無し = 演算子は存在のみをテストします
表12.4 重要なシェル変数置換のリスト
パラメーター置換形 | 結果 |
---|---|
${var%suffix} |
最短のサフィックスパターンを削除 |
${var%%suffix} |
最長のサフィックスパターンを削除 |
${var#prefix} |
最短のプレフィックスパターンを削除 |
${var##prefix} |
最長のプレフィックスパターンを削除 |
各コマンドは条件式に使えるエグジットステイタスを返します。
成功: 0 ("真")
エラー: 非0 ("偽")
注記 | |
---|---|
シェル条件文の文脈において "0" は "真" を意味しますが、C 条件文の文脈では "0" は "偽" を意味します。 |
注記 | |
---|---|
" |
覚えておくべき基本的な条件文の慣用句は次です。
"command &&
成功したらこのcommandも実行 || true
"
"command ||
もしcommandが成功しないとこのコマンドも実行 || true
"
以下のような複数行のスクリプト断片
if [ conditional_expression ]; then if_success_run_this_command else if_not_success_run_this_command fi
ここで、シェルが "-e
" フラグ付きで起動された際にシェルスクリプトがこの行で誤って exit
しないようにするために、末尾の "|| true
" が必要です。
表12.5 条件式中のファイル比較演算子
式 | 論理真を返す条件 |
---|---|
-e file |
file が存在する |
-d file |
file が存在しディレクトリーである |
-f file |
file が存在し通常ファイルである |
-w file |
file が存在し書込み可能である |
-x file |
file が存在し実行可能である |
file1 -nt file2 |
file1 が file2 よりも新しい (変更) |
file1 -ot file2 |
file1 が file2 よりも古い (変更) |
file1 -ef file2 |
file1 と file2 は同デバイス上の同 inode 番号 |
表12.6 条件式中での文字列比較演算子のリスト
式 | 論理真を返す条件 |
---|---|
-z str |
str の長さがゼロ |
-n str |
str の長さが非ゼロ |
str1 = str2 |
str1 と str2 は等しい |
str1 != str2 |
str1 と str2 は等しく無い |
str1 < str2 |
str1 のソート順が str2 より前 (ロケール依存) |
str1 > str2 |
str1 のソート順が str2 より後 (ロケール依存) |
条件式中の算術整数比較演算子は "-eq
"
と "-ne
" と "-lt
" と
"-le
" と "-gt
" と
"-ge
" です。
POSIX シェル中で使われるループの慣用句があります。
"for x in foo1 foo2 … ; do コマンド ; done
" は "foo1
foo2 …
" リストの項目を変数 "x
" に代入し
"コマンド
" を実行してループします。
"while 条件 ; do コマンド ; done
" は"条件
"
が真の場合 "コマンド
" を繰り返します。
"until 条件 ; do コマンド ; done
" は"条件
"
が真でない場合 "コマンド
" を繰り返します。
"break
" によってループから脱出できます。
"continue
" によってループ初めに戻り次の反復実行を再開します。
ヒント | |
---|---|
C 言語のような数字の繰り返しは " |
ヒント | |
---|---|
「ファイルに関してループしながらコマンドを反復実行」を参照下さい。 |
普通の人気あるシェル コマンド プロンプトがあなたのスクリプト実行環境下使えないかもしれません。
"$USER
" には "$(id -un)
" を使います
"$UID
" には "$(id -u)
" を使います
"$HOME
" に関して、"$(getent passwd "$(id -u)"|cut -d
":" -f 6)
" を使います (これは「集中システム管理」上でも機能します。)
シェルはおおよそ以下のシーケンスでスクリプトを処理します。
シェルは1行読み込みます。
シェルは、もし "…"
や '…'
の中なら、行の一部を1つのトークンとしてグループします。
シェルは1行を以下のによってトークンに分割します。
空白: space tab
newline
メタ文字: < > | ; & ( )
"…"
や '…'
の中でない場合、シェルは各トークンを予約語に対してチェックしその挙動を調整します。
予約語: if then elif else fi for in
while unless do done case esac
"…"
や '…'
の中でない場合、シェルはエイリアスを展開します。
"…"
や'…'
の中でない場合、シェルはティルダを展開します。
"~
" → 現ユーザーのホームディレクトリー
"~user
" →
user
のホームディレクトリー
'…'
の中でない場合、シェルは パラメーター"をその値に展開します。
パラメーター: "$PARAMETER
"
or "${PARAMETER}
"
'…'
の中でない場合、シェルは コマンド置換を展開します。
"$( command )
" → "command
" の出力
"` command `
" → "command
" の出力
"…"
や '…'
の中でない場合、シェルは パス名のグロブを展開します。
*
→ あらゆる文字
?
→ 1文字
[…]
→ "…
" 中の1つ
シェルはコマンドを次から検索して実行します。
関数定義
ビルトインコマンド
"$PATH
" 中の実行ファイル
シェルは次行に進みこのプロセスを一番上から順に反復します。
ダブルクォート中のシングルクォートに効果はありません。
シェル環境中で "set -x
" を実行したり、シェルを "-x
"
オプションで起動すると、シェルは実行するコマンドを全てプリントするようになります。これはデバグをするのに非常に便利です。
Debian システム上でできるだけポータブルなシェルプログラムとするには、ユーティリティープログラムを essential パッケージで提供されるプログラムだけに制約するのが賢明です。
"aptitude search ~E
" はessential (必須) パッケージをリストします。
"dpkg -L パッケージ名 |grep '/man/man.*/'
"
は パッケージ名
パッケージによって提供されるコマンドのマンページをリストします。
表12.7 シェルスクリプト用の小さなユーティリティープログラムを含むパッケージのリスト
パッケージ | ポプコン | サイズ | 説明 |
---|---|---|---|
dash
|
V:884, I:997 | 191 | sh 用の小型で高速の POSIX 準拠シェル |
coreutils
|
V:880, I:999 | 18307 | GNU コアユーティリティー |
grep
|
V:782, I:999 | 1266 | GNU grep , egrep and
fgrep |
sed
|
V:790, I:999 | 987 | GNU sed |
mawk
|
V:442, I:997 | 285 | 小さく高速な awk |
debianutils
|
V:907, I:999 | 224 | Debian 特有の雑多なユーティリティー |
bsdutils
|
V:519, I:999 | 356 | 4.4BSD-Lite 由来の基本ユーティリティー |
bsdextrautils
|
V:596, I:713 | 339 | 4.4BSD-Lite 由来の追加のユーティリティー |
moreutils
|
V:15, I:38 | 231 | 追加の Unix ユーティリティー |
ヒント | |
---|---|
|
例は「Unix 的テキスト処理」を参照下さい。
表12.8 インタープリター関連のパッケージのリスト
パッケージ | ポプコン | サイズ | 文書 |
---|---|---|---|
dash
|
V:884, I:997 | 191 | sh: sh 用の小型高速 POSIX 準拠シェル |
bash
|
V:838, I:999 | 7175 | sh: bash-doc が提供する
"info bash " |
mawk
|
V:442, I:997 | 285 | AWK: 小型高速 awk |
gawk
|
V:285, I:349 | 2906 | AWK: gawk-doc が提供する
"info gawk " |
perl
|
V:707, I:989 | 673 | Perl: perl-doc and
perl-doc-html が提供する perl (1) と html ページ |
libterm-readline-gnu-perl
|
V:2, I:29 | 380 | GNU ReadLine/History ライブラリーのための Perl 拡張: perlsh (1) |
libreply-perl
|
V:0, I:0 | 171 | PerlのREPL: reply (1) |
libdevel-repl-perl
|
V:0, I:0 | 237 | PerlのREPL: re.pl (1) |
python3
|
V:718, I:953 | 81 | Python: python-doc が提供する
python3 (1) と html ページ |
tcl
|
V:25, I:218 | 21 | Tcl: tcl-doc が提供する
tcl (3) と詳細なマンページ |
tk
|
V:20, I:211 | 21 | Tk: tk-doc が提供する
tk (3) と詳細なマンページ |
ruby
|
V:86, I:208 | 29 | Ruby: ruby (1),
erb (1), irb (1),
rdoc (1), ri (1) |
Debian 上のタスクを自動化したい場合には、まず最初にインタープリター言語でタスクをスクリプト化すべきです。 インタープリター言語選択のガイドラインは:
もしタスクがシェルプログラムでできた CLI プログラムを組み合わせる簡単なタスクなら、dash
を使います。
もしタスクが簡単なタスクではなく何もないところから書くなら、python3
を使います。
もしタスクをするための加筆をする必要がある perl
, tcl
,
ruby
, ... で書かれたコードが Debian 上にすでに存在する場合には、その言語を使います。
もし出来上がったコードがおそすぎる場合には、実行速度にクリチカルな部分のみコンパイラー言語で書き直しインタープリター言語から呼びます。
ほとんどのインタープリターは基本的文法チェックやコード追跡の機能を提供します。
“dash -n script.sh” - シェルスクリプトの文法チェック
“dash -x script.sh” - シェルスクリプトのトレース
“python -m py_compile script.py” - Python スクリプトの文法チェック
“python -mtrace --trace script.py” - Python スクリプトのトレース
“perl -I ../libpath -c script.pl” - Perl スクリプトの文法チェック
“perl -d:Trace script.pl” - Perl スクリプトのトレース
dash
のコードチェックの際には、 bash
のようなインタラクティブ環境を用意する「Readline のラッパー」を試します。
perl
のコードチェックの際には、 python
のような Perl 用の REPL
(=READ + EVAL + PRINT + LOOP) 環境を用意する「Readline のラッパー」を試します。
シェルスクリプトは魅力的な GUI プログラムを作るまで改善できます。echo
や
read
コマンドを使う鈍いやりとりに代えて、いわゆるダイアログプログラムを使うのがこのトリックです。
表12.9 ダイアログプログラムのリスト
パッケージ | ポプコン | サイズ | 説明 |
---|---|---|---|
x11-utils
|
V:192, I:566 | 651 | xmessage (1): window 中にメッセージや質問を表示 (X) |
whiptail
|
V:284, I:996 | 56 | シェルスクリプトからユーザーフレンリーなダイアログボックスを表示 (newt) |
dialog
|
V:11, I:99 | 1227 | シェルスクリプトからユーザーフレンリーなダイアログボックスを表示 (ncurses) |
zenity
|
V:76, I:363 | 183 | シェルスクリプトからグラフィカルなダイアログボックスを表示 (GTK) |
ssft
|
V:0, I:0 | 75 | シェルスクリプトフロントエンドツール (gettext を使った zenity や kdialog や dialog のラッパー) |
gettext
|
V:56, I:259 | 5818 | "/usr/bin/gettext.sh ": メッセージ翻訳 |
簡単なシェルスクリプトだけでできるほど GUI プログラムがいかに簡単ということを示す GUI プログラムの例は以下です。
このスクリプトはファイルの選択(デフォルトは/etc/motd
) に
zenity
を使い、それを表示します。
このスクリプトの GUI ローンチャーは以下のようにして生成できます 「GUI からプログラムをスタート」.
#!/bin/sh -e # Copyright (C) 2021 Osamu Aoki <osamu@debian.org>, Public Domain # vim:set sw=2 sts=2 et: DATA_FILE=$(zenity --file-selection --filename="/etc/motd" --title="Select a file to check") || \ ( echo "E: File selection error" >&2 ; exit 1 ) # Check size of archive if ( file -ib "$DATA_FILE" | grep -qe '^text/' ) ; then zenity --info --title="Check file: $DATA_FILE" --width 640 --height 400 \ --text="$(head -n 20 "$DATA_FILE")" else zenity --info --title="Check file: $DATA_FILE" --width 640 --height 400 \ --text="The data is MIME=$(file -ib "$DATA_FILE")" fi
シェル スクリプトでの GUI プログラムへのこのようなアプローチは簡単な選択ケースでのみ有効です。何らかの複雑のあるプログラムを書く場合には、もっと能力あるプラットフォームで書くことを考えましょう。
GUI ファイラー プログラムは、追加の拡張パッケージを使って選択されたファイルに対していくつかの人気ある動作を実行するように拡張できます。また、GUI ファイラー プログラムはあなたの特定のスクリプトを追加することで非常に特定のカスタム動作を実行するようにもできます。
GNOME の場合、NautilusScriptsHowtoを参照下さい。
KDE の場合、Creating Dolphin Service Menusを参照下さい。
Xfce の場合、Thunar - Custom Actions and https://help.ubuntu.com/community/ThunarCustomActionsを参照下さい。
LXDEの場合、Custom Actionsを参照下さい。
データー処理をするためには、cut
や grep
や
sed
等を実行するサブプロセスを起動する必要が sh
ではあり、遅いです。一方、データーを処理する内部機能が perl
ではあり、高速です。そのため、多くの
Debian のシステム メンテナンス スクリプトは perl
を使います。
以下の AWK スクリプトとそれと等価Perl スクリプトの断片を考えましょう。
awk '($2=="1957") { print $3 }' |
これは以下の数行のどれとも等価です。
perl -ne '@f=split; if ($f[1] eq "1957") { print "$f[2]\n"}' |
perl -ne 'if ((@f=split)[1] eq "1957") { print "$f[2]\n"}' |
perl -ne '@f=split; print $f[2] if ( $f[1]==1957 )' |
perl -lane 'print $F[2] if $F[1] eq "1957"' |
perl -lane 'print$F[2]if$F[1]eq+1957' |
最後のスクリプトは謎々状態です。Perl の以下の機能を利用しています。
ホワイトスペースはオプション。
数字から文字列への自動変換が存在します。
コマンドライン オプション経由の Perl 実行トリック集: perlrun
(1)
Perl の特別な変数集: perlvar
(1)
このフレキシビリティーは Perl の強みです。同時に、これは我々に読解不能な絡まったコードを書くことを許容します。だから注意して下さい。
表12.10 コンパイラ関連のパッケージのリスト
パッケージ | ポプコン | サイズ | 説明 |
---|---|---|---|
gcc
|
V:167, I:550 | 36 | GNU C コンパイラ |
libc6-dev
|
V:248, I:567 | 12053 | GNU C ライブラリー: 開発用ライブラリーとヘッダーファイル集 |
g++
|
V:56, I:501 | 13 | GNU C++ コンパイラー |
libstdc++-10-dev
|
V:14, I:165 | 17537 | GNU 標準 C++ ライブラリー v3 (開発用ファイル集) |
cpp
|
V:334, I:727 | 18 | GNU C プリプロセッサ |
gettext
|
V:56, I:259 | 5818 | GNU 国際化ユーティリティ |
glade
|
V:0, I:5 | 1204 | GTK ユーザー インターフェース ビルダー |
valac
|
V:0, I:4 | 725 | GObject システム用の C# に似た言語 |
flex
|
V:7, I:73 | 1243 | LEX 互換の 高速字句解析ジェネレータ |
bison
|
V:7, I:80 | 3116 | YACC互換のパーサジェネレータ |
susv2
|
I:0 | 16 | "The Single UNIX Specifications v2" を取得 |
susv3
|
I:0 | 16 | "The Single UNIX Specifications v3" を取得 |
susv4
|
I:0 | 16 | "The Single UNIX Specifications v4" を取得 |
golang
|
I:20 | 11 | Go プログラミング言語コンパイラー |
rustc
|
V:3, I:14 | 8860 | Rust システム プログラム言語 |
haskell-platform
|
I:1 | 12 | 標準 Haskell ライブラリーとツール |
gfortran
|
V:6, I:62 | 15 | GNU Fortran 95 コンパイラー |
fpc
|
I:2 | 103 | Free Pascal |
ここで、「Flex — 改良版 Lex」と「Bison — 改良版 Yacc」は、コンパイラーのようなプログラムがどのように高レベル記述を C 言語にすることで C 言語で書かれているかを示すために含めています。
C プログラム言語で書かれたプログラムをコンパイルする適正な環境を以下のようにして設定できます。
# apt-get install glibc-doc manpages-dev libc6-dev gcc build-essential
GNU C ライブラリーパッケージである libc6-dev
パッケージは、C
プログラム言語で使われるヘッダーファイルやライブラリールーチンの集合である C
標準ライブラリーを提供します。
C のリファレンスは以下を参照下さい。
"info libc
" (C ライブラリー関数リファレンス)
gcc
(1) と "info gcc
"
各 C ライブラリー関数名
(3)
Kernighan & Ritchie 著, "The C Programming Language", 第2版 (Prentice Hall)
簡単な例の "example.c
" は"libm
"
ライブラリーを使って実行プログラム "run_example
" に以下のようにしてコンパイル出来ます。
$ cat > example.c << EOF #include <stdio.h> #include <math.h> #include <string.h> int main(int argc, char **argv, char **envp){ double x; char y[11]; x=sqrt(argc+7.5); strncpy(y, argv[0], 10); /* prevent buffer overflow */ y[10] = '\0'; /* fill to make sure string ends with '\0' */ printf("%5i, %5.3f, %10s, %10s\n", argc, x, y, argv[1]); return 0; } EOF $ gcc -Wall -g -o run_example example.c -lm $ ./run_example 1, 2.915, ./run_exam, (null) $ ./run_example 1234567890qwerty 2, 3.082, ./run_exam, 1234567890qwerty
ここで、"-lm
" はsqrt
(3) のために
libc6
パッケージで提供されるライブラリー
"/usr/lib/libm.so
" をリンクするのに必要です。実際のライブラリーは
"/lib/
" 中にあるファイル名 "libm.so.6
" で、それは
"libm-2.7.so
" にシムリンクされています。
出力テキスト中の最後のパラメーターを良く見ましょう。"%10s
"
が指定されているにもかかわらず10文字以上あります。
上記のオーバーラン効果を悪用するバッファーオーバーフロー攻撃を防止のために、sprintf
(3) や
strcpy
(3) 等の境界チェック無しのポインターメモリー操作関数の使用は推奨できません。これに代えて
snprintf
(3) や strncpy
(3) を使います。
flex
(1) の入門書は "info flex
" の中にあります。
シンプルな例が "/usr/share/doc/flex/examples/
" の下にあります。
[7]
Yacc 互換の前方参照可能な LR パーサーとか LALR パーサー生成ソフトは、いくつかのパッケージによって Debian 上で提供されています。
bison
(1) の入門書は "info bison
" の中にあります。
あなた自身の "main()
" と "yyerror()
"
を供給する必要があります。"main()
" は、Flex によって通常作成された
"yylex()
" を呼び出す "yyparse()
" を呼び出します。
シンプルなターミナル上の計算機プログラムの作成例をここに示します。
example.y
を作成しましょう:
/* calculator source for bison */ %{ #include <stdio.h> extern int yylex(void); extern int yyerror(char *); %} /* declare tokens */ %token NUMBER %token OP_ADD OP_SUB OP_MUL OP_RGT OP_LFT OP_EQU %% calc: | calc exp OP_EQU { printf("Y: RESULT = %d\n", $2); } ; exp: factor | exp OP_ADD factor { $$ = $1 + $3; } | exp OP_SUB factor { $$ = $1 - $3; } ; factor: term | factor OP_MUL term { $$ = $1 * $3; } ; term: NUMBER | OP_LFT exp OP_RGT { $$ = $2; } ; %% int main(int argc, char **argv) { yyparse(); } int yyerror(char *s) { fprintf(stderr, "error: '%s'\n", s); }
example.l
を作成しましょう:
/* calculator source for flex */ %{ #include "example.tab.h" %} %% [0-9]+ { printf("L: NUMBER = %s\n", yytext); yylval = atoi(yytext); return NUMBER; } "+" { printf("L: OP_ADD\n"); return OP_ADD; } "-" { printf("L: OP_SUB\n"); return OP_SUB; } "*" { printf("L: OP_MUL\n"); return OP_MUL; } "(" { printf("L: OP_LFT\n"); return OP_LFT; } ")" { printf("L: OP_RGT\n"); return OP_RGT; } "=" { printf("L: OP_EQU\n"); return OP_EQU; } "exit" { printf("L: exit\n"); return YYEOF; } /* YYEOF = 0 */ . { /* ignore all other */ } %%
そして、これを試すためにシェルプロンプトから以下を実行しましょう:
$ bison -d example.y $ flex example.l $ gcc -lfl example.tab.c lex.yy.c -o example $ ./example 1 + 2 * ( 3 + 1 ) = L: NUMBER = 1 L: OP_ADD L: NUMBER = 2 L: OP_MUL L: OP_LFT L: NUMBER = 3 L: OP_ADD L: NUMBER = 1 L: OP_RGT L: OP_EQU Y: RESULT = 9 exit L: exit
静的解析(lint) のようなツールは、自動静的コード分析に役立ちます。
Indent のようなツールは整合性をもってソースコードの再フォーマットすることで人間によるコードレビューを助けます。
Ctags のようなツールは、ソースコード中に見つかる名前のインデックス(とかタグ)を生成することで、人間がコードのレビューするのを助けます。
ヒント | |
---|---|
あなたの好きなエディター ( |
表12.12 静的コード分析ツールのリスト
パッケージ | ポプコン | サイズ | 説明 |
---|---|---|---|
vim-ale
|
I:0 | 2591 | Vim 8 や NeoVim 用の非同期静的解析エンジン |
vim-syntastic
|
I:3 | 1379 | Vim 用のシンタックスシェックのハック |
elpa-flycheck
|
V:0, I:1 | 808 | Emacs 用の現代的な同時進行のシンタックスチェック |
elpa-relint
|
V:0, I:0 | 147 | Emacs Lisp の正規表現 (regexp) の間違い検出器 |
cppcheck-gui
|
V:0, I:1 | 7224 | 静的 C/C++ コード分析ツール (GUI) |
shellcheck
|
V:2, I:13 | 18987 | シェルスクリプトの静的解析(lint)ツール |
pyflakes3
|
V:2, I:15 | 20 | Python 3 の受動チェッカー |
pylint
|
V:4, I:20 | 2018 | Python コード静的チェックソフト |
perl
|
V:707, I:989 | 673 | 静的コードチェックソフト付きのインタープリタ: B::Lint (3perl) |
rubocop
|
V:0, I:0 | 3247 | Ruby 静的コード分析ツール |
clang-tidy
|
V:2, I:11 | 21 | Clang に基づく C++ の静的解析(lint)ツール |
splint
|
V:0, I:2 | 2320 | C プログラムを静的にバグのチェックするためのツール |
flawfinder
|
V:0, I:0 | 205 | C/C++ ソースコードを検査してセキュリティーの脆弱性を探すツール |
black
|
V:3, I:13 | 660 | 非妥協的な Python コードフォーマッター |
perltidy
|
V:0, I:4 | 2493 | Perl スクリプトのインデントとリフォーマット |
indent
|
V:0, I:7 | 431 | C 言語ソースコード フォーマッター プログラム |
astyle
|
V:0, I:2 | 785 | C と C++ と Objective-C と C# と Java のソースコード インデンター |
bcpp
|
V:0, I:0 | 111 | C(++) の美化プログラム |
xmlindent
|
V:0, I:1 | 53 | XML ストリームリフォーマッタ |
global
|
V:0, I:2 | 1908 | ソースコードの検索と閲覧のツール |
exuberant-ctags
|
V:2, I:20 | 341 | ソースコード定義のタグファイルのインデックスの構築 |
universal-ctags
|
V:1, I:11 | 3386 | ソースコード定義のタグファイルのインデックスの構築 |
デバッグはプログラミング活動において重要です。プログラムのデバッグ法を知ることで、あなたも意味あるバグリポートを作成できるような良い Debian ユーザーになれます。
Debian 上の第一義的デバッガは、実行中のプログラムを検査できるようにする
gdb
(1) です。
gdb
と関連プログラムを以下のようにインストールしましょう。
# apt-get install gdb gdb-doc build-essential devscripts
gdb
のよいチュートリアルについては以下を参照下さい:
“info gdb
”
/usr/share/doc/gdb-doc/html/gdb/index.html
中の “Debugging
with GDB”
次は gdb
(1) を"-g
" を使ってデバッグ情報を付けてコンパイルされた
"program
" に使う簡単な例です。
$ gdb program (gdb) b 1 # set break point at line 1 (gdb) run args # run program with args (gdb) next # next line ... (gdb) step # step forward ... (gdb) p parm # print parm ... (gdb) p parm=12 # set value to 12 ... (gdb) quit
ヒント | |
---|---|
多くの |
全てのインストールされたバイナリーはデフォルトでは Debian
システム上ではストリップされているべきなので、ほとんどのデバグシンボルは普通のパッケージからは除かれています。gdb
(1)
を使って Debian パッケージをデバグするためには、*-dbgsym
パッケージ(例えばcoreutils
の場合は
coreutils-dbgsym
)をインストールする必要があります。ソースパッケージは、普通のバイナリーパッケージとともに
*-dbgsym
パッケージを自動生成し、そうしたデバグパッケージは別にして debian-debug アーカイブ中に置かれます。詳細は Debian Wiki の記事を参照下さい。
デバッグしようとしているパッケージに*-dbgsym
パッケージが無い場合は、以下のようにしてリビルドした後でインストールする必要があります。
$ mkdir /path/new ; cd /path/new $ sudo apt-get update $ sudo apt-get dist-upgrade $ sudo apt-get install fakeroot devscripts build-essential $ apt-get source package_name $ cd package_name* $ sudo apt-get build-dep ./
必要に応じてバグを修正します。
例えば以下のように、既存パッケージを再コンパイルする時は "+debug1
"
を後ろに付けたり、リリース前のパッケージをコンパイルする時は "~pre1
" を後ろに付けたりと、正規の
Debian バージョンとかち合わないようにパッケージバージョンを増やします。
$ dch -i
以下のようにしてデバグシンボル付きでパッケージをコンパイルしてインストールします。
$ export DEB_BUILD_OPTIONS="nostrip noopt" $ debuild $ cd .. $ sudo debi package_name*.changes
パッケージのビルドスクリプトを確認して、バイナリーのコンパイルに確実に "CFLAGS=-g -Wall
"
が使われているようにします。
プログラムがクラッシュするのに出会った場合に、バックトレース情報をバグレポートに切り貼りして報告するのは良い考えです。
バックトレースはgdb
(1) によって以下のような段取りで得られます。
GDBの中でクラッシュ アプローチ:
GDB からプログラムを実行します。
プログラムがクラッシュします。
GDB プロンプトで "bt
" と打ちます。
先にクラッシュ アプローチ:
無限ループやキーボードが凍結した場合、Ctrl-\
か Ctrl-C
を押すか “kill -ABRT PID
”
を実行することでプログラムを強制終了できます。(「プロセスの停止」を参照下さい)
ヒント | |
---|---|
しばしば、一番上数行が " $ MALLOC_CHECK_=2 gdb hello |
表12.14 高度な gdb コマンドのリスト
コマンド | コマンド目的の説明 |
---|---|
(gdb) thread apply all bt |
マルチスレッドプログラムの全てのスレッドのバックトレースを取得 |
(gdb) bt full |
関数コールのスタック上に来たパラメーターを取得 |
(gdb) thread apply all bt full |
異常のオプションの組み合わせでバックトレースとパラメーターを取得 |
(gdb) thread apply all bt full 10 |
無関係の出力を切り最後の10のコールに関するバックトレースとパラメーターを取得 |
(gdb) set logging on |
gdb アウトプットをファイルに書き出す (デフォールトは
"gdb.txt ") |
以下のように ldd
(1) を使ってプログラムのライブラリーへの依存関係をみつけだします。
$ ldd /usr/bin/ls librt.so.1 => /lib/librt.so.1 (0x4001e000) libc.so.6 => /lib/libc.so.6 (0x40030000) libpthread.so.0 => /lib/libpthread.so.0 (0x40153000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
`chroot` された環境下で ls
(1) が機能するには、上記ライブラリーがあなたの `chroot`
された環境内で利用可能である必要があります。
「プログラム活動の追跡」を参照下さい。
Debian 中に複数の動的呼び出し追跡ツールがあります。「プログラム活動の監視と制御と起動」 を参照下さい。
GNOME プログラム preview1
が X エラーを受けると、以下のようなメッセージが見つかります。
The program 'preview1' received an X Window System error.
このような場合には、プログラムを "--sync
" 付きで実行して、バックトレースを得るために
"gdk_x_error
" 関数上で停止するようにしてみます。
Debian にはメモリーリークを検出するプログラムがいくつか利用可能です。
表12.15 メモリーリーク検出ツールのリスト
パッケージ | ポプコン | サイズ | 説明 |
---|---|---|---|
libc6-dev
|
V:248, I:567 | 12053 | mtrace (1): glibc 中の malloc デバッグ機能 |
valgrind
|
V:6, I:37 | 78191 | メモリーデバッガとプロファイラ |
electric-fence
|
V:0, I:3 | 73 | malloc (3) デバッガ |
libdmalloc5
|
V:0, I:2 | 390 | メモリーアロケーションのデバグ用ライブラリー |
duma
|
V:0, I:0 | 296 | C および C++ プログラムのバッファオーバーランとアンダーランを検出するライブラリー |
leaktracer
|
V:0, I:1 | 56 | C++ プログラム用のメモリーリーク追跡ソフト |
表12.16 ビルドツールパッケージのリスト
パッケージ | ポプコン | サイズ | 文書 |
---|---|---|---|
make
|
V:151, I:555 | 1592 | make-doc が提供する "info make " |
autoconf
|
V:31, I:230 | 2025 | autoconf-doc が提供する "info autoconf |
automake
|
V:30, I:228 | 1837 | automake1.10-doc が提供する "info automake " |
libtool
|
V:25, I:212 | 1213 | libtool-doc が提供する "info libtool " |
cmake
|
V:17, I:115 | 36607 | クロスプラットフォームでオープンソースの make システム cmake (1) |
ninja-build
|
V:6, I:41 | 428 | Make と似た精神の小さなビルドシステム ninja (1) |
meson
|
V:3, I:22 | 3759 | ninja の上に構築された高生産性のビルドシステム meson (1) |
xutils-dev
|
V:0, I:9 | 1484 | imake (1), xmkmf (1), 他 |
Make
はプログラムのグループを管理するためのユーティリティーです。make
(1)
を実行すると、make
は"Makefile
"
というルールファイルを読み、ターゲットが最後に変更された後で変更された前提ファイルにターゲットが依存している場合やターゲットが存在しない場合にはターゲットを更新します。このような更新は同時並行的にされるかもしれません。
ルールファイルのシンタックスは以下の通りです。
target: [ prerequisites ... ] [TAB] command1 [TAB] -command2 # ignore errors [TAB] @command3 # suppress echoing
上記で、"[TAB]
" は TAB コードです。各行は make
による変数置換後シェルによって解釈されます。スクリプトを継続する行末には "\
"
を使います。シェルスクリプトの環境変数のための "$
" を入力するためには
"$$
" を使います。
ターゲットや前提に関するインプリシット (暗黙) ルールは、例えば以下のように書けます。
%.o: %.c header.h
上記で、ターゲットは "%
" という文字を (1つだけ)
含んでいます。"%
"
は実際のターゲットファイル名の空でないいかなる部分文字列ともマッチします。前提もまた同様にそれらの名前が実際のターゲットファイル名にどう関連するかを示すために
"%
" を用いることができます。
表12.17 make の自動変数のリスト
自動変数 | 変数値 |
---|---|
$@ |
ターゲット |
$< |
最初の前提条件 |
$? |
全ての新規の前提条件 |
$^ |
全ての前提条件 |
$* |
"% " はターゲットパターンの軸にマッチします |
"make -p -f/dev/null
" を実行して自動的な内部ルールを確認下さい。
Autotools は多くの Unix-like システムに移植可能なソースコードパッケージを作ることを援助するように設計された一連のプログラムツールです。
警告 | |
---|---|
システムファイルをあなたがコンパイルしたプログラムでインストールする時に上書きしてはいけません。 |
Debian は"/usr/local/
" とか "/opt
"
中のファイルに触れません。プログラムをソースからコンパイルする場合、Debian とかち合わないようにそれを
"/usr/local/
" の中にインストールします。
$ cd src $ ./configure --prefix=/usr/local $ make # this compiles program $ sudo make install # this installs the files in the system
オリジナルのソースを保有し、それが
autoconf
(1)/automake
(1)
と使用しあなたがそれをどう設定したかを覚えているなら、以下のように実行してソフトウェアーをアンイストールします。
$ ./configure all-of-the-options-you-gave-it
$ sudo make uninstall
この代わりに、"/usr/local/
"
の下にだけインストールプロセスがファイルを置いたことが絶対に確実でそこに重要なものが無いなら、以下のようにしてその内容を消すことが出来ます。
# find /usr/local -type f -print0 | xargs -0 rm -f
どこにファイルがインストールされるか良く分からない場合には、checkinstall
パッケージにある
checkinstall
(8)
を使いアンインストールする場合クリーンなパスとなるようにすることを考えましょう。これは "-D
"
オプションを使うと Debian パッケージを作成できます。
ソフトウェアービルドシステムは進化してきています:
Make の上に構築された Autotools は 1990 年代より移植可能なビルドインフラのデファクトスタンダードです。これは非常に遅いです。
2000 年に最初にリリースされた CMake は、スピードが大幅向上させたが、依然として本質的に遅い Make の上に構築されていました。(現在は、Ninja がバックエンドで使えます。)
2012 年に最初にリリースされた Ninja は、さらなるビルド速度の向上のために Make の置き換えを意図し、その入力ファイルはハイレベルビルドシステムが生成するように設計されています。
2013 年に最初にリリースされた Meson は、新しく人気ある Ninja をバックエンドに使うハイレベルビルドシステムです。
"The Meson Build system" や "The Ninja build system" にある文書を参照下さい。
基本的な対話式動的ウェッブページは以下のようにして作られます。
質問 (クエリー) はブラウザーのユーザーに HTML フォームを使って提示されます。
フォームのエントリーを埋めたりクリックすることによって以下の符号化されたパラメーター付きの URL 文字列をブラウザーからウェッブサーバーに送信します。
"https://www.foo.dom/cgi-bin/program.pl?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3
"
"https://www.foo.dom/cgi-bin/program.py?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3
"
"https://www.foo.dom/program.php?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3
"
URL 中の "%nn
" は16進数で nn
の値の文字と置き換えられます。
環境変通は以下のように設定されます: "QUERY_STRING="VAR1=VAL1 VAR2=VAL2
VAR3=VAL3"
".
ウェッブサーバー上の CGI プログラム
("program.*
" のいずれでも) が環境変数
"$QUERY_STRING
" の下で実行されます。
CGI プログラムの STDOUT
(標準出力)
がウエブブラウザーに送られ対話式の動的なウェッブページとして表示されます。
セキュリティー上、CGI パラメーターを解釈する手作りの急ごしらえのプログラムは作らない方が賢明です。Perl や Python にはこのための確立したモジュールが存在します。PHP はこの様な機能が同梱されています。クライアントでのデーターのストレージの必要がある場合、HTTP クッキーが使われます。クライアントサイドのデーター処理が必要な場合、Javascript が良く使われます。
詳しくは、Common Gateway Interface や The Apache Software Foundation や JavaScript を参照下さい。
https://www.google.com/search?hl=en&ie=UTF-8&q=CGI+tutorial を URL として直接ブラウザーのアドレスに入れ Google で"CGI tutorial" を検索するとグーグルサーバー上の CGI スクリプトが動いているのを観察する良い例です。
Debian パッケージを作りたい場合には、次を読みましょう。
基本的なパッケージシステムの理解には2章Debian パッケージ管理
基本的なポーティングプロセスの理解のために、「安定版システムへのパッケージ移植」
基本的な chroot 技術の理解のために、「Chroot システム」
debuild
(1) と sbuild
(1)
リコンパイルとデバグは「Debian パッケージのデバグ」
Guide for Debian
Maintainers (debmake-doc
パッケージ)
Debian Developer's
Reference (developers-reference
パッケージ)
Debian ポリシーマニュアル
(debian-policy
パッケージ)
debmake
や dh-make
や
dh-make-perl
等のパッケージングを補助するパッケージがあります。