0
0

MakeFile 入門 (学習記録)

Posted at

MakeFile とは

コンパイル、依存関係の管理、インストールなどのルールを記述しておくためのファイルです。
(引用: https://linuc.org/study/knowledge/542/)

Makeileでできること

まずMakeFileの基本機能として通常のターミナルと同じコマンドが使える(一部のコマンドの記述方法は異なる)

①コンパイル

gcc cファイル名 -o 実行ファイル名

②自ディレクトリから子ディレクトリのMakeFileを呼び出す

default :
        make -C 子ディレクトリ名

などの基本機能があります。

一方でターミナル同様に実行できないコマンドとしてechoやmkdirがあります(環境によって異なります)

    @echo "サンプルテキスト"

基本的には「 TAB @コマンド名 」 の形になる

MakeFileには

2つの段階があり、ターゲットの実行前の[準備段階]と実行後の[実行段階]に分かれています。

この[準備段階]に関してですが、主に変数やコマンドライン引数などを管理・関数の定義を上の方にまとめておきます。

[実行段階]に関しては、出力やコンパイルなどの処理でターゲットの
中 or 実行後 に配置する必要があります。

そして一度、[実行段階]に入ると変数の定義or代入が困難になります。不便ですねぇ…

まぁ、ファイル操作で情報やり取りは可能(">"でリダイレクトして"cat"で読み取り)
あとbashで代用可能コマンドもあるらしい

変数

型の宣言等は不要ですが参照時には $ を使用します。

    宣言 : Hoge = xxx または Hoge = "xxx"
    参照 : $(Hoge) or  ${Hoge}

※変数名が一文字の場合は 参照時に()or{}は不要

定数

    変数名 := 要素  で宣言可能

(命名指針としては大文字・区切りはアンダーバー )

ただしプログラム言語とは違い、定数の要素へ上書き可能
(再定義の事ね)

※プログラム言語にあるような「define」での宣言は
MakeFileではマクロ(関数のようなモノ)を指している

・デフォルトの変数(自動変数)

$@ : 自ターゲット名を参照

$% : 構成中ライブラリを参照

$< : 自ターゲットの前提条件を 1つ目のみ 参照

$^ : 自ターゲットの前提条件を 全て
参照(スペースあり)

$? :
自ターゲットのタイムスタンプ(更新日時)が新しい前提条件を参照

$* :
自ターゲット名におけるワイルドカード(%)の文字列を参照

などが存在する

参考資料 : https://tex2e.github.io/blog/makefile/automatic-variables

変数の扱い方

変数は参照時の要素を取得するので、プログラム言語と同じ動作はしない(
アドレスのような感じ )

例 ) ※PHONY は割愛します

x = 初期値x
y = $(x) 初期値y                 # x の要素 と "初期値y"の文字列を格納
x = 転生x                        # 再定義

test:
              @echo $(y)        # "転生x 初期値y" になる
              @echo %@          # "test"(自ターゲット名を参照)

もし"初期値x 初期値y"の出力をするのであれば『y := $(x) 初期値y』
yを定数として宣言する必要がある 

※※※ コマンドライン引数に関して ※※※

make実行時に「$ make 使用するターゲット名 x=hoge」とすることが可能になる。

これを行うことによって固定値の変数となり、MakeFile内での宣言よりも優先度の高い要素を代入する事が可能になる。

※※※ 演算子に関して ※※※

「 a ?= b 」というように ?= の宣言が存在する

これはvoid型の変数を指しており、"?="以外の代入(a =xxxなど)が行わる場合まで要素は b から不動となる

使用用途に関しては「デフォルトの数値は○○ですが、必要ならコマンドライン引数で変更してください」の命名指針にもなる。

マクロ

・基本構文

define マクロ名

    処理

endef


ターゲット:

    $(マクロ名)               # マクロの呼び出し

の流れになる。

関数とは違い、ファイルの操作等も可能のため今後に記述されるターゲットやシェルスクリプトと同等のモノと考えてよい。

ターゲット         :
実行時のコマンドにて使用される可能性がある
(誤爆の可能性)

シェルスクリプト:
ファイルへのパスを指定して実行する
(ファイルの分離化が可能)

マクロ                 :
関数のようなモノだが、MakeFile本体が冗長になりやすい。

ただし、三種とも変数の操作は行えないと思うので、分岐や動的処理が苦手かもしれない(するならターゲット前でフラグ管理を!)

参考資料 (少ないのでつらい)

https://qiita.com/Ro3jin/items/27170827707e5136ee89

https://qiita.com/mkataigi/items/b3028d73f9865d45ba1e

ターゲット

・基本構文

ターゲット名 : 前提条件
    処理

の流れになる。

ターゲットを使用するには主に"疑似ターゲット"を作成する必要がある

