Linux の Makefile とは何ですか? どのように機能しますか?

Linux の Makefile とは何ですか? どのように機能しますか?

この便利なツールでプログラムをより効率的に実行およびコンパイルします
Makefile は自動コンパイルとリンクに使用されます。プロジェクトは多数のファイルで構成されます。ファイルに変更を加えると、プロジェクトが再リンクされます。ただし、すべてのファイルを再コンパイルする必要はありません。Makefile はファイル情報を記録し、リンク時に再コンパイルする必要があるファイルを決定できます。

make ツールは通常、一部のソース ファイルが変更された後にタスクを実行または更新する必要がある場合に使用されます。 make ツールは、実行される一連のタスクを定義する Makefile (または makefile) ファイルを読み取る必要があります。 make を使用してソース コードを実行可能プログラムにコンパイルできます。ほとんどのオープンソース プロジェクトでは、make を使用して最終的なバイナリ ファイルをコンパイルし、make install コマンドを使用してインストールを実行します。
この記事では、いくつかの基本的な例と高度な例を通して、make と Makefile の使用方法を説明します。始める前に、システムに make がインストールされていることを確認してください。

基本的な例は、依然として「Hello World」を印刷することから始まります。まず、myproject という名前のディレクトリを作成し、そのディレクトリ内に次の内容の Makefile ファイルを作成します。

こんにちは:
「こんにちは世界」をエコーし​​ます

myproject ディレクトリで make を実行すると、次の出力が表示されます。

$ 作る
「こんにちは世界」をエコーし​​ます
こんにちは世界

上記の例では、「say_hello」は他のプログラミング言語の関数名に似ています。これをターゲットといいます。ターゲットの後に、前提条件または依存関係が続きます。簡潔にするために、この例では前提条件を定義しませんでした。 echo 'Hello World' コマンドはレシピと呼ばれます。これらのステップは、目標を達成するための前提条件に基づいています。目標、前提条件、および手順が組み合わさってルールが構成されます。

要約すると、典型的なルールの構文は次のようになります。

目的: 前提条件
<TAB> 手順

たとえば、ターゲットは、前提条件 (ソース コード) に基づいたバイナリ ファイルになる場合があります。一方、前提条件は、他の前提条件に依存するターゲットになることもできます。

final_target: サブターゲット final_target.c
最終ターゲットを作成するためのレシピ
サブターゲット: sub_target.c
サブターゲットを作成するレシピ

ターゲットはファイルである必要はなく、この例のようにステップの名前だけにすることもできます。これを「疑似ターゲット」と呼びます

上記の例に戻ると、make が実行されると、コマンド全体 echo "Hello World" が表示され、その後に実際の実行結果が表示されます。コマンド自体を印刷したくない場合は、echo の前に @ を追加する必要があります。

こんにちは:
@echo "こんにちは世界"

make を再度実行すると、次の出力が表示されます。

$ 作る
こんにちは世界

次に、Makefile に次の疑似ターゲットを追加します: generate および clean:

こんにちは:
@echo "こんにちは世界"
生成する:
@echo "空のテキスト ファイルを作成しています..."
タッチファイル-{1..10}.txt
クリーン:
@echo "クリーンアップ中..."
rm *.txt

後で make を実行すると、 say_hello ターゲットのみが実行されます。これは、Makefile の最初のターゲットがデフォルトのターゲットであるためです。通常、デフォルトのターゲットが呼び出されます。これは、ほとんどのプロジェクトの最初のターゲットとして表示されるものです: all。 all はターゲットを呼び出す責任があります。特別な疑似目標.DEFAULT_GOAL を使用して、デフォルトの動作をオーバーライドできます。

Makefile の先頭に .DEFAULT_GOAL を追加します。

.DEFAULT_GOAL := generate

Make は、generate をデフォルトのターゲットとして使用します。

$ 作る
空のテキスト ファイルを作成しています...
タッチファイル-{1..10}.txt

名前が示すように、.DEFAULT_GOAL 疑似ターゲットは 1 つの目標のみを定義できます。このため、多くの Makefile には、複数のターゲットを呼び出すことができるターゲット all が含まれています。
次に、.DEFAULT_GOAL を削除し、all 目標を追加します。

すべて: say_hello 生成
こんにちは:
@echo "こんにちは世界"
生成する:
@echo "空のテキスト ファイルを作成しています..."
タッチファイル-{1..10}.txt
クリーン:
@echo "クリーンアップ中..."
rm *.txt

実行する前に、いくつかの特別な疑似ターゲットを追加しましょう。 .PHONY は、ファイルではないターゲットを定義するために使用されます。デフォルトでは、make はファイル名や最終変更日の存在を確認せずに、これらの疑似ターゲットの下のステップを呼び出します。完全な Makefile は次のとおりです。

.PHONY: すべて say_hello 生成クリーン
すべて: say_hello 生成
こんにちは:
@echo "こんにちは世界"
生成する:
@echo "空のテキスト ファイルを作成しています..."
タッチファイル-{1..10}.txt
クリーン:
@echo "クリーンアップ中..."
rm *.txt

make コマンドは say_hello を呼び出して次を生成します。

$ 作る
こんにちは世界
空のテキスト ファイルを作成しています...
タッチファイル-{1..10}.txt

clean は all や first ターゲットには入れないでください。 cleanは、クリーニングが必要な場合に手動で呼び出す必要があります。呼び出しメソッドはmake cleanです。

$ クリーンにする
掃除中…
rm *.txt

Makefile の基本を理解できたので、次は高度な例を見てみましょう。

高度な例 変数 前の例では、ターゲットと前提条件のほとんどは固定されていましたが、実際のプロジェクトでは通常、それらは変数とパターンに置き換えられます。

変数を定義する最も簡単な方法は、= 演算子を使用することです。たとえば、コマンド gcc を変数 CC に割り当てるには、次のようにします。

CC = gcc

これは再帰変数拡張と呼ばれ、次のようなルールで使用されます。

こんにちは: hello.c
${CC} hello.c -o hello

ご想像のとおり、これらの手順は次のように拡張されます。

gcc hello.c -o hello

${CC} と $(CC) はどちらも gcc を参照できます。しかし、変数が自分自身に代入しようとすると、無限ループが発生します。これを検証してみましょう:

CC = gcc
CC = ${CC}
全て:
@echo ${CC}

この時点で make を実行すると、次の結果になります。

$ 作る
Makefile:8: *** 再帰変数 'CC' は (最終的に) 自分自身を参照します。停止します。

これを回避するには、:= 演算子を使用します (これは単純な変数展開と呼ばれます)。次のコードでは上記の問題は発生しません。

CC := gcc
CC := ${CC}
全て:
@echo ${CC}

モードと関数 次の Makefile は、変数、モード、および関数を使用してすべての C コードをコンパイルします。行ごとに分析してみましょう。

# 使用法:
# make # すべてのバイナリをコンパイル
# make clean # すべてのバイナリとオブジェクトを削除
.PHONY = すべてクリーン
CC = gcc # 使用するコンパイラ
リンカーフラグ = -lm
SRCS := $(ワイルドカード *.c)
ビン:= $(SRCS:%.c=%)
すべて: ${BINS}
%: %.o
@echo "確認中..."
${CC} ${LINKERFLAG} $< -o $@
%.o: %.c
@echo "オブジェクトを作成しています。"
${CC} -c $<
クリーン:
@echo "クリーンアップ中..."
rm -rvf *.o ${BINS}

#で始まる行はコメントです
.PHONY = all clean という行は、 all と clean という 2 つの疑似ターゲットを定義します。
変数 LINKERFLAG は、gcc コマンドがステップで使用する必要があるパラメータを定義します。
SRCS := $(ワイルドカード *.c): $(ワイルドカード パターン) はファイル名に関連する関数です。この例では、「.c」サフィックスを持つすべてのファイルが SRCS 変数に保存されます。
BINS := $(SRCS:%.c=%): これは置換参照と呼ばれます。この例では、SRCS の値が「foo.c bar.c」の場合、BINS の値は「foo bar」になります。
all: ${BINS}: という行は、疑似ターゲット all は ${BINS} 変数内のすべての値をサブターゲットとして呼び出します。
ルール:

%: %.o
@echo "確認中..."
${CC} ${LINKERFLAG} $< -o $@

このルールを理解するために例を見てみましょう。 foo が変数 ${BINS} の値であると仮定します。 % は foo に一致します (% は任意のターゲットに一致します)。拡張後のルールは次のようになります。

foo: foo.o
@echo "確認中..."
gcc -lm foo.o -o foo

上記のように、% は foo に置き換えられます。 $< は foo.o に置き換えられます。 $< は事前設定された条件に一致させるために使用され、 $@ はターゲットに一致します。このルールは、${BINS} 内の各値に対して 1 回呼び出されます。
ルール:

%.o: %.c
@echo "オブジェクトを作成しています。"
${CC} -c $<

前のルールの各前提条件は、このルールではターゲットとして扱われます。展開後の外観は次のようになります。

foo.o: foo.c
@echo "オブジェクトを作成しています。"
gcc -c foo.c

最後に、 clean ターゲットでは、すべてのバイナリとコンパイル済みファイルが削除されます。
以下は書き直された Makefile です。これは foo.c ファイルと同じディレクトリに配置する必要があります。

# 使用法:
# make # すべてのバイナリをコンパイル
# make clean # すべてのバイナリとオブジェクトを削除
.PHONY = すべてクリーン
CC = gcc # 使用するコンパイラ
リンカーフラグ = -lm
SRCS := foo.c
ビン:= foo
全員: foo
foo: foo.o
@echo "確認中..."
gcc -lm foo.o -o foo
foo.o: foo.c
@echo "オブジェクトを作成しています。"
gcc -c foo.c
クリーン:
@echo "クリーンアップ中..."
rm -rvf foo.o foo

これらが一緒になって makefile を形成します。もちろん、これらの関数は少なすぎるため、他の多くのプロジェクトを追加することもできます。しかし、目的は、ファイルをコンパイルするためにどの他のファイルに依存する必要があるかをコンパイラに知らせることです。これらの依存ファイルが変更されると、コンパイラは最終的に生成されたファイルが古くなっていることを自動的に検出し、対応するモジュールを再コンパイルします。

要約する

以上がこの記事の全内容です。この記事の内容が皆様の勉強や仕事に何らかの参考学習価値をもたらすことを願います。123WORDPRESS.COM をご愛顧いただき、誠にありがとうございます。これについてもっと知りたい場合は、次のリンクをご覧ください。

以下もご興味があるかもしれません:
  • Linux での makefile コマンド パッケージの定義と使用
  • Linux での makefile の理解
  • Linux での Makefile の書き方と使い方の詳細な説明

<<:  Linux での MySQL 5.7.17 の最新安定バージョンのインストール チュートリアル

>>:  Vue が Ref を使用してレベル間でコンポーネントを取得する手順

推薦する

React Hooksを使用する際のよくある落とし穴

React Hooks は React 16.8 で導入された新しい機能で、クラスを使用せずに状態や...

CSS 画面サイズ適応実装例

CSS 画面サイズの適応を実現するには、まず CSS3 @media メディア クエリを導入する必要...

デザイナーが再びハマーの公式サイトに不満を述べる

昨年、この公開書簡は大ヒットし、羅永浩氏を驚かせた。今日、著者が新しい章を発表するとは思ってもみなか...

HTML テーブル タグ チュートリアル (47): ネストされたテーブル

<br />このページでは、テーブルをネストすることで組版を実現しています。つまり、1 ...

CocosCreatorの共通知識ポイントを整理する

目次1. シーンの読み込み2. ノードを見つける1. ノード検索2. その他のノード操作3. 再生ア...

1 つの記事で v-model とその修飾子を学ぶ

目次序文v-model の修飾子:怠け者トリム番号さまざまな入力タイプやその他の要素での v-mod...

iframe を通じて DOM 要素のサイズ変更を監視する

開発プロセス中によく発生する問題は、div のサイズ変更をどのように監視するかということです。たとえ...

CSS3 のメディアクエリと rem レイアウトを組み合わせてモバイル画面に適応

CSS3 構文: (750 ピクセルのデザインの場合、1rem = 100 ピクセル) @media...

Vue Element フロントエンドアプリケーション開発: Vuex での API ストアビューの使用

目次概要1. フロントエンドとバックエンドの分離とWeb APIの優先ルート設計2. Axiosネッ...

HTML でフォントの色を設定する方法と、PS を使用して HTML で正確なフォントの色を取得する方法

1. HTMLフォントカラー設定HTML では、フォント タグを使用してフォント コンテンツの色を設...

Vue で webSocket を使用してリアルタイムの天気を更新する方法

目次序文webSocket の操作と例について:ウェブソケット1. webSocketについて2. ...

フロントエンドの上級者向けコースでは、JavaScript のストレージ機能の使い方を学習します。

目次序文背景実施計画の考え方js ストレージ機能ソリューション設計やっと要約する序文どの SaaS ...

MySQL ページング制限の実用的な最適化

序文クエリ ステートメントを使用する場合、多くの場合、データの最初の数行または中間行を返す必要があり...

Vueデータ監視の原理の詳細な説明

目次1. はじめにII. 監視対象2.1 なぜオブジェクトを監視する必要があるのですか? 2.2 デ...