Linuxのgmakeとは何ですか

Nov 09, 2022 pm 07:04 PM
linux

Linux では、gmake は GUN make であり、C 言語ソフトウェアを構築するために広く使用されているプログラムであり、Linux カーネルやその他の一般的に使用される GNU/Linux プログラムおよびソフトウェア ライブラリの構築に使用されます。 GNU Make は、シェル コマンドを自動化し、反復的なタスクの実行を支援できるプログラムです。ソース コード ファイルをプログラムやライブラリにコンパイルするなど、ファイルを他の形式に変換するためによく使用されます。

Linuxのgmakeとは何ですか

#このチュートリアルの動作環境: linux7.3 システム、Dell G3 コンピューター。

gmake は GUN make です。Linux 以外のプラットフォームでは通常、make が使用されているため、GUN make は gmake と呼び出す必要があります。

GNU Make は、C 言語ソフトウェアを構築するために広く使用されているプログラムです。 Linux カーネルお​​よびその他の一般的に使用される GNU/Linux プログラムおよびソフトウェア ライブラリを構築するために使用されます。

ほとんどの組み込みソフトウェア開発者は、キャリアのある時点で、小さなライブラリをコンパイルするか、プロジェクト全体を構築するために GNU Make を使用することになります。 Make の代替手段は数多くありますが、その機能セットと広範なサポートにより、新しいソフトウェアのビルド システムとして Make が選択されることがよくあります。

この記事では、GNU Make の一般的な概念と機能について説明し、Make ビルドを最大限に活用する方法についてのアドバイスが含まれています! これは、私のお気に入り/最もよく使用される Make の概念と機能の簡単な紹介です。

GNU Make とは何ですか?

GNU Make は、シェル コマンドを自動化し、反復的なタスクの実行を支援するプログラムです。ソース コード ファイルをプログラムやライブラリにコンパイルするなど、ファイルを他の形式に変換するためによく使用されます。

これは、前提条件を追跡し、コマンドの階層を実行してターゲットを生成することによって行われます。

GNU Make マニュアルは非常に長いですが、私が見つけた中で最高のリファレンスなので、一読することをお勧めします: https://www.gnu.org/software/make/manual/html_node/index. html

Make を選択する場合

Make は、プロジェクトのビルドに別のプロジェクトに含まれる小さな C/C プロジェクトまたはライブラリを構築するのに適しています。システム。ほとんどのビルド システムには、make ベースのサブプロジェクトを統合する方法があります。

大規模なプロジェクトの場合は、より最新のビルド システムの方が使いやすい場合があります。

次のような状況では、Make 以外のビルド システムを使用することをお勧めします。

ビルドされるターゲット (またはファイル) の数が数百である (または最終的には数百になる) 場合。変数、ターゲット定義、および環境構成を設定して保存する「構成」ステップが必要です。プロジェクトは社内または非公開のままであり、エンド ユーザーが構築する必要はありません。デバッグは面倒な作業だと感じるかもしれません。構築する必要があるものはクロスプラットフォームであり、macOS、Linux、Windows 上で構築できます。このような場合、CMake、Bazel、Meson、またはその他の最新のビルド システムを使用する方が快適であることがわかります。

Make を呼び出す

make を実行すると、現在のディレクトリから Makefile という名前のファイルがロードされ、デフォルトのターゲットの更新が試行されます (これについては後で詳しく説明します)。 )導入目標)。

Make は、GNUmakefile、makefile、makefile という名前のファイルを順番に検索します。

-f/--file パラメーターを使用して、特定の makefile を指定できます:

$ make - f foo.mk 位置引数としてリストして、任意の数のターゲットを指定できます。

# 一般的なターゲット $ make clean all -C 引数で Make ディレクトリを渡すと、次のように Make が実行されます。最初にそのディレクトリに cd します。

$ make -C some/sub/directory 面白い事実: git を -C とともに実行して同じ効果を達成することもできます!

並列呼び出し

-j または -l オプションが指定されている場合、Make はジョブを並列実行できます。私が聞いたガイドラインの 1 つは、ジョブの制限をプロセッサー コアの数の 1.5 倍に設定することです。

#4 コアのマシン: make -j make -j 興味深いことに、私は-l "load limit" オプションを使用すると、-j "job" オプションを使用するよりも CPU 使用率がわずかに向上することがわかりました。 YMMV!