※理論上は作成しなくとも動作可能だが、コマンドなのかファイル名の指定なのかを判別させるために必要

主に【.PHONY】宣言を使用する。使い方) .PHONY
疑似ターゲット名

例)下記、ターゲットは「make aaa」コマンドで実行可

.PHONY: aaa

aaa:
    @echo "Hello World"

※宣言なしの場合でも他のターゲットからの呼び出し自体は可能(ただし同ファイル名があると誤作動)

※あと、宣言がないと『make: 'ターゲット名' is up to
date.』とかいう謎の「最新です」エラーが出る場合があるので注意

・ターゲットの実行方法は二つ存在しており、

①ターミナルでの引数として指定する
(2つ以上でも可能 例: make aaa bbb で2種のタスクの実行が可能 )

②MakeFileにて aaa: bbb という形で前提条件を宣言する
(bbbターゲットが存在しない場合はエラー )

パターンルール

同じようなターゲット処理が複数必要な場合はパターンルールのターゲットを作成する事で解消できます。

・基本構文
※ "%"はワイルドカードを指している
※ "%.o"の拡張子は例です

%.o : 前提条件

        処理

PHONYは不要で、前提条件の箇所にもワイルドカード(%)を使用する事が可能です。※PHONYしようにもできないやろ

こちらも通常のターゲットと同様の方法で呼び出し(実行)が出来ます。

ただし【エラー「何もする必要はありません」で実行できない場合】

処理で使用するファイル等をtouchコマンドやコンパイル等で更新する事で解消します。

一番簡単なパターンルールの展開だけします。コマンド:
make hoge.echo にて実行

%.echo:
    echo $@

以上

関数

単純にターミナルでのコマンドが関数化している事も多いので注意

例) ファイル・ディレクトリの検索

MakeFile: $(wildcard test*)

ターミナル: find test*

文字列やファイル操作など様々な関数がある。※正確には"組み込み関数"と呼ぶらしい

一つ注意点があり、【区切りに余分な半角スペースやTABを挿入しない事】

参考: https://tex2e.github.io/blog/makefile/functions

make -f- <<< 'x:;@echo =$(sort d b s d t)='

出力結果: =b d s t=

if文

・変数が定義されているかの判別 ( ifdef ) ※ターゲット配下の場合でも左寄せ

ifdef 変数名1
    処理

else ifdef 変数名2
    処理

else
    else処理

endif

・変数が定義されていない場合の判別 ( ifndef ) ※not ifdef

ifndef 変数名
    処理

else
    else処理

endif

・値の比較 ( ifeq ) ※変数の場合は$(変数名),文字列はそのままで "" は不要

ifeq ($(変数名),比較する文字列)
    true処理

else
    false処理

endif

include

まず、自分以外のMakeFileをインポートする事を想定します。

MakeFileと同じ階層に"inc.mk"を作成して、てきとーな疑似ターゲット"inc"を作成

MakeFileでは[ include inc.mk ]を記述すると"inc"ターゲットが使用可能になる

自前のヘッダファイルをincludeしたい

まず、cファイルでのincludeでは二種類あります。

#include <stdio.h>         // デフォルト要素を指定

#include "Hoge.h"           // 相対パスにて指定

そしてこのデフォルト要素のincludeファイルを自前で追加してやろうというお話です。

MakeFileにて

# 目的のパス $(CURDIR) == pwdコマンドと同じ(現在までのディレクトリパス)

FPATH := \

    $(CURDIR)/includeしたいディレクトリまでのパス

疑似ターゲット : main.c

    gcc -I  $(FPATH) main.c -o main.exe

これで main.exe というファイルが生成され、実行可能になる

ただし上記のモノでは拡張性に欠けてしまいます。
(1ファイルごとにコマンドを書く必要が出てくる)

ちなみに、分かりやすさ重視のため、$^→ main.c にしています。

FPATH := \
    $(CURDIR)/ディレクトリまでのパス

疑似ターゲット : main.c

    gcc -c $(FPATH)/*.c $(FPATH)/*.h main.c -I $(FPATH) main.c

    gcc main.o -o 実行ファイル名

上記の例でも可能です。

このmain.cの箇所は、複数のファイル名を格納した変数でも問題ありません。

ちなみに、ワイルドカードを使用しているため -c で生成するオブジェクトファイル名を指定することができません。

番外編

・ターミナルにてMakeFileのコマンドを使う( 今回はpwdと同等のモノを出力できる )

make -f- <<< 'x:;@echo $(CURDIR)'

-f オプションはファイルを指定するオプションで

<<< は Here string というエスケープ処理

x という疑似ファイルを実行して、デフォルトの自動変数を echo している

Links:

[1] https://tex2e.github.io/blog/makefile/automatic-variables
[2] https://tex2e.github.io/blog/makefile/functions

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0