読解の対象 - Red Hatpeople.redhat.com/yamato/talks/reading/slides/0/02target.pdf$ git submodule...

Post on 28-Jul-2020

5 views 0 download

Transcript of 読解の対象 - Red Hatpeople.redhat.com/yamato/talks/reading/slides/0/02target.pdf$ git submodule...

読解の対象著者: 大和 正武 <yamato@redhat.com>

生成日時: 20151102-17:59

Copyright © 2013 Red Hat, K.K.Copyright © 2015 Red Hat, K.K.

The text of and illustrations in this document are licensed by RedHat under a Creative Commons Attribution–Share Alike 3.0 Unportedlicense ("CC-BY-SA"). An explanation of CC-BY-SA is available athttp://creativecommons.org/licenses/by-sa/3.0/. In accordance withCC-BY-SA, if you distribute this document or an adaptation of it,you must provide the URL for the original version.

アウトライン

•なぜC言語か

•ソースコードの位置付け

•ソースコードの入手と配置

•ソースコードツリーの構成

2

なぜC言語か

•本演習では読解の対象をC言語で記述されたソースコードとする。

•C言語は実世界で広く使われている。

•高度な言語機能が欠けているため読解が容易である。

3

実世界でのC言語の利用: FOSSでの利用例

• linuxカーネル

•qemuプロセッサエミュレータ

•apacheウェブサーバ

•openssl暗号化ツールキット

•ruby言語処理系

•Xウィンドウシステム

•postgresqlデータベース

•以前のgccコンパイラコレクション(最近C++へ移行した)

•bindネームサーバ

•sendmail Mail Tranfer Agent

• gimpフォトレタッチソフトウェア

4

読解を阻害する高度な言語機能の欠如

•プログラミング言語の機能の多くが、ソースコードを書くことの支援を目的とている。

•読む側にとっては「逆支援」となる高度な機能がある。

•独立した複数の名前空間とその操作

•関数の多重定義

•匿名関数

•ランタイムライブラリ•C言語にはそのような高度な機能が無い。

•字面と実行内容の間の差異が小さい。

•記述全体では冗長になるが、一つの記述の理解は容易となる。

5

言語機能とプログラムの記述

言語Xであれば文法という形で言語処理系が提供している機能をソフトウェア開発者がC言語で記述するかライブラリを使うかして実現する必要がある。

目的のソフトウェアを記述に必要な言語機能

C 言語が提供する機能の水準

より高機能

言語Xが提供する機能の水準

言語Xで文法/処理系に隠れて見えなった仕掛けが対象ソフトウェアのソースコードに直接記載されている。

読解者の立場 開発者の立場

6

高度な言語機能(1)

独立した複数の名前空間とその操作

•プログラムが複数のモジュールから構成されているとする。

•変数、型、関数などの名前の一意性がモジュール毎に独立している。 (独立した名前空間を持つ)

•開発者への影響

•他のモジュールとの名前の衝突を気にする必要無く書ける。•読解者への影響

•名前だけを文字列検索しても複数の定義がみつかってしまう。

•モジュールを特定する必要がある。

7

独立した複数の名前空間とその操作

Ruby言語での例

1 # A.rb2 require 'DB'3 require 'FILE'4 # ...5 h = open()6 # ...

1 # DB.rb2 # module DB3 def open()4 ...5 return handle6 end

A.rbを読んでいて出てきたopenはどこに定義されているのか? DB.rb, FILE.rbを調べる必要がある。

8

独立した複数の名前空間とその操作

もしC言語だったら

1 /* ... */2 #include "DB.h"3 #include "FILE.h"4 5 DB_HANDLE * h;6 7 /* ... */8 h = db_open();9 /* ... */

•名前の衝突を避けるために、きっと db_ か何かプレフィックスをつける。

•db_ から DB.hに由来していることが想像がつく。

•由来の想像がつかないようなプレフィックスであっても、その名前に対する 定義は一つのはずなので、文字列検索で定義箇所を特定できる。

•(変数の型もヒントとなる。)

9

高度な言語機能(2): 関数の多重定義

• C++言語やJava言語では同じ名前で引数の型や個数(シグネチャー)が異なる関数を定義できる。

•読解者への影響

•関数名だけで文字列検索しても複数の定義がみつかってしまう。

•関数の実引数の型と個数を踏まえて定義を探さないといけない。

10

関数の多重定義

1 // ここに関心が湧いた。 2 return add(3); 3 // ... 4 5 int add(int x, int y) 6 { 7 return x + y; 8 } 9 10 int add(int x)11 {12 return x + 1;13 }