現在のマシンの CPU 数をプログラムで確認する方法はいくつかあります。簡単な方法は、python multiprocessing.cpu_count() 関数を使用して、システムでサポートされているスレッドの数を取得することです (ハイパースレッド システムの場合、これは多くのコンピュータ リソースを消費しますが、システムに負荷をかけるよりも望ましい場合があることに注意してください)無制限の仕事を生み出します)。

#サブシェルで Python の cpu_count() 関数を呼び出します make -l (python -c "import multiprocessing;print (multiprocessing.cpu_count())")

並列呼び出し中の出力

Make が大量の出力を持つコマンドを並列実行している場合、stdout で出力がずらして表示されることがあります。この問題に対処するために、Make には、output -sync というオプションがあります。

--output-sync=recurse を使用することをお勧めします。これにより、他のレシピの出力を邪魔することなく、各目標が完了したときにレシピの出力全体が印刷されます。

レシピで再帰的 Make が使用されている場合は、再帰的 Make 全体の出力もまとめて出力されます。

Makefile の分析 Makefile には、ターゲットを生成するためのルールが含まれています。 Makefile の基本コンポーネントの一部は次のとおりです。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#Comments are prefixed with the '#' symbol

 

#A variable assignment

FOO = "hello there!"

 

#A rule creating target "test", with "test.c" as a prerequisite

test: test.c

 # The contents of a rule is called the "recipe"and is

 # typically composed of one or more shell commands.

 # It must be indented from the target name (historically with

 # tabs, spaces are permitted)

 

 # Using the variable "FOO"

 echo $(FOO)

 

 # Calling the C compiler using a predefined variable naming

 # the default C compiler, '$(CC)'

 $(CC) test.c -o test

ログイン後にコピー

上記の例の各部分を見てみましょう。

変数

変数は構文 $(FOO) を使用します。ここで、FOO は変数名です。

Make には他のデータ型がないため、変数にはプレーン文字列が含まれます。変数に追加すると、スペースと新しいコンテンツが追加されます。

1

2

3

4

5

6

7

FOO = one

FOO += two

# FOO is now "one two"

 

FOO = one

FOO = $(FOO)two

# FOO is now "onetwo"

ログイン後にコピー

変数の割り当て

GNU Make 構文では、変数に値を割り当てるには 2 つの方法があります:

右側の式は文字通り変数に割り当てられます。これは、変数を使用するときに式を評価する C/C のマクロに非常によく似ています。 :

1

2

3

4

5

FOO = 1

BAR = $(FOO)

FOO = 2

# prints BAR=2

$(info BAR=$(BAR))

ログイン後にコピー

式の結果を変数に代入します。式は代入中に展開されます:

1

2

3

4

5

FOO = 1

BAR := $(FOO)

FOO = 2

# prints BAR=1

$(info BAR=$(BAR))

ログイン後にコピー

注: $(info上記 ...) 関数は式を出力するために使用されます。これは、メイクファイルをデバッグするときに非常に便利です!*'

明示的、暗黙的、または自動的に設定されていない変数は、空の文字列として評価されます。

環境変数

環境変数は、Make 実行環境に引き継がれます。次の makefile を例に挙げます。

1

$(info YOLO variable = $(YOLO))

ログイン後にコピー

make の実行時にシェル コマンドで変数 YOLO を設定すると、次の値が設定されます:

1

2

3

$ YOLO="hello there!" make

YOLO variable = hello there!

make: *** No targets.  Stop.

ログイン後にコピー

注: Make ファイルにはターゲットがリストされていないため、Make は「ターゲットがありません」エラーを出力します!

?= 代入構文を使用する場合、Make は変数に値がない場合にのみ値を割り当てます。

Makefile:

1

2

#默认CC为gcc

CC ? = gcc

ログイン後にコピー

Makefile で $(CC) をオーバーライドできます:

$ CC=clang make

もう 1 つの一般的なパターンは、追加のフラグの挿入を許可することです。 Makefile では、変数を直接割り当てるのではなく追加します。

CFLAGS = -Wall

これにより、環境から追加のフラグを渡すことができます:

1

$ CFLAGS='-Werror=conversion -Werror=double-promotion' make

ログイン後にコピー

これは非常に便利です便利 !

最も重要な変数

