[新人エンジニアが作る自作OS]ソースコードの分割とmakeによる自動コンパイル

◆ Live配信スケジュール ◆
サイオステクノロジーでは、Microsoft MVPの武井による「わかりみの深いシリーズ」など、定期的なLive配信を行っています。
⇒ 詳細スケジュールはこちらから
⇒ 見逃してしまった方はYoutubeチャンネルをご覧ください
【4/18開催】VSCode Dev Containersで楽々開発環境構築祭り〜Python/Reactなどなど〜
Visual Studio Codeの拡張機能であるDev Containersを使ってReactとかPythonとかSpring Bootとかの開発環境をラクチンで構築する方法を紹介するイベントです。
https://tech-lab.connpass.com/event/311864/

本投稿、[新卒が作る自作OS]は、我々が自作OSを作るにあたり、詰まったところや、備忘録的に残しておきたいところなどをまとめておこうという趣旨の投稿です。

今回はソースコードを分割する方法とmakeによる自動コンパイルについて取り上げます。使用する言語はC言語です。

本記事のソースコードの開発環境は以下の通りです。

OSWindows 10 Pro 64bit
コンパイラgcc 9.2.0
makeGNU Make version 3.79.1

ソースコードの分割

大規模なプログラムを書いていると、どうしても行数が増えてしまい複雑になります。そんなときは、ソースコードを機能ごとに複数に分割することで可読性を高めます。

ソースコードの分け方

C言語の文法上はどのように分けても問題はないのですが、一般的には以下のようなルールで分割すると可読性が高まります。プログラム本体のCファイルは基本的にはmain関数のみを記述します。それ以外の関数は類似機能ごとにヘッダファイルと関数定義用のCファイルに分割します。ヘッダファイルには関数の定義は書かず、プロトタイプ宣言を記述します。他に共通するinclude文、define定数、グローバル変数や型の定義を記述します。このように分けることでヘッダファイルが定義されている関数や変数の一覧表のような役割を果たし、より読みやすいソースコードになります。

ファイル記述内容
Cファイル(本体)
  • main関数
ヘッダファイル
  • インクルード
  • 定数定義
  • グローバル変数定義
  • 型定義
  • 関数のプロトタイプ宣言
Cファイル(関数定義)
  • 関数の定義

分割前のソースコード

ソースコードの分割のサンプルコードを作成しました。こちらが分割前のソースコードsample.cです。3つの関数print_hello、print_num、print_structではそれぞれグローバル変数、define定数、構造体を呼び出して画面表示しています。これらをmain関数から呼び出しています。

#include <stdio.h>

#define NUM     10

struct MYSTRUCT
{
    int i1, i2, i3;
};

char *str;

void print_hello(void)
{
    str = "Hello!\n";
    printf("%s", str);
}

void print_num(void)
{
    printf("%d\n", NUM);
}

void print_struct(void)
{
    struct MYSTRUCT ms;
    ms.i1 = 1;
    ms.i2 = 2;
    ms.i3 = 3;
    printf("%d,%d,%d\n", ms.i1, ms.i2, ms.i3);
}

int main(void)
{
    print_hello();
    print_num();
    print_struct();
    return 0;
}

コンパイルをするにはコマンドラインに以下のように記述します。

# gcc sample.c

分割後のソースコード

sample.cを先程の表の分け方に従い分割します。上から順にmain.c、print.h、print.cです。

#include "print.h"

int main(void)
{
    print_hello();
    print_num();
    print_struct();
    return 0;
}
#pragma once

//インクルード
#include <stdio.h>

//定数定義
#define NUM     10

//型定義
struct MYSTRUCT
{
    int i1, i2, i3;
};

//グローバル変数定義
char *str;

//関数のプロトタイプ宣言
void print_hello(void);
void print_num(void);
void print_struct(void);
#include "print.h"

void print_hello(void)
{
    str = "Hello!\n";
    printf("%s", str);
}

void print_num(void)
{
    printf("%d\n", NUM);
}

void print_struct(void)
{
    struct MYSTRUCT ms;
    ms.i1 = 1;
    ms.i2 = 2;
    ms.i3 = 3;
    printf("%d,%d,%d\n", ms.i1, ms.i2, ms.i3);
}

コンパイルをするにはコマンドラインに以下のように記述します。

# gcc -o a.exe main.c print.c print.h

main.cはmain関数のみ、print.cは各関数の定義のみになりかなりスッキリしました。print.hを見ることでprint.cで定義した関数や使用している変数などがすべてわかります。この程度の分量のソースコードでも内容がわかりやすくなったと思います。大規模な開発になるほど可読性の差は顕著になります。

makeでコンパイルを自動化

makeとは

簡単にいうと高性能なバッチファイルです。ファイルの依存関係を調べ必要な部分のみ実行することができます。一部のソースファイルを修正したとき、通常のコンパイルであればすべてのソースコードをコンパイルし直さなければなりませんが、makeを使えば変更に関連するファイルのみをコンパイルすることができ、コンパイルの高速化を実現できます。

いくつか種類がありますが、ここではGNUmakeを使用しています。

GNU公式サイト:https://gnuwin32.sourceforge.net/packages/make.htm

makeの書き方

Makefileというファイル名で以下の内容を記述します。他にも様々な機能がありますがここでは省略します。

【ターゲット】:【依存ファイル】
	【コマンド】

実行時に依存ファイルに変更があった場合、コマンドが実行されます。今回のソースコードをコンパイルする場合は以下のように記述します。main.c、print.c、print.hのいずれかが更新されると、それぞれ対応するmain.o、print.oが新たに生成されます。-cオプションはコンパイルのみ行いオブジェクトファイルを生成します。main.o、print.oのいずれかが更新されると実行ファイルであるa.exeのコンパイルが行われます。

a.exe: main.o print.o
	gcc -o a.exe main.o print.o

main.o:main.c
	gcc -c main.c

print.o:print.c print.h
	gcc -c print.c	

.PHONY: clean
clean:
	del main.o print.o print.h.gch

コマンドラインに以下のように記述することで実行できます。

# make

このようにmakeを導入することで、ファイルを更新する度にすべてのファイルをコンパイルする必要がなくなり、コンパイルが高速化されます。コマンドを何度も書く必要もなくなるので手間も減らせます。

10~12行目は生成された中間ファイルを削除するためのコマンドです。以下のように記述することでコンパイルの過程で生成されたmain.o、print.o、print.h.gchを削除できます。

# make clean

まとめ

今回はソースコードを分割する方法とmakeによる自動コンパイルについてまとめました。OS開発に直接的に関わる部分ではありませんが、開発を効率的に行うために非常に重要な内容です。

最後までお読みいただきありがとうございます。

アバター画像
プロフェッショナルサービスチームの中の人。
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。


ご覧いただきありがとうございます。
ブログの最新情報はSNSでも発信しております。
ぜひTwitterのフォロー&Facebookページにいいねをお願い致します!



>> 雑誌等の執筆依頼を受付しております。
   ご希望の方はお気軽にお問い合わせください!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


質問はこちら 閉じる