開発環境 C言語(その2)

【連載】

にわか管理者のためのLinux運用入門

【第157回】開発環境 C言語(その2)

[2018/12/18 09:45]後藤大地 ブックマーク ブックマーク

サーバ/ストレージ

基本的なMakefileを作っておく

C言語でコマンドやユーティリティを開発する場合、単一のCソースコードだけを使うというのはまれなケースだ。開発の初期段階はそれでもよいと思うが、しばらくしてソースコードが膨れ上がると複数のファイルに分割するようになる。C言語に慣れている開発者であれば、最初から複数のファイルに分割した状態でコーディングを始めるだろう。そこで役立つのが「Makefile」である。

Makefileは、コンパイル方法やコンパイルの依存関係などを書いておくものだ。ビルド、クリーンナップ、などの処理をあらかじめMakefileに書いておくことで、「開発段階では『make』または『make clean』としか入力しない」という状況が整う。いちいちccコマンドを実行するのは面倒なので、Makefileに処理をまとめておくのである。

C言語のソースコードをビルドするためのMakefileは比較的使い回しが効くので、1つ作っておけば後はコピー&ペーストと簡単な編集で再利用できると思う。作っておいて損はないだろう。

Makefileのサンプル

まずは今回のファイル配置を把握しておこう。用意したファイルは、次の5つだ。

$ tree .
.
├── Makefile
├── message.c
├── usage.c
├── welcome.c
└── welcome.h

0 directories, 5 files
$

前回作成した「welcome.c」というファイルは、「welcome.c」「message.c」「usage.c」という3つのファイルに分けてある。message.cにはメッセージを返す「message()」という関数を、usage.cには使い方を出力する「usage()」という関数を実装した。welcome.cにはオプションを処理するコードを加えると共に、usage()とmessage()を呼び出す処理を追加してある。次のような感じだ。

welcome.c - オプション処理を追加するとともに、usage()およびmessage()を利用するように変更

#include "welcome.h"

int
main(int argc, char *argv[])
{
    int opt;

    while (-1 != (opt = getopt(argc, argv, "uh"))) {
        switch (opt) {
        case 'u':
        case 'h':
            usage();
            exit(EXIT_FAILURE);
            break;
        default:
            usage();
            exit(EXIT_FAILURE);
            break;
        }
    }

    printf("%s", message());

    exit(EXIT_SUCCESS);
}

message.c - メッセージを返すmessage()を実装

#include "welcome.h"

char *
message()
{
    char *b;
    b = calloc(1, sizeof(char) * 1024 * 4);
    strcpy(b,
        "            .-/+oossssoo+/-." "\n"
        "        `:+ssssssssssssssssss+:`" "\n"
        "      -+ssssssssssssssssssyyssss+-" "\n"
        "    .ossssssssssssssssssdMMMNysssso." "\n"
        "   /ssssssssssshdmmNNmmyNMMMMhssssss/" "\n"
        "  +ssssssssshmydMMMMMMMNddddyssssssss+" "\n"
        " /sssssssshNMMMyhhyyyyhmNMMMNhssssssss/" "\n"
        ".ssssssssdMMMNhsssssssssshNMMMdssssssss." "\n"
        "+sssshhhyNMMNyssssssssssssyNMMMysssssss+" "\n"
        "ossyNMMMNyMMhsssssssssssssshmmmhssssssso" "\n"
        "ossyNMMMNyMMhsssssssssssssshmmmhssssssso" "\n"
        "+sssshhhyNMMNyssssssssssssyNMMMysssssss+" "\n"
        ".ssssssssdMMMNhsssssssssshNMMMdssssssss." "\n"
        " /sssssssshNMMMyhhyyyyhdNMMMNhssssssss/" "\n"
        "  +sssssssssdmydMMMMMMMMddddyssssssss+" "\n"
        "   /ssssssssssshdmNNNNmyNMMMMhssssss/" "\n"
        "    .ossssssssssssssssssdMMMNysssso." "\n"
        "      -+sssssssssssssssssyyyssss+-" "\n"
        "        `:+ssssssssssssssssss+:`" "\n"
        "            .-/+oossssoo+/-." "\n");

    return b;
}

usage.c - 使い方を出力するusage()を実装

#include "welcome.h"

int
usage()
{
    fprintf(stderr, "usage: welcome [-uh]\n");

    return 0;
}

