LinuxでのC開発 - プログラムの構築 - X.
紹介
理論や話し合いが終わったので、このシリーズの最後の9部で書かれたコードを構築するところから始めましょう。このシリーズの部分は、他の場所でCを学んだ場合でも役に立つかもしれませんし、C開発の実践的な側面にもう少し力が必要だと思っている場合でも役立つかもしれません。必要なソフトウェアをインストールする方法、ソフトウェアが何をするか、そして最も重要なことは、コードをゼロと一に変換する方法を見ていきます。始める前に、開発環境をカスタマイズする方法についての最近の記事を一度見てみることをお勧めします。
- VIMエディタの紹介
- Emacsの紹介
- 開発のためのVIMのカスタマイズ
- 開発のためのEmacsのカスタマイズ
プログラムを構築する
私たちのC開発シリーズの最初の部分を覚えていますか?そこで、プログラムをコンパイルするときに行われる基本的なプロセスを説明しました。しかし、コンパイラ開発や非常に低レベルの作業をしていない限り、生成されたアセンブラファイルにJMP命令がいくつあるのか、あってもなくても興味はないでしょう。あなたが知りたいのは、いかに効率的に作業するかだけです。この記事のこの部分はそれについてですが、テーマが広範であるため、表面をなでるだけです。しかし、入門レベルのCプログラマは、これを読んだ後、効率的に作業するために必要なすべてを理解するでしょう。
道具
達成したい目標を正確に知ることに加え、望んでいることを達成するためのツールにも熟知している必要があります。そして、Linuxの開発ツールにはgccだけでなく、他にもたくさんのものがあります。gccだけでもプログラムをコンパイルするには十分ですが、プロジェクトの規模が大きくなるにつれて、それは tediousな作業になります。これが他のツールが作成された理由であり、ここではそれらが何であり、どのように手に入れることができるかを見ていきます。私はすでにgccのマニュアルを読むことを強くお勧めしましたので、あなたが読んだと仮定します。
作る
複数のファイルからなるプロジェクトを想像してください。ソースファイルがたくさんあって、その作品があります。次に、1つのファイルを(些細なことですが)修正し、別のソースファイルにコードを追加しなければならないと想像してください。それだけの理由でプロジェクト全体を再ビルドするのは痛手でしょう。ここで、make が作られた理由があります。ファイルのタイムスタンプに基づいて、目的の結果(実行可能ファイルやオブジェクトファイルなど)を得るために再ビルドが必要なファイルを検出します。これらを ターゲット と呼びます。この概念がまだ不明瞭に感じるかもしれませんが、心配しないでください。makefile と一般的な概念について説明した後は、すべてがより簡単に感じるでしょう。ただし、上級の make 概念は頭痛の原因になり得ます。
私が作業したすべてのプラットフォームで同じ名前の make が使用されています。それはかなり多くの Linux ディストロ、*BSD、および Solaris です。したがって、どのパッケージマネージャを使用していようが(使用していない場合でも)、apt、yum、zypper、pacman、または emerge のいずれであっても、適切なインストールコマンドを使用し、引数として make を指定すればそれで済みます。もう一つのアプローチは、グループサポートを持つパッケージマネージャを持つディストロの場合、C/C++ 開発グループ/パターン全体をインストールすることです。言語に関して言えば、ここで神話を打破したいと思います。makefile(make がターゲットに到達するために従う必要のあるルールのセット)は、C/C++ 開発者のみが使用するものだと言われていますが、これは間違いです。シェルから呼び出すことができるコンパイラ/インタプリタを持つ任意の言語は make の機能を使用できます。実際、依存関係に基づいた更新が必要なプロジェクトは、すべて make を使用できます。 したがって、makefileの更新された定義はプロジェクトのファイル間の関係および依存関係を説明するファイルであり、依存関係チェーン内の1つまたはそれ以上のファイルが変更された場合に、何を更新/再コンパイルすべきかを定義する目的を持つ。 makeの仕組みを理解することは、LinuxやUnixの下で作業するC開発者にとって不可欠です - そうですね、商用Unixにもmakeはありますが、おそらくGNU makeとは異なるバージョンです。 「異なるバージョン」とは、数字以上の意味があり、BSDのmakefileはGNUのmakefileと互換性がないことを意味します。 したがって、Linuxボックスでない場合は、GNU makeがインストールされていることを確認してください。
この記事の最初の部分とその後のいくつかの部分では、昨日の日付をデフォルトで表示する小さなプログラムであるyestの一部について使ったり話したりしましたが、日付/時間に関連するさまざまな便利な機能も備えています。著者のキンボール・ホーキンズと協力することで、小さなMakefileが誕生しました。これが私たちが取り組むものです。
まず、Makefileに関する基本的なことを見てみましょう。標準的な名前はGNUmakefileであるべきですが、そのようなファイルが存在しない場合は、マニュアルページによるとmakefileやMakefileのような名前をその順番で探します。ところで、もちろん、それを読んで、もう一度読んで、さらにもう一度読むべきです。それはgccのように大きくはなく、後で役立つ多くの便利な技術を学ぶことができます。ただし、実際に最も多く使われる名前はMakefileであり、正直なところGNUmakefileという名前のファイルが含まれているソースコードを見たことがありません。さまざまな理由で別の名前を指定する必要がある場合は、次のようにmakeの-fオプションを使用してください:
$ make -f mymakefileここに昨日のMakefileがあります。このMakefileを使用して、まだSourceforgeにアップロードされていないプログラムをコンパイルしてインストールできます。ソースファイルとマニュアルページの2ファイルしかないプログラムですが、makeがすでに便利であることがわかるでしょう。
Makefile for compiling and installing yest
UNAME := $(shell uname -s)
CC = gcc
CFLAGS = -Wall
CP = cp
RM = rm
RMFLAGS = -f
GZIP = gzip
VERSION = yest-2.7.0.5
yest:
ifeq ($(UNAME), SunOS)
$(CC) -DSUNOS $(CFLAGS) -o yest $(VERSION).c
else
$(CC) $(CFLAGS) -o yest $(VERSION).c
endif
all: yest install maninstall
install: maninstall
$(CP) yest /usr/local/bin
maninstall:
$(CP) $(VERSION).man1 yest.1
$(GZIP) yest.1
$(CP) yest.1.gz /usr/share/man/man1/
clean:
$(RM) $(RMFLAGS) yest yest.1.gz
deinstall:
$(RM) $(RMFLAGS) /usr/local/bin/yest /usr/share/man/man1/yest1.gz
上記のコードを注意深く見れば、すでにいくつかのことを観察し学ぶことができるでしょう。コメントはハッシュで始まり、Makefileはかなり難解になる可能性があるので、Makefileにコメントを追加することをお勧めします。次に、自分自身の変数を宣言することができ、それらをうまく活用することができます。そして次は重要な部分です:ターゲットです。コロンの後に続く言葉はターゲットと呼ばれ、make [-f makefile名] ターゲット名のように使用します。もしソースからインストールしたことがあれば、おそらく「make install」と入力したでしょう。実際、「install」はMakefileのターゲットの一つで、他の一般的に使用されるターゲットには「clean」、「deinstall」、または「all」が含まれます。 もう一つ非常に重要なことは、最初のターゲットが指定されていない場合、常にデフォルトで実行されるということです。私たちのケースでは、「make」と入力すれば、「make yest」と同等であることがわかります。これは条件付きコンパイルを意味します(Solaris/SunOS上にいる場合、追加のgccフラグが必要です)と、「yest」という名前の実行可能ファイルの作成を意味します。私たちの例の「all」のようなターゲットは、他のファイル/ターゲットが最新であることを依存しているだけで、自身は何も行いません。構文に注意してください。特にスペースやタブに関して、makeはこうしたことに非常にうるさいです。
これは、2つのソースファイルを持つプロジェクトのための短いMakefileです。ファイル名はsrc1.cとsrc2.cで、実行可能ファイルの名前はexecでなければなりません。簡単ですね?
exec: src1.o src2.o
gcc -o exec src1.o src2.o
src1.o: src1.c
gcc -c src1.c
src2.o: src2.c
gcc -c src2.c実際に使用される唯一のターゲットはデフォルトでもある 'exec' です。これは、src1.o と src2.o に依存しており、その src1.o と src2.o はそれぞれの .c ファイルに依存しています。ですので、たとえば src2.c を変更した場合、再度 make を実行するだけで大丈夫です。make は src2.c が他のファイルよりも新しいことに気付き、それに応じて処理を進めます。ここで説明したこと以上に make については多くのことがありますが、これ以上のスペースはありません。いつものように、自己学習は推奨されますが、基本的な機能だけが必要な場合は、上記の内容で十分役立ちます。
設定スクリプト
通常、単に「make && make install」ではありません。なぜなら、これらの二つの前に、特に大きなプロジェクトで役立つmakefileを生成するステップが存在するからです。基本的に、そのスクリプトはコンパイルに必要なコンポーネントがインストールされているかチェックしますが、インストールされたファイルの設置先を変更するのに役立つさまざまな引数や、さまざまなオプション(例えば、Qt4やGTK3のサポート、PDFやCBRファイルのサポートなど)も受け取ります。それでは、これらのconfigureスクリプトが何についてかをざっと見てみましょう。
通常、configure スクリプトを手動で書くことはありません。これには autoconf と automake を使用します。その名称が示すように、これらはそれぞれ configure スクリプトと Makefile を生成します。たとえば、以前の yest プログラムの例では、実際には OS 環境を検出しいくつかの make 変数を変更し、最終的に Makefile を生成する configure スクリプトを使用できます。yest の Makefile は SunOS で実行しているかどうかをチェックし、もしそうならコンパイラフラグを追加することがわかっています。それを拡張して、BSD システム上で作業しているかどうかを確認し、もしそうであれば、ネイティブの make の代わりに gmake (GNU make) を呼び出すようにするつもりです。これは、我々が言ったように、GNU Makefile とは互換性がありません。 これら二つのことは自動構成を使って行われます:私たちは小さなconfigure.inファイルを書き、自動構成に何をチェックする必要があるかを伝えます。通常、OSプラットフォーム以上のものをチェックすることを望むでしょう。ユーザーがコンパイラをインストールしていない場合や、makeがない、コンパイル時に重要な開発ライブラリがないなどの可能性があります。たとえば、システムの標準ヘッダーの場所にtime.hの存在をチェックする行は次のようになります:
AC_CHECK_HEADERS(time.h)あまり大きくないアプリケーションから始めることをお勧めします。ソースタールボールの内容を確認し、configure.inおよび/またはconfigure.acファイルを読むと良いでしょう。それらがあるタールボールでは、Makefile.amもautomakeファイルがどのように見えるかを知るための良い方法です。この件については良い本がいくつかあり、そのうちの一つがロバート・メックルバーグの「GNU Makeによるプロジェクト管理」です。
gccのヒントと一般的なコマンドラインフラグ
私はgccのマニュアルが大きいことを知っていますし、多くの皆さんがそれすら読んでいないことも知っています。私はそれを全部読むことに誇りを持っています(とにかくIAハードウェアに関係する部分ですが)が、その後頭痛がしました。それでも、進むにつれてもっと学ぶとはいえ、知っておくべきオプションもいくつかあります。
あなたはすでに-oフラグに出会っていますが、それはgccに出力ファイルの名前を伝え、-cはgccにリンカーを実行しないように指示し、アセンブラが生成するオブジェクトファイルを作成します。それに関連して、gccがどの段階で実行を停止すべきかを制御するオプションがあります。したがって、コンパイル自体の後にアセンブリ段階の前で停止するには、-Sを使用します。同様に、プリプロセスが終了した直後にgccを停止させたい場合は、-Eを使用します。
標準に従うことは良い習慣であり、均一性のためだけでなく、良いプログラミング習慣のためにも良い練習です。もしあなたがC開発者としての形成期にいるなら、標準を選んで(下記を参照)それに従ってください。C言語は1978年にカーニハンとリッチー(安らかに眠れ)が「Cプログラミング言語」を出版した後、最初に標準化されました。それは正式な標準ではありませんでしたが、すぐにK&Rと呼ばれ、尊重されました。しかし、今ではそれは古くなり、推奨されません。その後、80年代と90年代に、ANSIとISOが公式の標準であるC89を策定し、続いてC99とC11が策定されました。gccはgnuxxのような他の標準もサポートしており、ここでxxは89または99などの例が挙げられます。詳細についてはマニュアルを確認し、オプションは「-std=」であり、「-pedantic」によって「強制」されます。
警告に関連するオプションは「-W」で始まり、例えば「-Wall」(gccにすべてのエラーを有効にするように指示しますが、実際にはすべてのエラーが有効になるわけではありません)や「-Werror」(警告をエラーとして扱う、常に推奨されます)があります。前処理器、アセンブラ、リンク器などの中間ステップを助けるためにプログラムに補足引数を渡すことができます。たとえば、リンク器にオプションを渡す方法は以下の通りです:
$ gcc [other options...] -Wl,option [yet another set of options...]同様に直感的に、アセンブラには「Wa」を、プリプロセッサには「Wp」を使用できます。コンパイラにプリプロセッサ/アセンブラ/リンカーの部分が終了したことを知らせるカンマと空白に注意してください。他にも役立つオプションのファミリーには、デバッグ用の「-g」とその仲間、最適化用の「-O」とその仲間、またはヘッダーを含む場所を追加するための「-Idirectory」(空白なし)が含まれます。
結論
この記事をじっくり読んで、例を試し、自分自身のものを書いて、進むにつれて複雑さを増していくことをお勧めします。
今後の予想は以下の通りです:
- Linux上のC言語開発 - はじめに
- II. C言語と他のプログラミング言語との比較
- III. タイプ、演算子、変数
- IV. フロー制御
- V. 機能
- VI. ポインタと配列
- VII. 構造
- VIII. 基本的な入出力
- IX. コーディングスタイルと推奨事項
- X. プログラムを構築する
- XI. DebianおよびFedoraのパッケージング
- XII. 公式Debianリポジトリからパッケージを取得する