• addだけを探しても定義を確定できない。

•C言語には多重定義機能は無い。

11

高度な言語機能(3): 匿名関数名前の無い関数(匿名関数)を定義できる言語がある。 JavaScriptの例を示す。

(function (x, y) { return x + y; }) (2, 3);=> 5

• (使われる場所の近くに定義された関数の方が読みやそうである。)

•名前がついていないので、メモとして記録したり、覚えたり、人に伝 えるのがむずかしい。

•C言語には匿名関数は無い。

12

匿名関数

余談: C言語の匿名構造体型

struct { int x; int y;} point = { 0, 0 };

構造体変数pointの型を指し示す名前が無い。

13

高度な言語機能(4): ランタイム環境

•ランタイム環境(=裏方)の活躍により、ソースコードが簡潔となる。

•インタプリタ型言語

•インタプリタがプログラム実行の「裏方」の役割を担う。•コンパイル型言語

•ランタイムライブラリがプログラム実行の「裏方」の役割を担う。•裏方の例: ガベージコレクター(GC)

•プログラムのどこからも参照されなくなったメモリオブジェクトを 再利用できるように、自動的に回収してくれる。

•開発者への影響

•明示的に開放を指示する必要が無い。

•開放し忘れや二重開放によるバグを気にする必要が減る。•読解者への影響

•変数の参照がいつまで続くかわからないので、いつまでもその変数を気にしておかなければいけない。

14

ランタイム環境

手動によるメモリ管理と読解

struct Data * data;

data = malloc(sizeof(struct Data));...free(data);...

• free呼び出しの後dataを参照しないはずである。

•このfreeを呼び出しを最後にdataについて、一旦忘れることができる。

•もしdataが再度出てきたら、...読み間違いかバグである。

15

ソースコードの位置付け

プロセス

libx.soライブラリ

liby.soライブラリ

バイナリコード

関心の対象

p.c q.c r.c

p.o q.o r.o

主要な読解の対象

ソースコード

オブジェクトファイル

コンパイル処理

リンク処理

ビルド処理

A.h

r.c.in A.h.in

ソースコード生成処理

B.h

a.out実行ファイル

実行

16

ソースコードの位置付け

•実行内容に関心がある。

•実行内容はバイナリコードに由来する。

•バイナリコードのソースコードを読む。

バイナリコードの分類

•バイナリコードは実行ファイルと共有ライブラリに分類できる。

•実行ファイルは主に/usr/bin以下に配置される。

•共有ライブラリファイルは/usr/libあるいは/usr/lib64以下に配置される。

•共有ライブラリファイルは拡張子*.soを持つ。

•ライブラリの例

•画面描画

•暗号化処理

•データ圧縮

17

ソースコードの位置付け

バイナリコードの要素

•実行ファイルは0個以上の共有ライブラリとリンクされている。

•実行ファイルやライブラリは1つ以上のソースコードファイルから成る。

•各ソースコード(拡張子.c)はコンパイルされてオブジェクトファイル(.oとなる)。

•リンクはリンカが担当する。

•後に登場するソースコード生成処理とコンパイル、リンク処理をまとめてビルド処理と呼ぶ。

•リンク処理とコンパイル処理はgccパッケージに含まれるgccコマンドが担当する。

•特に指定しなかった場合、gccは生成する実行ファイルの名前をa.outとする。

•本演習ではa.outを実行ファイル名の総称として用いる。

•デモ

gcc -vgcc -dumpsepcs (gcc5)

18

ソースコードの位置付け

ソースコード

• C言語で記述されたソースコードの拡張子は.cあるいは.hとなる。

•.hファイルを特にヘッダファイルと呼ぶ。

•ヘッダファイルは1つ以上の.cファイルから共通に参照される。

19

ソースコードの位置付け

ビルド処理

•一部のソースコードをビルド時に生成するような工程を持つソフトウェアもある。

•ソースコード生成の例

•ビルドコンフィギュレーションを反映したヘッダファイルを生成する。

•インターネット経由で技術仕様書をダウンロードして、その技術仕様書の内容の 一部をC言語へ変換する。

•ソースコード生成を含めビルド処理はソフトウェア毎に異なる。

•コードリーディングによってバイナリコードの疑問を解くには、ビルド処理を遡る必要 がある。

•実行ファイル、ライブラリの特定

•オブジェクトファイルの特定

• .cファイル、ヘッダファイルの特定

• (生成されている場合).cファイル、ヘッダファイルの出自の特定