welcome.cからmessage()とusage()が利用できるように、「welcome.h」というヘッダファイルを作成しておく。どのファイルからもこのヘッダファイルを取り込むように(include)してある。

welcome.h - 今回のコマンドのヘッダファイル

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int usage();
char *message();

makeで関連するファイルをすべてビルドして、最後にオブジェクトファイルを結合して「welcome」というバイナリファイル(実行ファイル)を生成するMakefileを次のように書いておく。

SRCS=   welcome.c message.c usage.c
CMD=    welcome

OBJS=   ${SRCS:.c=.o}

all: ${OBJS}
    cc -o ${CMD} ${OBJS}

.SUFFIXES: .c .c

.c.o:
    cc -c $<

clean:
    rm -f ${OBJS} ${CMD}

ここでは、「make clean」でオブジェクトファイルとバイナリファイルが削除され、ソースコードだけが残るようにしてある。

今回取り上げたようなフラットな構造のC言語ソースコードの組み合わせであれば、上記Makefileの「SRCS=」の行に指定するソースコードファイルの一覧と「CMD=」に指定するコマンド名を変えるだけで、ほかのコマンドやユーティリティのビルドにも利用できる。本連載はソースコードの解説は範疇ではないのでMakefileの記述内容について詳しくは説明しないが、興味があれば調べてみていただきたい。それほど複雑な書き方はしていないので、すぐにわかると思う。

ビルドの例と実行の例

では早速、ビルドしてみよう。環境が整っていれば、次のようにmakeコマンドを実行することでccコマンドによるコンパイルが実行される。

$ make
cc -c welcome.c
cc -c message.c
cc -c usage.c
cc -o welcome welcome.o message.o usage.o
$ tree
.
├── Makefile
├── message.c
├── message.o
├── usage.c
├── usage.o
├── welcome
├── welcome.c
├── welcome.h
└── welcome.o

0 directories, 9 files
$

実行する前に一度「make clean」を試してみてほしい。今、生成したオブジェクトファイルとバイナリファイルが削除されるはずだ。

$ make clean
rm -f welcome.o message.o usage.o welcome
$ tree
.
├── Makefile
├── message.c
├── usage.c
├── welcome.c
└── welcome.h

0 directories, 5 files
$

makeでビルド、make cleanでクリーンナップだ。ここまで準備しておくと開発の作業がとても楽になる。

ビルドしてwelcomeコマンドを実行すると、次のようになる。

welcomeコマンドのビルドと実行例

オプションを利用すると、次のようにusage()がメッセージを出力することなどを確認することができる。

welcomeコマンドのオプション利用例

仕組みさえ作っておけば、後は細かくコーディングとビルドを繰り返すことである程度のコマンドは作れるようになる。C言語でプログラミングをしたことがないのであれば、サンプルをコピー&ペーストするなどしてぜひ一度お試しいただきたい。

※ 本記事は掲載時点の情報であり、最新のものとは異なる場合がございます。予めご了承ください。

一覧はこちら

連載目次

もっと知りたい!こちらもオススメ

なぜ今、統合システムなのか? 押さえておくべき「3つのインパクト」

なぜ今、統合システムなのか? 押さえておくべき「3つのインパクト」

ガートナー ジャパンは10月31日~11月2日、都内で「Gartner Symposium/ITxpo 2017」を開催。11月1日には同社 主席アナリストの青山浩子氏が登壇し「CIOが理解すべき統合システムの3大インパクト」と題する講演を行った。本稿では、講演の内容をダイジェストでお届けする。

関連リンク

この記事に興味を持ったら"いいね!"を Click
Facebook で IT Search+ の人気記事をお届けします

会員登録(無料)

注目の特集/連載
知りたい! カナコさん 皆で話そうAIのコト
教えてカナコさん! これならわかるAI入門
対話システムをつくろう! Python超入門
Kubernetes入門
RPA入門
AWSで作るクラウドネイティブアプリケーションの基本
ソフトウェア開発自動化入門
PowerShell Core入門
Swagger 3.0 入門
徹底研究! ハイブリッドクラウド
マイナビニュース スペシャルセミナー 講演レポート/当日講演資料 まとめ
セキュリティアワード特設ページ

一覧はこちら

今注目のIT用語の意味を事典でチェック!

一覧はこちら

ページの先頭に戻る