Was ist gmake unter Linux?

青灯夜游
Freigeben: 2022-11-09 19:04:41
Original
3061 Leute haben es durchsucht

Unter Linux ist gmake GUN make, ein beliebtes und häufig verwendetes Programm zum Erstellen von C-Sprachsoftware. Es wird zum Erstellen des Linux-Kernels und anderer häufig verwendeter GNU/Linux-Programme und Softwarebibliotheken verwendet. GNU Make ist ein Programm, das Shell-Befehle automatisieren und bei der Ausführung wiederkehrender Aufgaben helfen kann. Es wird häufig zum Konvertieren von Dateien in andere Formen verwendet, beispielsweise zum Kompilieren von Quellcodedateien in Programme oder Bibliotheken.

Was ist gmake unter Linux?

Die Betriebsumgebung dieses Tutorials: Linux7.3-System, Dell G3-Computer.

gmake ist GUN make, da make auf anderen Plattformen als Linux normalerweise belegt ist, sodass GUN make gmake heißen muss.

GNU Make ist ein beliebtes und häufig verwendetes Programm zum Erstellen von C-Sprachsoftware. Wird zum Erstellen des Linux-Kernels und anderer häufig verwendeter GNU/Linux-Programme und Softwarebibliotheken verwendet.

Die meisten Entwickler eingebetteter Software werden GNU Make irgendwann in ihrer Karriere verwenden, entweder zum Kompilieren kleiner Bibliotheken oder zum Erstellen ganzer Projekte. Obwohl es viele, viele Alternativen zu Make gibt, wird es aufgrund seines Funktionsumfangs und seiner breiten Unterstützung immer noch häufig als Build-System für neue Software gewählt.

Dieser Artikel erklärt die allgemeinen Konzepte und Funktionen von GNU Make und enthält Ratschläge, wie Sie Ihre Make-Builds optimal nutzen können. Dies ist eine kurze Einführung in meine bevorzugten/am häufigsten verwendeten Make-Konzepte und -Funktionen ist GNU Make?

GNU Make ist ein Programm, das Shell-Befehle automatisieren und bei der Ausführung sich wiederholender Aufgaben helfen kann. Es wird häufig zum Konvertieren von Dateien in andere Formen verwendet, beispielsweise zum Kompilieren von Quellcodedateien in Programme oder Bibliotheken. Dies geschieht durch die Verfolgung der Voraussetzungen und die Ausführung einer Hierarchie von Befehlen zur Generierung von Zielen.

Obwohl das GNU Make-Handbuch ziemlich lang ist, empfehle ich, es zu lesen, da es die beste Referenz ist, die ich gefunden habe: https://www.gnu.org/software/make/manual/html_node/index.html

Wann Sie sich für Make entscheiden sollten

Make eignet sich zum Erstellen kleiner C/C++-Projekte oder Bibliotheken, die in das Build-System eines anderen Projekts eingebunden werden. Die meisten Build-Systeme verfügen über eine Möglichkeit, make-basierte Teilprojekte zu integrieren. Für größere Projekte werden Sie feststellen, dass modernere Build-Systeme einfacher zu verwenden sind.

Ich empfehle die Verwendung eines Nicht-Make-Build-Systems in den folgenden Situationen:

Wenn die Anzahl der zu erstellenden Ziele (oder Dateien) Hunderte beträgt (oder irgendwann betragen wird). Es ist ein „Konfigurieren“-Schritt erforderlich, der Variablen, Zieldefinitionen und Umgebungskonfiguration festlegt und speichert. Das Projekt bleibt intern oder privat und muss nicht von Endbenutzern erstellt werden. Möglicherweise stellen Sie fest, dass das Debuggen ein frustrierendes Unterfangen sein kann. Was Sie zum Erstellen benötigen, ist plattformübergreifend und kann auf macOS, Linux und Windows erstellt werden. In diesen Fällen ist die Verwendung von CMake, Bazel, Meson oder anderen modernen Build-Systemen möglicherweise eine angenehmere Erfahrung.