20

ソースコードの入手と配置

•ソースコードが無いとソースコードを読むことはできない。

•入手して読める場所に読める形で配置することはコードリーディングの技術の一部である。

•本演習で対象とするのはFOSSなので、ソースコードを入手できるはずである。

21

ソースコードの入手と配置

配置先本気でリーディングに取り組む場合、配置先を決めておく。

本演習では、入手先に応じて3つのディレクトリを使う。

•~/upstream

• ~/released

• ~/fedora

22

ソースコードの入手と配置

入手先

vcsリポジトリ

ftp or webサイト

パッケージリポジトリ

Fedoraプロジェクトにて公開* リポジトリの場所はyumdownloaderが知っている。

バージョン番号をつけてリリース

取り込み、改変

ローカルファイルシステム

git, svn, cvsなどのコマンド使って取り出す。

ftp or webクライアントでダウンロードする。

yumdownloaderでダウンロードする。

アップストリームプロジェクトにて公開* vcsリポジトリやftp/webサイトの場所はウェブ検索などで探す。* vcsリポジトリを公開していないプロジェクトもある。

23

アップストリームプロジェクトからの入手

アップストリームプロジェクトからの入手したくなる理由

1.そもそもFedora経由でソフトウェアが提供されていない。

2.最新版が必要である

3.ソースコードを読むにあたりFedoraで施された調整を排除したい。

24

アップストリームプロジェクトからの入手

Fedora経由でソフトウェアが提供されていない場合ソフトウェアの名称を手掛かりにウェブ検索して探す。

25

アップストリームプロジェクトからの入手

Fedora経由のパッケージになっている場合

• rpmで手に入るパッケージ情報中のURLをヒントに探す。

•例: lsコマンドの最新版を探す。

1. 目的のソフトウェアに対するファイルを特定する

$ which ls/usr/bin/ls

2. ファイル名からパッケージ名を特定する。

$ rpm -qf /usr/bin/lscoreutils-8.15-7.fc17.x86_64

3. パッケージの情報を表示する。

$ rpm -qi coreutils-8.15-7.fc17.x86_64Name : coreutils...

26

URL : http://www.gnu.org/software/coreutils/...

•演習

27

アップストリームプロジェクトからの入手

gitによるチェックアウトリポジトリの場所についてはプロジェクトのウェブページなどから探す。

# yum install git$ git clone リポジトリの場所

•デモ: GNU helloの最新版をチェックアウトしてみます。

$ git clone git://git.savannah.gnu.org/hello.git

• helloが利用するgnulibライブラリもあわせてチェックアウトします。

$ cd hello$ git submodule init$ git submodule update

•演習

28

アップストリームプロジェクトからの入手

subversion(svn)によるチェックアウトリポジトリの場所についてはプロジェクトのウェブページなどから探す。

# yum install subversion$ svn checkout リポジトリの場所

•デモ: apache httpd の最新版をチェックアウトしてみます。

$ svn checkout http://svn.apache.org/repos/asf/httpd/httpd/trunk

29

アップストリームプロジェクトからの入手

webあるいはftp経由でのダウンロード

• wgetコマンド(コマンドラインベースのクライアント) にURLを指定する。

# yum install wget$ wget URL

•アーカイブ、圧縮されている場合、展開、伸張の必要がある。foo.tar.gz

tar zxvf foo.tar.gzfoo.tar.bz2

tar jxvf foo.tar.bz2foo.tar.xzz

tar Jxvf foo.tar.xz

•デモ: sendmailのリリース版をダウンロードします。

30

$ wget ftp://ftp.sendmail.org/pub/sendmail/sendmail.8.14.6.tar.gz$ tar zxvf ftp://ftp.sendmail.org/pub/sendmail/sendmail.8.14.6.tar.gz

•演習

31

Fedoraの開発プロジェクトのリポジトリからの入手

src.rpmパッケージ

•リポジトリからsrc.rpmパッケージ形式でソースコードを入手できる。

•内訳

specファイルビルド手順を含むパッケージのメタデータを記したファイル

インストール先: ~/rpmbuild/SPECS/foo.specオリジナルソースコード

アップストリームプロジェクトに由来するアーカイブファイル

インストール先: ~/rpmbuild/SOURCES/foo.tar.{gz,bz2,xz}パッチ群

(Red Hatなど)パッケージャが独自に変更した内容を記載したファイル