使用される変数の特別なカテゴリは、オーバーライド変数と呼ばれます。このコマンド ライン オプションを使用すると、環境または Makefile に設定された値がオーバーライドされます!

Makefile:

1

2

3

# any value set elsewhere

YOLO = "not overridden"

$(info $(YOLO))

ログイン後にコピー

Command:

1

2

3

4

5

# setting "YOLO" to different values in the environment + makefile + overriding

# variable, yields the overriding value

$ YOLO="environment set" make YOLO='overridden!!'

overridden!!

make: *** No targets.  Stop.

ログイン後にコピー

ターゲット変数

これらの変数は、レシピ コンテキストでのみ使用できます。これらは、必須のレシピにも適用されます。

1

2

3

4

5

# set the -g value to CFLAGS

# applies to the prog.o/foo.o/bar.o recipes too!

prog : CFLAGS = -g

prog : prog.o foo.o bar.o

 echo $(CFLAGS) # will print '-g'

ログイン後にコピー

暗黙的変数

これらは、Make によって事前定義されています (ただし、同じ名前の他の変数タイプでオーバーライドされます)。一般的な例:

1

2

3

4

5

6

$(CC) - the C compiler (gcc)

$(AR) - archive program (ar)

$(CFLAGS) - flags for the C compiler

Full list here:

 

https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html

ログイン後にコピー

自動変数

これらは、レシピ コンテキストで Make によって設定される特別な変数です。で 。これらは、名前の重複を防ぐのに役立ちます (Don'trepeat Yourself)。

いくつかの一般的な自動変数:

1

2

3

4

5

6

7

8

9

10

# $@ : the target name, here it would be "test.txt"

test.txt:

 echo HEYO > $@

 

# $^ : name of all the prerequisites

all.zip: foo.txt test.txt

 # run the gzip command with all the prerequisites "$^", outputting to the

 # name of the target, "$@"

 gzip -c $^ > $@

See more at: https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html

ログイン後にコピー

target(target)

ターゲットはルール 構文の左側:

1

2

arget: prerequisite

 recipe

ログイン後にコピー

target は、ほとんどの場合、ファイルの名前を指定します。これは、Make が最終変更時刻を使用して、ターゲットがその前提条件よりも新しいか古いか、および再ビルドが必要かどうかを追跡するためです!

Make を呼び出すときは、次のように指定することで、必要なものを指定できます。位置引数。ビルドするターゲット:

1

2

# make the 'test.txt' and 'all.zip' targets

make test.txt all.zip

ログイン後にコピー

如果您没有在命令中指定目标,Make将使用makefile中指定的第一个目标,称为“默认目标”(如果需要,也可以覆盖默认目标)。

虚假phony目标

有时候设置元目标是很有用的,比如all, clean, test等等。在这些情况下,您不希望Make检查名为all/clean等的文件。

Make提供.PHONY目标语法,将目标标记为不指向文件:

假设我们的项目构建了一个程序和一个库foo和foo.a;如果我们想要 在默认情况下,我们可以创建一个'all'规则来构建两者 .PHONY:all all : foo foo.a

如果你有多个假目标,一个好的模式可能是将每个目标都附加到定义它的.PHONY中:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

# the 'all' rule that builds and tests. Note that it's listed first to make it

# the default rule

.PHONY: all

all: build test

 

# compile foo.c into a program 'foo'

foo: foo.c

 $(CC) foo.c -o foo

 

# compile foo-lib.c into a library 'foo.a'

foo.a: foo-lib.c

 # compile the object file

 $(CC) foo-lib.c -c foo-lib.o

 use ar to create a static library containing our object file. using the

 '$@' variable here to specify the rule target 'foo.a'

 $(AR) rcs $@ foo-lib.o

 

# a phony rule that builds our project; just contains a prerequisite of the

# library + program

.PHONY: build

build: foo foo.a

 

# a phony rule that runs our test harness. has the 'build' target as a

# prerequisite! Make will make sure (pardon the pun) the build rule executes

# first

.PHONY: test

test: build

 ./run-tests.sh

ログイン後にコピー

请注意! !. phony目标总是被认为是过期的,因此Make将总是运行这些目标的配方(因此也运行任何具有. phony先决条件的目标!)小心使用! !

隐式规则

隐含规则由Make提供。我发现使用它们会让人感到困惑,因为在幕后发生了太多的行为。你偶尔会在野外遇到它们,所以要小心。

1

2

3

4

5

6

# this will compile 'test.c' with the default $(CC), $(CFLAGS), into the program

'test'. it will handle prerequisite tracking on test.c

test: test.o

Full list of implicit rules here:

 

https://www.gnu.org/software/make/manual/html_node/Catalogue-of-Rules.html

ログイン後にコピー

模式的规则

模式规则允许你编写一个通用规则,通过模式匹配应用于多个目标:

1

2

3

4

# Note the use of the '$<&#39; automatic variable, specifying the first

# prerequisite, which is the .c file

%.o: %.c

 $(CC) -c $< -o $@

ログイン後にコピー

or

1

2

3

4

5

6

7

OBJ_FILES = foo.o bar.o

 

# Use CC to link foo.o + bar.o into &#39;program&#39;. Note the use of the &#39;$^&#39;

# automatic variable, specifying ALL the prerequisites (all the OBJ_FILES)

# should be part of the link command

program: $(OBJ_FILES)

    $(CC) -o $@ $^

ログイン後にコピー

先决条件

如上所述,Make将在运行规则之前检查这些目标。它们可以是文件或其他目标。

如果任何先决条件比目标更新(修改时间),Make将运行目标规则。

在C项目中,你可能有一个将C文件转换为目标文件的规则,如果C文件发生变化,你希望目标文件重新生成:

1

2

3

foo.o: foo.c

 # use automatic variables for the input and output file names

 $(CC) $^ -c $@

ログイン後にコピー

自动的先决条件

对于C语言项目来说,一个非常重要的考虑是,如果C文件的#include头文件发生了变化,那么将触发重新编译。这是通过gcc/clang的-M编译器标志完成的,它将输出一个.d文件,然后用Make include指令导入。

.d文件将包含.c文件的必要先决条件,因此任何头文件的更改都会导致重新构建。

点击这里查看更多详情:

https://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html

http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/

基本形式可能是:

1

2

3

4

5

6

7

8

9

10

# these are the compiler flags for emitting the dependency tracking file. Note

# the usage of the &#39;$<&#39; automatic variable

DEPFLAGS = -MMD -MP -MF $<.d

 

test.o: test.c

    $(CC) $(DEPFLAGS) $< -c $@

 

# bring in the prerequisites by including all the .d files. prefix the line with

# &#39;-&#39; to prevent an error if any of the files do not exist

-include $(wildcard *.d)

ログイン後にコピー

Order-only 先决条件

这些先决条件只有在不存在的情况下才会构建;如果它们比目标更新,则不会触发目标重新构建。

典型的用法是为输出文件创建一个目录;将文件发送到目录将更新其mtime属性,但我们不希望由此触发重新构建。

1

2

3

4

5

6

7

8

9

10

OUTPUT_DIR = build

 

# output the .o to the build directory, which we add as an order-only

# prerequisite- anything right of the | pipe is considered order-only

$(OUTPUT_DIR)/test.o: test.c | $(OUTPUT_DIR)

 $(CC) -c $^ -o $@

 

# rule to make the directory

$(OUTPUT_DIR):

 mkdir -p $@

ログイン後にコピー

recipe

“recipe”是创建目标时要执行的shell命令列表。它们被传递到子shell中(默认为/bin/sh)。如果target在recipe运行后更新,则认为规则是成功的(但如果没有更新,则不视为错误)。

1

2

3

foo.txt:

 # a simple recipe

 echo HEYO > $@

ログイン後にコピー

如果配方中的任何一行返回非零退出代码,Make将终止并打印一条错误消息。你可以通过前缀-字符来告诉Make忽略非零退出码:

1

2

3

4

.PHONY: clean

clean:

 # we don't care if rm fails

 -rm -r ./build

ログイン後にコピー

在recipe行前面加上@将禁止在执行之前echo该行:

1

2

3

4

5

clean:

 @# this recipe will just print 'About to clean everything!'

 @# prefixing the shell comment lines '#' here also prevents them from

 @# appearing during execution

 @echo About to clean everything!

ログイン後にコピー

Make会在运行recipe上下文中展开变量/函数表达式,但不会处理它。如果你想访问shell变量,请使用$:

1

2

3

4

5

6

7

8

USER = linus

 

print-user:

 print out the shell variable $USER

 echo $$USER

 

 print out the make variable USER

 echo $(USER)

ログイン後にコピー

function

Make函数的调用语法如下:

$(function-name arguments) 其中arguments是用逗号分隔的参数列表。

For example:

1

2

3

4

5

6

7

8

9

FILES=$(wildcard *.c)

 

# you can combine function calls; here we strip the suffix off of $(FILES) with

# the $(basenamefunction, then add the .o suffix

O_FILES=$(addsuffix .o,$(basename $(FILES)))

 

# note that the GNU Make Manual suggests an alternate form for this particular

# operation:

O_FILES=$(FILES:.c=.o)

ログイン後にコピー

用户定义函数

1

2

3

4

5

6

7

8

9

reverse = $(2) $(1)

 

foo = $(call reverse,a,b)

 

# recursive wildcard (use it instead of $(shell find . -name '*.c'))

# taken from https://stackoverflow.com/a/18258352

rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))

 