Make aufrufen

Wenn Sie make ausführen, wird eine Datei namens Makefile aus dem aktuellen Verzeichnis geladen und versucht, die Standardziele zu aktualisieren (mehr zu Zielen später). Make sucht der Reihe nach nach Dateien mit den Namen GNUmakefile, makefile und makefile.

Sie können ein bestimmtes Makefile mit dem Parameter -f/ --file angeben:

$ make -f foo.mk Sie können eine beliebige Anzahl von Zielen angeben. Listen Sie sie als Positionsargumente auf:

#Typisches Ziel $ make clean all Sie können das Make-Verzeichnis mit dem Argument -C übergeben und Make wird so ausgeführt, als ob es ursprünglich in dieses Verzeichnis kopiert worden wäre.

$ make -C some/sub/directory Lustige Tatsache: git kann auch mit -C ausgeführt werden, um den gleichen Effekt zu erzielen

Parallele Aufrufe

Wenn die Option -j oder -l bereitgestellt wird, Make kann Jobs parallel ausführen. Eine Richtlinie, die mir gesagt wurde, ist, das Joblimit auf das 1,5-fache der Anzahl der Prozessorkerne festzulegen: #eine Maschine mit 4 Kernen:

make -j

make -j Interessanterweise habe ich festgestellt, dass die Option -l „Lastlimit“ verwendet hat eine etwas bessere CPU-Auslastung als die Verwendung der Option -j „Job“. YMMV!

Es gibt mehrere Möglichkeiten, die CPU-Anzahl der aktuellen Maschine programmgesteuert zu ermitteln. Eine einfache Möglichkeit besteht darin, die Funktion python multiprocessing.cpu_count() zu verwenden, um die Anzahl der vom System unterstützten Threads abzurufen (beachten Sie, dass dies bei Hyper-Thread-Systemen viele Computerressourcen verbraucht, aber möglicherweise besser ist, als das System laufen zu lassen erzeugen unendliche Arbeit). #Rufen Sie die cpu_count()-Funktion von Python in einer Subshell auf

make -l

(python -c "import multiprocessing;print (multiprocessing.cpu_count())")

Ausgabe bei parallelen Aufrufen

Wenn Make ist Wenn Sie Befehle parallel ausführen, die eine große Ausgabemenge haben, kann es sein, dass die Ausgabe auf stdout gestaffelt ist. Um dieses Problem zu lösen, verfügt Make über die Option „output -sync“.

Ich empfehle die Verwendung von --output-sync=recurse, wodurch die gesamte Ausgabe des Rezepts gedruckt wird, wenn jedes Ziel erreicht ist, ohne die Ausgabe anderer Rezepte zu beeinträchtigen.

Wenn das Rezept rekursives Make verwendet, wird auch die Ausgabe des gesamten rekursiven Make zusammen ausgegeben.

Anatomie von Makefile Makefile enthält Regeln zum Generieren von Zielen. Einige grundlegende Komponenten eines Makefiles werden unten gezeigt:

#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
Nach dem Login kopieren

Schauen wir uns jeden Teil des obigen Beispiels an.

Variablen

Variablen verwenden die Syntax $(FOO), wobei FOO der Variablenname ist.

Variablen enthalten einfache Zeichenfolgen, da Make keine anderen Datentypen hat. Durch Anhängen an eine Variable werden ein Leerzeichen und neuer Inhalt hinzugefügt:

FOO = one
FOO += two
# FOO is now "one two"

FOO = one
FOO = $(FOO)two
# FOO is now "onetwo"
Nach dem Login kopieren

Variablenzuweisung

In der GNU Make-Syntax werden Variablen auf zwei Arten zugewiesen:

Der Ausdruck auf der rechten Seite ist eine wörtliche Zuweisung für Variablen – Dies ähnelt einem Makro in C/c++, das einen Ausdruck auswertet, wenn eine Variable verwendet wird:

FOO = 1
BAR = $(FOO)
FOO = 2
# prints BAR=2
$(info BAR=$(BAR))
Nach dem Login kopieren

weist das Ergebnis eines Ausdrucks einer Variablen zu; der Ausdruck wird während der Zuweisung erweitert:

FOO = 1
BAR := $(FOO)
FOO = 2
# prints BAR=1
$(info BAR=$(BAR))
Nach dem Login kopieren

Hinweis : Die obige Funktion $(info…) wird zum Drucken von Ausdrücken verwendet, was beim Debuggen von Makefiles sehr praktisch ist! *'

Variablen, die nicht explizit, implizit oder automatisch gesetzt sind, werden als leere Zeichenfolge ausgewertet.

Umgebungsvariablen

Umgebungsvariablen werden in die Make-Ausführungsumgebung übertragen. Nehmen Sie das folgende Makefile als Beispiel:

$(info YOLO variable = $(YOLO))
Nach dem Login kopieren

Wenn wir beim Ausführen von make die Variable YOLO im Shell-Befehl festlegen, legen wir diesen Wert fest:

$ YOLO="hello there!" make
YOLO variable = hello there!
make: *** No targets.  Stop.
Nach dem Login kopieren

Hinweis: Make gibt einen Fehler „Keine Ziele“ aus, weil wir Im Makefile ist kein Ziel aufgeführt!

Wenn Sie die Zuweisungssyntax ?= verwenden, weist Make nur dann einen Wert zu, wenn die Variable keinen Wert hat:

Makefile:

#默认CC为gcc
CC ? = gcc
Nach dem Login kopieren

Dann können wir $(CC) in überschreiben makefile :

$ CC=clang make$ CC=clang make

另一个常见的模式是允许插入额外的标志。在makefile中,我们将追加变量而不是直接赋值给它。

CFLAGS += -Wall

Ein weiteres gängiges Muster besteht darin, das Einfügen zusätzlicher Flags zu ermöglichen. Im Makefile hängen wir die Variable an, anstatt sie direkt zuzuweisen.

CFLAGS += -Wall

Dadurch können zusätzliche Flags aus der Umgebung übergeben werden:
$ CFLAGS='-Werror=conversion -Werror=double-promotion' make
Nach dem Login kopieren

Das ist sehr nützlich!

Die wichtigsten Variablen

Eine spezielle Kategorie der verwendeten Variablen wird als überschreibende Variablen bezeichnet. Die Verwendung dieser Befehlszeilenoption überschreibt die in der Umgebung oder im Makefile festgelegten Werte! Rezept Im Kontext verfügbar. Sie funktionieren auch mit jedem unverzichtbaren Rezept! Einige gängige Beispiele:

# any value set elsewhere
YOLO = "not overridden"
$(info $(YOLO))
Nach dem Login kopieren

Automatische Variablen