インストール先: ~/rpmbuild/SOURCES/*.patch

•バイナリの「元」となったソースコードを手に入れるには、オリジナルソース コードにパッチ群を適用するといったソースコード合成の処理が必要となる。

•合成した結果は ~/rpmbuild/BUILD 以下に配置される。

32

Fedoraの開発プロジェクトのリポジトリからの入手

手順の概要

1.ソースパッケージリポジトリの設定変更

2.目的のソフトウェアに対するパッケージ名の特定

3.ソースパッケージのダウンロード

4.依存パッケージのインストール

5.ソースパッケージのインストール

6.ソースコードツリーの合成

•デモ: coreutilsのソースコードをソースパッケージから復元します。

•演習

33

Fedoraの開発プロジェクトのリポジトリからの入手

1. ソースパッケージリポジトリの設定変更/etc/yum.repos.d/fedora.repo及びfedora-updates.repoの[fedora-source] 及び[updates-source]セクションにあるenableのフィールドを0から1に変更する:

[fedora-source]name=Fedora $releasever - Source...enabled=1...

[updates-source]name=Fedora $releasever - Updates Source...enabled=1...

34

Fedoraの開発プロジェクトのリポジトリからの入手

1. ソースパッケージリポジトリの設定変更(RHELの場合)rhel-source.repoをコピーして新しいrepoファイルを作り編集する。

# /etc/yum.repos.d/rhel-source.repo /etc/yum.repos.d/rhel-src.repo# vi /etc/yum.repos.d/rhel-src.repo

# [rhel-source][rhel-src]name=Red Hat Enterprise Linux $releasever - $basearch - Source...# enabled=0enabled=1...

35

Fedoraの開発プロジェクトのリポジトリからの入手

2. 目的のソフトウェアに対するパッケージ名の特定rpmの-qオプションを使ってsrc.rpmパッケージを特定する。

例:

$ rpm -qif /bin/lsName : coreutils Relocations: (not relocatable)Version : 8.4 Vendor: Red Hat, Inc.Release : 19.el6 Build Date: 2012年04月17日 22時14分13秒Install Date: 2013年04月16日 17時01分08秒 Build Host: hs20-bc2-3.build.redhat.comGroup : System Environment/Base Source RPM: coreutils-8.4-19.el6.src.rpmSize : 12847030 License: GPLv3+Signature : RSA/8, 2012年04月20日 14時59分38秒, Key ID 199e2f91fd431d51Packager : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>URL : http://www.gnu.org/software/coreutils/Summary : A set of basic GNU tools commonly used in shell scriptsDescription :...

Source RPMの行に着目する。

36

Fedoraの開発プロジェクトのリポジトリからの入手

3. ソースパッケージのダウンロードrpm -qi 出力のSource RPMフィールドに記載したファイル名から .rpm部分を除去してyumdownloaderを--sourceをつけて呼び出す。

# yum -y install yum-utils$ yumdownloader --source coreutils-8.4-19.el6.srccoreutils-8.4-19.el6_4.1.src.rpm | 4.4 MB 00:06

環境によってバージョン番号/リリース番号の部分は異なります。

37

Fedoraの開発プロジェクトのリポジトリからの入手

4. 依存パッケージのインストール(オプショナルのステップ)

•ソースコードを合成するのに特別なツールが必要となる場合がある。

•以降のステップで合成に失敗した場合、yum-builddepを用いて合成に 使うツールを含むパッケージを追加インストールする。

# yum-builddep coreutils-8.4-19.el6.src.rpm...

38

Fedoraの開発プロジェクトのリポジトリからの入手

5. ソースパッケージのインストール

• rpmコマンドでsrc.rpmをインストールする。

•rpmデータベースの変更などは行なわず、単に ~/rpmbuild以下にファイルを 配置するだけである。

$ rpm -ivh coreutils-8.4-19.el6.src.rpm...

39

Fedoraの開発プロジェクトのリポジトリからの入手

6. ソースコードツリーの合成

• specファイルを指定してrpmbuildを実行する。

•coreutils-8.4.tar.xz を展開する。

•パッチ群を適用する。

•... などspecファイルに記載された処理を実行する。•結果が ~/rpmbuild/BUILDROOT 以下に配置される。

•別のソフトウェアのソースコードを合成すると上書きされることに注意する。

# yum -y install rpm-build...$ rpmbuild [--nodeps] -bp ~/rpmbuild/SPECS/coreutils.spec...

1. --nodeps をつけて試してみる。

2.失敗するようなら依存するパッケージをインストールした後、 --nodeps を外して実行する。

40

ソースコードツリーの構成

•ダウンロードしたソースコードを含むディレクトリ 以下全体をソースコードツリーと呼ぶ。

•.cやヘッダファイル以外に様々な物が含まれている。ドキュメント

•ライセンス

•そのソフトウェアについての簡単な説明をしたファイル

•ビルド、セルフテストとインストールの手順を説明したファイル

•典型的な使い方を説明したユーザーマニュアル

•(ライブラリであれば)APIの詳細を説明したリファレンスマニュアル

•改変履歴

• ...ビルドスクリプト

ビルド処理用のツールへの入力テストスイート

プログラムが期待通りの動作をするかどうかをセルフテストに使う 補助プログラム群とテストケース

プログラムが利用するデータ

41

•画像ファイル

•フォントファイル

•設定ファイル(のサンプル)

•...翻訳カタログ

プログラムが出力するメッセージやラベルの各国語別の翻訳ソースコードファイル(狭義のソースコード)

•.cファイルや.hファイル

•ビルドスクリプトによってソースコードファイルを自動生成する場合、その入力

42

GNU hello

概要

• FOSSの開発者に(GNU Projectでの)標準的なソースコードツリーの構成を例示 することを目的とする。

•多くの重要ソフトウェアがこの構成にある程度従っているので参考になる。

•古典的な"hello, worldn"を出力するプログラムを拡張した.cファイルが含まれている。

1 #include <stdio.h>2 3 int main(void)4 {5 printf("hello, world\n");6 return 0;7 }

43

44

GNU hello

ソースコードツリー

$ tree hellohello|-- AUTHORS (ドキュメント)|-- COPYING (ドキュメント)|-- ChangeLog (ドキュメント)|-- ChangeLog.O (ドキュメント)|-- GNUmakefile (ビルドスクリプト)|-- Makefile.am (ビルドスクリプト)|-- NEWS (ドキュメント)|-- README (ドキュメント)|-- README-alpha (ドキュメント)|-- README-dev (ドキュメント)|-- README-release (ドキュメント)|-- THANKS (ドキュメント)|-- TODO (ドキュメント)|-- bootstrap (ビルドスクリプト)|-- bootstrap.conf (ビルドスクリプト)

45

|-- build-aux (ビルドスクリプト)| |-- config.rpath| |-- gendocs.sh| |-- useless-if-before-free| `-- vc-list-files|-- cfg.mk (ビルドスクリプト)|-- configure.ac (ビルドスクリプト)|-- contrib| |-- ChangeLog| |-- Makefile.am| |-- de_franconian_po.txt| `-- evolution.txt|-- doc (ドキュメント)| |-- ChangeLog| |-- Makefile.am| |-- gendocs_template| `-- hello.texi|-- gnulib (プロジェクト外部で開発されているライブラリ)|-- man (ドキュメント(自動生成?))| |-- ChangeLog| `-- Makefile.am|-- po (翻訳カタログ群)

46

| |-- ChangeLog| |-- LINGUAS| |-- Makevars.template| |-- POTFILES.in| |-- Rules-quot| |-- bg.po| |-- boldquot.sed| |-- ca.po| |-- da.po| |-- de.po| |-- el.po| |-- en@boldquot.header| |-- en@boldquot.po| |-- en@quot.header| |-- en@quot.po| |-- eo.po| |-- es.po| |-- et.po| |-- eu.po| |-- fa.po| |-- fi.po| |-- fr.po

47

| |-- ga.po| |-- gl.po| |-- he.po| |-- hr.po| |-- hu.po| |-- id.po| |-- insert-header.sin| |-- it.po| |-- ja.po| |-- ka.po| |-- ko.po| |-- lv.po| |-- ms.po| |-- nb.po| |-- nl.po| |-- nn.po| |-- pl.po| |-- pt.po| |-- pt_BR.po| |-- quot.sed| |-- remove-potcdate.sin| |-- rm.po

48

| |-- ro.po| |-- ru.po| |-- sk.po| |-- sl.po| |-- sr.po| |-- sv.po| |-- th.po| |-- tr.po| |-- uk.po| |-- vi.po| |-- zh_CN.po| `-- zh_TW.po|-- src| |-- ChangeLog (ドキュメント)| |-- Makefile.am (ビルドスクリプト)| |-- hello.c (ソースコードファイル)| `-- system.h (ソースコードファイル)`-- tests (テストスイート) |-- ChangeLog |-- Makefile.am |-- greeting-1 |-- greeting-2

49

|-- hello-1 |-- last-1 `-- traditional-1

8 directories, 98 files

50