C_FILES = $(call rwildcard,.,*.c)

ログイン後にコピー

shell函数

你可以让Make调用一个shell表达式并捕获结果:

TODAYS_DATE=$(shell date --iso-8601)

不过,我在使用这个功能时很谨慎;它会增加对你使用的任何程序的依赖,所以如果你正在调用更奇特的程序,确保你的构建环境是受控的(例如在容器中或使用Conda)。

make的条件表达式

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

FOO=yolo

ifeq ($(FOO),yolo)

$(info foo is yolo!)

else

$(info foo is not yolo :( )

endif

 

# testing if a variable is set; unset variables are empty

ifneq ($(FOO),)  # checking if FOO is blank

$(info FOO is unset)

endif

 

"complex conditional"

ifeq ($(FOO),yolo)

$(info foo is yolo)

else ifeq ($(FOO), heyo)

$(info foo is heyo)

else

$(info foo is not yolo or heyo :( )

endif

ログイン後にコピー

make include

sources.mk:

SOURCE_FILES :=
bar.c
foo.c \

Makefile:

include sources.mk

OBJECT_FILES = $(SOURCE_FILES:.c=.o)

%.o: %.c (CC) -c ^ -o $@

make eval

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

# generate rules for xml->json in some weird world

FILES = $(wildcard inputfile/*.xml)

 

# create a user-defined function that generates rules

define GENERATE_RULE =

$(eval

# prereq rule for creating output directory

$(1)_OUT_DIR = $(dir $(1))/$(1)_out

$(1)_OUT_DIR:

 mkdir -p $@

 

# rule that calls a script on the input file and produces $@ target

$(1)_OUT_DIR/$(1).json: $(1) | $(1)_OUT_DIR

 ./convert-xml-to-json.sh $(1) $@

)

 

# add the target to the all rule

all: $(1)_OUT_DIR/$(1).json

endef

 

# produce the rules

.PHONY: all

all:

 

$(foreach file,$(FILES),$(call GENERATE_RULE,$(file)))

ログイン後にコピー

请注意,使用Make的这个特性的方法可能会让人很困惑,添加一些有用的注释来解释意图是什么,对您未来的自己会很有用!

VPATH

VPATH是一个特殊的Make变量,它包含Make在查找先决条件和目标时应该搜索的目录列表。

它可以用来将对象文件或其他派生文件发送到./build目录中,而不是把src目录弄得乱七八糟:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

# This makefile should be invoked from the temporary build directory, eg:

# $ mkdir -p build && cd ./build && make -f ../Makefile

 

# Derive the directory containing this Makefile

MAKEFILE_DIR = $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))

 

# now inform Make we should look for prerequisites from the root directory as

# well as the cwd

VPATH += $(MAKEFILE_DIR)

 

SRC_FILES = $(wildcard $(MAKEFILE_DIR)/src/*.c)

 

# Set the obj file paths to be relative to the cwd

OBJ_FILES = $(subst $(MAKEFILE_DIR)/,,$(SRC_FILES:.c=.o))

 

# now we can continue as if Make was running from the root directory, and not a

# subdirectory

 

# $(OBJ_FILES) will be built by the pattern rule below

foo.a: $(OBJ_FILES)

 $(AR) rcs $@ $(OBJ_FILES)

 

# pattern rule; since we added ROOT_DIR to VPATH, Make can find prerequisites

# like `src/test.c` when running from the build directory!

%.o: %.c

 # create the directory tree for the output file  

 echo $@

 mkdir -p $(dir $@)

 # compile

 $(CC) -c $^ -o $@

ログイン後にコピー

touch file

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

# our tools are stored in tools.tar.gz, and downloaded from a server

TOOLS_ARCHIVE = tools.tar.gz

TOOLS_URL = https://httpbin.org/get

 

# the rule to download the tools using wget

$(TOOLS_ARCHIVE):

 wget $(TOOLS_URL) -O $(TOOLS_ARCHIVE)

 

# rule to unpack them

tools-unpacked.dummy: $(TOOLS_ARCHIVE)

 # running this command results in a directory.. but how do we know it

 # completed, without a file to track?

 tar xzvf $^

 use the touch command to record completion in a dummy file

 touch $@

ログイン後にコピー

调试makefile

对于小问题,我通常使用printf的Make等效函数,即$(info/warning/error)函数,例如当检查不工作的条件路径时:

1

2

3

ifeq ($(CC),clang)

$(error whoops, clang not supported!)

endif

ログイン後にコピー

要调试为什么规则在不应该运行的情况下运行(或者相反),可以使用——debug选项:https://www.gnu.org/software/make/manual/html_node/Options-Summary.html

我建议在使用此选项时将stdout重定向到文件,它会产生大量输出。

profile

For profiling a make invocation (e.g. for attempting to improve compilation times), this tool can be useful:

https://github.com/rocky/remake

Check out the tips here for compilation-related performance improvements:

https://interrupt.memfault.com/blog/improving-compilation-times-c-cpp-projects

verbose flag

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

# Makefile for building the 'example' binary from C sources

 

# Verbose flag

ifeq ($(V),1)

Q :=

else

Q := @

endif

 

# The build folder, for all generated output. This should normally be included

# in a .gitignore rule

BUILD_FOLDER := build

 

# Default all rule will build the 'example' target, which here is an executable

.PHONY:

all: $(BUILD_FOLDER)/example

 

# List of C source files. Putting this in a separate variable, with a file on

# each line, makes it easy to add files later (and makes it easier to see

# additions in pull requests). Larger projects might use a wildcard to locate

# source files automatically.

SRC_FILES = \

    src/example.c \

    src/main.c

 

# Generate a list of .o files from the .c files. Prefix them with the build

# folder to output the files there

OBJ_FILES = $(addprefix $(BUILD_FOLDER)/,$(SRC_FILES:.c=.o))

 

# Generate a list of depfiles, used to track includes. The file name is the same

as the object files with the .d extension added

DEP_FILES = $(addsuffix .d,$(OBJ_FILES))

 

# Flags to generate the .d dependency-tracking files when we compile.  It's

# named the same as the target file with the .d extension

DEPFLAGS = -MMD -MP -MF $@.d

 

# Include the dependency tracking files

-include $(DEP_FILES)

 

# List of include dirs. These are put into CFLAGS.

INCLUDE_DIRS = \

    src/

 

# Prefix the include dirs with '-I' when passing them to the compiler

CFLAGS += $(addprefix -I,$(INCLUDE_DIRS))

 

# Set some compiler flags we need. Note that we're appending to the CFLAGS

# variable

CFLAGS += \

    -std=c11 \

    -Wall \

    -Werror \

    -ffunction-sections -fdata-sections \

    -Og \

    -g3

 

# Our project requires some linker flags: garbage collect sections, output a

# .map file

LDFLAGS += \

    -Wl,--gc-sections,-Map,$@.map

 

# Set LDLIBS to specify linking with libm, the math library

LDLIBS += \

    -lm

 

# The rule for compiling the SRC_FILES into OBJ_FILES

$(BUILD_FOLDER)/%.o: %.c

 @echo Compiling $(notdir $<)

 @# Create the folder structure for the output file

 @mkdir -p $(dir $@)

 $(Q) $(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@

 

# The rule for building the executable "example", using OBJ_FILES as

# prerequisites. Since we're not relying on an implicit rule, we need to

# explicity list CFLAGS, LDFLAGS, LDLIBS

$(BUILD_FOLDER)/example: $(OBJ_FILES)

 @echo Linking $(notdir $@)

 $(Q) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@

 

# Remove debug information for a smaller executable. An embedded project might

# instead using [arm-none-eabi-]objcopy to convert the ELF file to a raw binary

# suitable to be written to an embedded device

STRIPPED_OUTPUT = $(BUILD_FOLDER)/example-stripped

 

$(STRIPPED_OUTPUT): $(BUILD_FOLDER)/example

 @echo Stripping $(notdir $@)

 $(Q)objcopy --strip-debug $^ $@

 

# Since all our generated output is placed into the build folder, our clean rule

# is simple. Prefix the recipe line with '-' to not error if the build folder

# doesn't exist (the -f flag for rm also has this effect)

.PHONY: clean

clean:

 - rm -rf $(BUILD_FOLDER)

ログイン後にコピー

$ V=1 make

make 提案

Make を最大限に活用するための提案のリスト:

target 通常は実際のファイルである必要があります。サブ MAKE コマンドを発行するときは、常に (MAKE) を使用してください。 .phony ターゲットの使用は避けてください。ルールによってファイル アーティファクトが生成される場合は、それらを偽装するのではなく、それらをターゲットにすることを検討してください! 暗黙的なルールの使用は避けるようにしてください。 C ファイルの場合は、トレースを自動的に含めるために .d を使用してください! メタプログラミングは注意して使用してください。ルールで自動変数を使用します。ルールと Make のパスが正確に同じになるように、レシピ出力パスとして常に @ を使用するようにしてください。特に複雑な動作や微妙な構文が使用されている場合は、メイクファイル内でコメントを積極的に使用してください。あなたの同僚(そして将来の自分)はあなたに感謝するでしょう。 -j または -l オプションを使用して Make を並行して実行します! ルールの完了を追跡するために touch コマンドを使用することは避けてください。

#Others

オープン ソース プロジェクトで automake が使用されている可能性もあります (./configure スクリプトを探してください)。これは Makefile を生成するための関連ツールであり、一見の価値があります (特に広範囲に移植する必要がある C ソフトウェアを作成している場合)。

今日、GNU Make には多くの競合他社が存在します。皆さんにはそれらを研究することをお勧めします。いくつかの例:

CMake は非常に人気があり (Zephyr プロジェクトで使用されています)、一見の価値があります。ツリー外のビルドが非常に簡単になります。Bazel は宣言構文を使用します (Make の命令型アプローチに対して)。Meson は cmake のようなメタビルダーですが、デフォルトでバックエンドとして Ninja を使用し、非常に高速です。

関連する推奨事項: 「Linux ビデオ チュートリアル

以上がLinuxのgmakeとは何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Apacheを始める方法 Apacheを始める方法 Apr 13, 2025 pm 01:06 PM

Apacheを開始する手順は次のとおりです。Apache(コマンド:sudo apt-get install apache2または公式Webサイトからダウンロード)をインストールします(linux:linux:sudo systemctl start apache2; windows:apache2.4 "serviceを右クリックして「開始」を右クリック) (オプション、Linux:Sudo SystemCtl

Apache80ポートが占有されている場合はどうすればよいですか Apache80ポートが占有されている場合はどうすればよいですか Apr 13, 2025 pm 01:24 PM

Apache 80ポートが占有されている場合、ソリューションは次のとおりです。ポートを占有するプロセスを見つけて閉じます。ファイアウォールの設定を確認して、Apacheがブロックされていないことを確認してください。上記の方法が機能しない場合は、Apacheを再構成して別のポートを使用してください。 Apacheサービスを再起動します。

DebianのNginx SSLパフォーマンスを監視する方法 DebianのNginx SSLパフォーマンスを監視する方法 Apr 12, 2025 pm 10:18 PM

この記事では、Debianシステム上のNginxサーバーのSSLパフォーマンスを効果的に監視する方法について説明します。 Nginxexporterを使用して、NginxステータスデータをPrometheusにエクスポートし、Grafanaを介して視覚的に表示します。ステップ1:NGINXの構成最初に、NGINX構成ファイルのSTUB_STATUSモジュールを有効にして、NGINXのステータス情報を取得する必要があります。 NGINX構成ファイルに次のスニペットを追加します(通常は/etc/nginx/nginx.confにあるか、そのインクルードファイルにあります):location/nginx_status {stub_status

Debianシステムでリサイクルビンをセットアップする方法 Debianシステムでリサイクルビンをセットアップする方法 Apr 12, 2025 pm 10:51 PM

この記事では、デビアンシステムでリサイクルビンを構成する2つの方法を紹介します:グラフィカルインターフェイスとコマンドライン。方法1:Nautilusグラフィカルインターフェイスを使用して、ファイルマネージャーを開きます。デスクトップまたはアプリケーションメニューでNautilusファイルマネージャー(通常は「ファイル」と呼ばれる)を見つけて起動します。リサイクルビンを見つけてください:左ナビゲーションバーのリサイクルビンフォルダーを探してください。見つからない場合は、「他の場所」または「コンピューター」をクリックして検索してみてください。リサイクルビンプロパティの構成:「リサイクルビン」を右クリックし、「プロパティ」を選択します。プロパティウィンドウで、次の設定を調整できます。最大サイズ:リサイクルビンで使用可能なディスクスペースを制限します。保持時間:リサイクルビンでファイルが自動的に削除される前に保存を設定します

Apacheサーバーを再起動する方法 Apacheサーバーを再起動する方法 Apr 13, 2025 pm 01:12 PM

Apacheサーバーを再起動するには、次の手順に従ってください。Linux/MacOS:sudo systemctl restart apache2を実行します。 Windows:Net Stop apache2.4を実行し、ネット開始apache2.4を実行します。 Netstat -A |を実行しますサーバーのステータスを確認するには、STR 80を見つけます。

Debian Readdirのパフォーマンスを最適化する方法 Debian Readdirのパフォーマンスを最適化する方法 Apr 13, 2025 am 08:48 AM

Debian Systemsでは、Directoryコンテンツを読み取るためにReadDirシステム呼び出しが使用されます。パフォーマンスが良くない場合は、次の最適化戦略を試してください。ディレクトリファイルの数を簡素化します。大きなディレクトリをできる限り複数の小さなディレクトリに分割し、Readdirコールごとに処理されたアイテムの数を減らします。ディレクトリコンテンツのキャッシュを有効にする:キャッシュメカニズムを構築し、定期的にキャッシュを更新するか、ディレクトリコンテンツが変更されたときに、頻繁な呼び出しをreaddirに削減します。メモリキャッシュ(memcachedやredisなど)またはローカルキャッシュ(ファイルやデータベースなど)を考慮することができます。効率的なデータ構造を採用する:ディレクトリトラバーサルを自分で実装する場合、より効率的なデータ構造(線形検索の代わりにハッシュテーブルなど)を選択してディレクトリ情報を保存およびアクセスする

ネットワーク監視におけるDebian Snifferの重要性 ネットワーク監視におけるDebian Snifferの重要性 Apr 12, 2025 pm 11:03 PM

検索結果は「DebiansNiffer」とネットワークモニタリングにおけるその特定のアプリケーションに直接言及するわけではありませんが、「Sniffer」はネットワークパケットキャプチャ分析ツールを指し、Debianシステムでのアプリケーションは他のLinux分布と本質的に違いはありません。ネットワークの監視は、ネットワークの安定性を維持し、パフォーマンスを最適化するために重要であり、パケットキャプチャ分析ツールが重要な役割を果たします。以下は、ネットワーク監視ツールの重要な役割(Debianシステムで実行されるSnifferなど)を説明しています。ネットワーク監視ツールの価値:高速障害場所:帯域幅の使用状況、遅延、パケット損失率など、ネットワーク障害の根本原因を迅速に特定し、トラブルシューティング時間を短縮できるようなネットワークメトリックのリアルタイム監視。

Debian syslogを学ぶ方法 Debian syslogを学ぶ方法 Apr 13, 2025 am 11:51 AM

このガイドでは、Debian SystemsでSyslogの使用方法を学ぶように導きます。 Syslogは、ロギングシステムとアプリケーションログメッセージのLinuxシステムの重要なサービスです。管理者がシステムアクティビティを監視および分析して、問題を迅速に特定および解決するのに役立ちます。 1. syslogの基本的な知識Syslogのコア関数には以下が含まれます。複数のログ出力形式とターゲットの場所(ファイルやネットワークなど)をサポートします。リアルタイムのログ表示およびフィルタリング機能を提供します。 2。syslog(rsyslogを使用)をインストールして構成するDebianシステムは、デフォルトでrsyslogを使用します。次のコマンドでインストールできます:sudoaptupdatesud

See all articles