Dies sind spezielle Variablen, die von Make festgelegt werden und im Rezeptkontext verfügbar sind. Sie sind nützlich, um doppelte Namen zu vermeiden (Don't Repeat Yourself). Einige häufige automatische Variablen:

# 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.
Nach dem Login kopieren

target(target)

target ist die linke Seite der Regelsyntax:

# 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'
Nach dem Login kopieren

target ist fast immer eine benannte Datei. Dies liegt daran, dass Make den Zeitpunkt der letzten Änderung verwendet, um zu verfolgen, ob ein Ziel neuer oder älter als seine Voraussetzung ist und ob es neu erstellt werden muss.
Beim Aufruf von Make können Sie das Ziel angeben, das Sie erstellen möchten, indem Sie es als angeben Positionsargument:

$(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
Nach dem Login kopieren

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

虚假phony目标

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

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

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

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

# 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
Nach dem Login kopieren

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

隐式规则

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

# 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
Nach dem Login kopieren

模式的规则

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

# Note the use of the '$<&#39; automatic variable, specifying the first
# prerequisite, which is the .c file
%.o: %.c
 $(CC) -c $< -o $@
Nach dem Login kopieren

or

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 $@ $^
Nach dem Login kopieren

先决条件

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

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

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

foo.o: foo.c
 # use automatic variables for the input and output file names
 $(CC) $^ -c $@
Nach dem Login kopieren

自动的先决条件

对于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/

基本形式可能是:

# 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)
Nach dem Login kopieren

Order-only 先决条件

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

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

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 $@
Nach dem Login kopieren

recipe

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

foo.txt:
 # a simple recipe
 echo HEYO > $@
Nach dem Login kopieren

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

.PHONY: clean
clean:
 # we don't care if rm fails
 -rm -r ./build
Nach dem Login kopieren

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

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!
Nach dem Login kopieren

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

USER = linus

print-user:
 # print out the shell variable $USER
 echo $$USER

 # print out the make variable USER
 echo $(USER)
Nach dem Login kopieren

function

Make函数的调用语法如下:

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

For example:

FILES=$(wildcard *.c)

# you can combine function calls; here we strip the suffix off of $(FILES) with
# the $(basename) function, 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)
Nach dem Login kopieren

用户定义函数

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)
Nach dem Login kopieren

shell函数

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

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

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

make的条件表达式

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
Nach dem Login kopieren

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

# 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)))
Nach dem Login kopieren

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

VPATH

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

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

# 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 $@
Nach dem Login kopieren

touch file

# 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 $@
Nach dem Login kopieren

调试makefile

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

ifeq ($(CC),clang)
$(error whoops, clang not supported!)
endif
Nach dem Login kopieren

要调试为什么规则在不应该运行的情况下运行(或者相反),可以使用——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

# 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)
Nach dem Login kopieren

$ V=1 make

make-Vorschläge

Eine Liste mit Vorschlägen, wie Sie Make:

target optimal nutzen können. Das Ziel sollte normalerweise eine echte Datei sein. Verwenden Sie beim Ausgeben von Sub-MAKE-Befehlen immer (MAKE). Vermeiden Sie die Verwendung von .phony-Zielen. Wenn die Regel Dateiartefakte generiert, sollten Sie diese gezielt ansprechen, anstatt sich als solche auszugeben. Vermeiden Sie die Verwendung impliziter Regeln. Stellen Sie bei C-Dateien sicher, dass Sie .d verwenden, um die Ablaufverfolgung automatisch einzuschließen! Verwenden Sie automatische Variablen in Regeln. Versuchen Sie immer, @ als Rezeptausgabepfad zu verwenden, damit Ihre Regeln und Make-Pfade genau gleich sind. Verwenden Sie Kommentare in Makefiles großzügig, insbesondere wenn komplexes Verhalten oder subtile Syntax verwendet wird. Ihre Kollegen (und Ihr zukünftiges Ich) werden es Ihnen danken. Führen Sie Make parallel mit der Option -j oder -l aus! Vermeiden Sie die Verwendung des Touch-Befehls zum Verfolgen der Regelvervollständigung Skript). Dies ist ein verwandtes Tool zum Generieren von Makefiles und einen Blick wert (insbesondere, wenn Sie C-Software schreiben, die umfassend portiert werden muss).

Es gibt heute viele Konkurrenten zu GNU Make und ich ermutige jeden, sich darüber zu informieren. Einige Beispiele: CMake ist sehr beliebt (das Zephyr-Projekt verwendet es) und einen Blick wert. Es macht das Out-of-Tree-Building sehr einfach. Bazel verwendet deklarative Syntax (im Gegensatz zum imperativen Ansatz von Make). Meson ist ein Meta-Builder wie cmake, verwendet jedoch standardmäßig Ninja als Backend und kann sehr schnell seinVerwandte Empfehlungen: „

Linux Video-Tutorial

"

Das obige ist der detaillierte Inhalt vonWas ist gmake unter Linux?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage