GNU/Linux >> Linux の 問題 >  >> Linux

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

特定のファイルが更新されたときにタスクを実行または更新する場合は、make ユーティリティが重宝します。 make ユーティリティにはファイルMakefileが必要です (またはmakefile )、実行するタスクのセットを定義します。 makeを使用した可能性があります ソースコードからプログラムをコンパイルします。ほとんどのオープンソースプロジェクトはmakeを使用します 最終的な実行可能バイナリをコンパイルします。これは、make installを使用してインストールできます。 。

この記事では、makeについて説明します。 およびMakefile 基本的な例と高度な例を使用します。開始する前に、makeを確認してください システムにインストールされています。

基本的な例

まず、端末にクラシックな「HelloWorld」を印刷してみましょう。空のディレクトリmyprojectを作成します ファイルを含むMakefile このコンテンツで:

say_hello:
        echo "Hello World"

次に、makeと入力してファイルを実行します ディレクトリmyproject内 。出力は次のようになります:

$ make
echo "Hello World"
Hello World

上記の例では、say_hello 他のプログラミング言語と同様に、関数名のように動作します。これはターゲットと呼ばれます 。 前提条件 または依存関係 ターゲットに従ってください。簡単にするために、この例では前提条件を定義していません。コマンドecho "Hello World" レシピと呼ばれます 。 レシピ 前提条件を使用します ターゲットを作成する 。ターゲット、前提条件、レシピが一緒になってルールを作成します 。

要約すると、以下は典型的なルールの構文です:

target: prerequisites
<TAB> recipe

例として、ターゲットは前提条件(ソースファイル)に依存するバイナリファイルである可能性があります。一方、前提条件は、他の依存関係に依存するターゲットになることもあります。

final_target: sub_target final_target.c
        Recipe_to_create_final_target

sub_target: sub_target.c
        Recipe_to_create_sub_target

ターゲットがファイルである必要はありません。この例のように、レシピの単なる名前である可能性があります。これらを「偽のターゲット」と呼びます。

上記の例に戻ると、make コマンド全体が実行され、echo "Hello World" が表示され、続いて実際のコマンド出力が表示されました。私たちはしばしばそれを望んでいません。実際のコマンドのエコーを抑制するには、echoを開始する必要があります @で :

say_hello:
        @echo "Hello World"

次に、makeを実行してみます また。出力にはこれだけが表示されます:

$ make
Hello World

さらにいくつかの偽のターゲットを追加しましょう:generate およびclean Makefileに :

say_hello:
        @echo "Hello World"

generate:
        @echo "Creating empty text files..."
        touch file-{1..10}.txt

clean:
        @echo "Cleaning up..."
        rm *.txt

makeを実行しようとすると 変更後は、ターゲットのsay_helloのみ 実行されます。これは、makefileの最初のターゲットのみがデフォルトのターゲットであるためです。多くの場合、デフォルトの目標と呼ばれます 、これがallが表示される理由です ほとんどのプロジェクトの最初のターゲットとして。 allの責任です 他のターゲットを呼び出すため。 .DEFAULT_GOALと呼ばれる特別な偽のターゲットを使用して、この動作をオーバーライドできます。 。

makefileの先頭にそれを含めましょう:

.DEFAULT_GOAL := generate

これにより、ターゲットのgenerateが実行されます デフォルトとして:

$ make
Creating empty text files...
touch file-{1..10}.txt

名前が示すように、偽のターゲット.DEFAULT_GOAL 一度に実行できるターゲットは1つだけです。これが、ほとんどのmakefileにallが含まれている理由です。 必要な数のターゲットを呼び出すことができるターゲットとして。

偽のターゲットallを含めましょう .DEFAULT_GOALを削除します :

all: say_hello generate

say_hello:
        @echo "Hello World"

generate:
        @echo "Creating empty text files..."
        touch file-{1..10}.txt

clean:
        @echo "Cleaning up..."
        rm *.txt

makeを実行する前に 、別の特別な偽のターゲット、.PHONYを含めましょう 、ファイルではないすべてのターゲットを定義します。 make その名前のファイルが存在するかどうか、またはその最終変更時刻が何であるかに関係なく、レシピを実行します。完全なmakefileは次のとおりです:

.PHONY: all say_hello generate clean

all: say_hello generate

say_hello:
        @echo "Hello World"

generate:
        @echo "Creating empty text files..."
        touch file-{1..10}.txt

clean:
        @echo "Cleaning up..."
        rm *.txt

make say_helloを呼び出す必要があります およびgenerate

$ make
Hello World
Creating empty text files...
touch file-{1..10}.txt

cleanを呼び出さないことをお勧めします all またはそれを最初のターゲットとして置きます。 clean makeの最初の引数としてクリーニングが必要な場合は、手動で呼び出す必要があります :

$ make clean
Cleaning up...
rm *.txt

基本的なmakefileがどのように機能し、簡単なmakefileを作成するかがわかったところで、さらに高度な例を見てみましょう。

高度な例

変数

その他のLinuxリソース

  • Linuxコマンドのチートシート
  • 高度なLinuxコマンドのチートシート
  • 無料のオンラインコース:RHELの技術概要
  • Linuxネットワーキングのチートシート
  • SELinuxチートシート
  • Linuxの一般的なコマンドのチートシート
  • Linuxコンテナとは何ですか?
  • 最新のLinux記事

上記の例では、ほとんどのターゲット値と前提条件値がハードコーディングされていますが、実際のプロジェクトでは、これらは変数とパターンに置き換えられています。

makefileで変数を定義する最も簡単な方法は、=を使用することです。 オペレーター。たとえば、コマンドgccを割り当てるには 変数CCに :

CC = gcc

これは、再帰展開変数とも呼ばれます。 、および以下に示すようなルールで使用されます:

hello: hello.c
    ${CC} hello.c -o hello

ご想像のとおり、レシピはターミナルに渡されると次のように拡張されます。

gcc hello.c -o hello

両方の${CC} および$(CC) gccを呼び出すための有効な参照です 。しかし、変数をそれ自体に再割り当てしようとすると、無限ループが発生します。これを確認しましょう:

CC = gcc
CC = ${CC}

all:
    @echo ${CC}

makeを実行しています 結果は次のようになります:

$ make
Makefile:8: *** Recursive variable 'CC' references itself (eventually).  Stop.

このシナリオを回避するために、:=を使用できます 演算子(これは単に展開された変数とも呼ばれます )。以下のmakefileの実行に問題はありません:

CC := gcc
CC := ${CC}

all:
    @echo ${CC}

パターンと機能

次のmakefileは、変数、パターン、および関数を使用して、すべてのCプログラムをコンパイルできます。行ごとに調べてみましょう:

# Usage:
# make        # compile all binary
# make clean  # remove ALL binaries and objects

.PHONY = all clean

CC = gcc                        # compiler to use

LINKERFLAG = -lm

SRCS := $(wildcard *.c)
BINS := $(SRCS:%.c=%)

all: ${BINS}

%: %.o
        @echo "Checking.."
        ${CC} ${LINKERFLAG} $< -o $@

%.o: %.c
        @echo "Creating object.."
        ${CC} -c $<

clean:
        @echo "Cleaning up..."
        rm -rvf *.o ${BINS}
  • #で始まる行 コメントです。

  • .PHONY = all clean 偽のターゲットを定義するall およびclean

  • 変数LINKERFLAG gccで使用されるフラグを定義します レシピで。

  • SRCS := $(wildcard *.c)$(wildcard pattern) ファイル名の関数の1つです 。この場合、.cを持つすべてのファイル 拡張子は変数SRCSに保存されます 。

  • BINS := $(SRCS:%.c=%) :これは置換参照と呼ばれます 。この場合、SRCS 値は'foo.c bar.c'BINS 'foo bar'があります 。

  • all: ${BINS} :偽のターゲットall ${BINS}の値を呼び出します 個別のターゲットとして。

  • ルール:

    %: %.o
      @echo "Checking.."
      ${CC} ${LINKERFLAG} $&lt; -o $@

    このルールを理解するために例を見てみましょう。 fooと仮定します ${BINS}の値の1つです 。次に% fooと一致します (% 任意のターゲット名に一致できます)。以下は、拡張された形式のルールです。

    foo: foo.o
      @echo "Checking.."
      gcc -lm foo.o -o foo

    示されているように、% fooに置き換えられます 。 $< foo.oに置き換えられます 。 $< 前提条件と$@に一致するようにパターン化されています ターゲットに一致します。このルールは、${BINS}のすべての値に対して呼び出されます

  • ルール:

    %.o: %.c
      @echo "Creating object.."
      ${CC} -c $&lt;

    前のルールのすべての前提条件は、このルールのターゲットと見なされます。以下は、拡張された形式のルールです。

    foo.o: foo.c
      @echo "Creating object.."
      gcc -c foo.c
  • 最後に、ターゲットのclean内のすべてのバイナリとオブジェクトファイルを削除します 。

以下は、単一のファイルfoo.c:を持つディレクトリに配置されていると仮定して、上記のmakefileを書き直したものです。

# Usage:
# make        # compile all binary
# make clean  # remove ALL binaries and objects

.PHONY = all clean

CC = gcc                        # compiler to use

LINKERFLAG = -lm

SRCS := foo.c
BINS := foo

all: foo

foo: foo.o
        @echo "Checking.."
        gcc -lm foo.o -o foo

foo.o: foo.c
        @echo "Creating object.."
        gcc -c foo.c

clean:
        @echo "Cleaning up..."
        rm -rvf foo.o foo

makefileの詳細については、完全なリファレンスと例を提供するGNUMakeマニュアルを参照してください。

また、GNU Autotoolsの概要を読んで、コーディングプロジェクトのmakefileの生成を自動化する方法を学ぶこともできます。


Linux
  1. NGINXとは何ですか?それはどのように機能しますか?

  2. Webサーバーとは何ですか?Webサーバーはどのように機能しますか?

  3. スティッキービットはどのように機能しますか?

  1. Awkの「!a [$ 0] ++」はどのように機能しますか?

  2. .bashrcの目的とそれはどのように機能しますか?

  3. Ssh – Tcp-keepaliveはSshでどのように機能しますか?

  1. DNSとは何ですか?どのように機能しますか?

  2. rm はどのように機能しますか? rm は何をしますか?

  3. sig_atomic_t は実際にどのように機能しますか?