Sous Linux, gmake est GUN make, qui est un programme populaire et couramment utilisé pour créer des logiciels en langage C. Il est utilisé pour créer le noyau Linux et d'autres programmes et bibliothèques de logiciels GNU/Linux couramment utilisés. GNU Make est un programme qui peut automatiser les commandes shell et aider à effectuer des tâches répétitives ; il est souvent utilisé pour convertir des fichiers sous d'autres formes, comme la compilation de fichiers de code source dans des programmes ou des bibliothèques.
L'environnement d'exploitation de ce tutoriel : système linux7.3, ordinateur Dell G3.
gmake est GUN make, car sur les plateformes autres que Linux, make est généralement occupé, donc GUN make doit s'appeler gmake.
GNU Make est un programme populaire et couramment utilisé pour créer des logiciels en langage C. Utilisé pour construire le noyau Linux et d'autres programmes et bibliothèques de logiciels GNU/Linux couramment utilisés.
La plupart des développeurs de logiciels embarqués utiliseront GNU Make à un moment donné de leur carrière, soit pour compiler de petites bibliothèques, soit pour créer des projets entiers. Bien qu'il existe de très nombreuses alternatives à Make, il est encore souvent choisi comme système de construction de nouveaux logiciels en raison de son ensemble de fonctionnalités et de son large support.
Cet article explique les concepts généraux et les fonctionnalités de GNU Make et comprend des conseils sur la façon de tirer le meilleur parti de vos builds Make ! Il s'agit d'une brève introduction à mes concepts et fonctionnalités Make préférés/les plus couramment utilisés
Quoi. qu'est-ce que GNU Make ?
GNU Make est un programme qui peut automatiser les commandes shell et aider à effectuer des tâches répétitives. Il est souvent utilisé pour convertir des fichiers sous d'autres formes, par exemple pour compiler des fichiers de code source dans des programmes ou des bibliothèques.
Il le fait en suivant les prérequis et en exécutant une hiérarchie de commandes pour générer des cibles.
Bien que le manuel de GNU Make soit assez long, je recommande de le lire car c'est la meilleure référence que j'ai trouvée : https://www.gnu.org/software/make/manual/html_node/index.html
Quand choisir Make
Make convient à la construction de petits projets ou bibliothèques C/c++ qui seront inclus dans le système de construction d'un autre projet. La plupart des systèmes de build disposent d'un moyen d'intégrer des sous-projets basés sur make.
Pour les projets plus importants, vous trouverez des systèmes de construction plus modernes et plus faciles à utiliser.
Je recommande d'utiliser un système de build non-Make dans les situations suivantes :
Lorsque le nombre de cibles (ou de fichiers) en cours de construction est (ou sera éventuellement) des centaines. Une étape de « configuration » est requise, qui définit et enregistre les variables, les définitions de cibles et la configuration de l'environnement. Le projet restera interne ou privé et n'aura pas besoin d'être construit par les utilisateurs finaux. Vous constaterez peut-être que le débogage peut être une entreprise frustrante. Ce que vous devez créer est multiplateforme et peut être construit sur macOS, Linux et Windows. Dans ces cas, vous constaterez peut-être que l’utilisation de CMake, Bazel, Meson ou d’autres systèmes de construction modernes est une expérience plus agréable.
Appeler Make
L'exécution de make chargera un fichier appelé Makefile à partir du répertoire actuel et tentera de mettre à jour les cibles par défaut (plus d'informations sur les cibles plus tard).
Make recherchera les fichiers nommés GNUmakefile, makefile et makefile dans l'ordre
Vous pouvez spécifier un makefile spécifique en utilisant le paramètre -f/ --file :
$ make -f foo.mk Vous pouvez spécifier n'importe quel nombre de cibles, Listez-les comme arguments de position :
#Typical Target $ make clean all Vous pouvez transmettre le répertoire Make avec l'argument -C et il exécutera Make comme s'il avait été cd dans ce répertoire en premier lieu.
$ make -C some/sub/directory Fait amusant : git peut également être exécuté avec -C pour obtenir le même effet
Appels parallèles
Si l'option -j ou -l est fournie, Make ! peut exécuter des tâches en parallèle. Une ligne directrice m'a été dite est de définir la limite de travail à 1,5 fois le nombre de cœurs de processeur :
#une machine avec 4 cœurs : make -j make -j Fait intéressant, j'ai trouvé qu'en utilisant l'option -l "load Limit" a une utilisation du processeur légèrement meilleure que l'utilisation de l'option -j "job". YMMV cependant !
Il existe plusieurs façons de trouver le nombre de processeurs de la machine actuelle par programme. Un moyen simple consiste à utiliser la fonction python multiprocessing.cpu_count() pour obtenir le nombre de threads pris en charge par le système (notez qu'avec les systèmes hyper-threadés, cela consommera beaucoup de ressources informatiques, mais peut être préférable que de laisser le système générer du travail illimité).
#Appelez la fonction cpu_count() de python dans un sous-shell make -l (python -c "import multiprocessing;print (multiprocessing.cpu_count())")
Sortie lors d'appels parallèles
Si Make est En exécutant des commandes en parallèle qui ont beaucoup de sortie, vous pouvez voir la sortie échelonnée sur la sortie standard. Pour résoudre ce problème, Make dispose d'une option - output -sync.
Je recommande d'utiliser --output-sync=recurse, qui imprimera l'intégralité du résultat de la recette lorsque chaque objectif est atteint sans perturber le résultat des autres recettes.
Si la recette utilise un Make récursif, elle affichera également la sortie de l'intégralité du Make récursif.
Anatomie de Makefile Makefile contient des règles pour générer des cibles. Certains composants de base d'un Makefile sont présentés ci-dessous :
#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
Examinons chaque partie de l'exemple ci-dessus.
Variables
Les variables utilisent la syntaxe $(FOO), où FOO est le nom de la variable.
Les variables contiennent des chaînes simples car Make n'a pas d'autres types de données. L'ajout à une variable ajoutera un espace et un nouveau contenu :
FOO = one FOO += two # FOO is now "one two" FOO = one FOO = $(FOO)two # FOO is now "onetwo"
Assignation de variable
Dans la syntaxe GNU Make, les variables sont affectées de deux manières :
L'expression de droite est une affectation littérale Pour les variables - cela ressemble beaucoup à une macro en C/c++, qui évalue une expression lors de l'utilisation d'une variable :
FOO = 1 BAR = $(FOO) FOO = 2 # prints BAR=2 $(info BAR=$(BAR))
assigne le résultat d'une expression à une variable ; l'expression est développée lors de l'affectation :
FOO = 1 BAR := $(FOO) FOO = 2 # prints BAR=1 $(info BAR=$(BAR))
Note : La fonction $(info…) ci-dessus est utilisée pour imprimer des expressions, ce qui est très pratique lors du débogage de makefiles ! *'
Les variables qui ne sont pas définies explicitement, implicitement ou automatiquement seront évaluées comme une chaîne vide.
Variables d'environnement
Les variables d'environnement sont transportées dans l'environnement d'exécution Make. Prenons comme exemple le makefile suivant :
$(info YOLO variable = $(YOLO))
Si nous définissons la variable YOLO dans la commande shell lors de l'exécution de make, nous définirons cette valeur :
$ YOLO="hello there!" make YOLO variable = hello there! make: *** No targets. Stop.
Remarque : Make imprime une erreur "Aucune cible" car nous Le makefile n'a pas de cible répertoriée !
Si vous utilisez la syntaxe d'affectation ?=, Make n'attribuera une valeur que si la variable n'a pas de valeur :
Makefile:
#默认CC为gcc CC ? = gcc
Ensuite, nous pouvons remplacer $(CC) dans le fichier. makefile :
$ CC=clang make
$ CC=clang make
另一个常见的模式是允许插入额外的标志。在makefile中,我们将追加变量而不是直接赋值给它。
CFLAGS += -Wall
Un autre modèle courant consiste à autoriser l'insertion d'indicateurs supplémentaires. Dans le makefile, nous ajouterons la variable au lieu de l'attribuer directement.
CFLAGS += -Wall
$ CFLAGS='-Werror=conversion -Werror=double-promotion' make
Les variables les plus importantes
Une catégorie spéciale de variables utilisées est appelée variables de substitution. L'utilisation de cette option de ligne de commande remplacera les valeurs définies dans l'environnement ou dans le Makefile ! recette Disponible en contexte. Ils fonctionnent également avec n'importe quelle recette incontournable ! Quelques exemples courants :# any value set elsewhere YOLO = "not overridden" $(info $(YOLO))
Ce sont des variables spéciales définies par Make et sont disponibles dans le contexte de la recette. Ils sont utiles pour éviter les noms en double (Ne vous répétez pas). Quelques variables automatiques courantes :
# 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.
target est le côté gauche de la syntaxe de la règle :
# 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将使用makefile中指定的第一个目标,称为“默认目标”(如果需要,也可以覆盖默认目标)。 虚假phony目标 有时候设置元目标是很有用的,比如all, clean, test等等。在这些情况下,您不希望Make检查名为all/clean等的文件。 Make提供.PHONY目标语法,将目标标记为不指向文件: 假设我们的项目构建了一个程序和一个库foo和foo.a;如果我们想要 在默认情况下,我们可以创建一个'all'规则来构建两者 .PHONY:all all : foo foo.a 如果你有多个假目标,一个好的模式可能是将每个目标都附加到定义它的.PHONY中: 请注意! !. phony目标总是被认为是过期的,因此Make将总是运行这些目标的配方(因此也运行任何具有. phony先决条件的目标!)小心使用! ! 隐式规则 隐含规则由Make提供。我发现使用它们会让人感到困惑,因为在幕后发生了太多的行为。你偶尔会在野外遇到它们,所以要小心。 模式的规则 模式规则允许你编写一个通用规则,通过模式匹配应用于多个目标: or 先决条件 如上所述,Make将在运行规则之前检查这些目标。它们可以是文件或其他目标。 如果任何先决条件比目标更新(修改时间),Make将运行目标规则。 在C项目中,你可能有一个将C文件转换为目标文件的规则,如果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/ 基本形式可能是: Order-only 先决条件 这些先决条件只有在不存在的情况下才会构建;如果它们比目标更新,则不会触发目标重新构建。 典型的用法是为输出文件创建一个目录;将文件发送到目录将更新其mtime属性,但我们不希望由此触发重新构建。 recipe “recipe”是创建目标时要执行的shell命令列表。它们被传递到子shell中(默认为/bin/sh)。如果target在recipe运行后更新,则认为规则是成功的(但如果没有更新,则不视为错误)。 如果配方中的任何一行返回非零退出代码,Make将终止并打印一条错误消息。你可以通过前缀-字符来告诉Make忽略非零退出码: 在recipe行前面加上@将禁止在执行之前echo该行: Make会在运行recipe上下文中展开变量/函数表达式,但不会处理它。如果你想访问shell变量,请使用$: function Make函数的调用语法如下: $(function-name arguments) 其中arguments是用逗号分隔的参数列表。 For example: 用户定义函数 shell函数 你可以让Make调用一个shell表达式并捕获结果: TODAYS_DATE=$(shell date --iso-8601) 不过,我在使用这个功能时很谨慎;它会增加对你使用的任何程序的依赖,所以如果你正在调用更奇特的程序,确保你的构建环境是受控的(例如在容器中或使用Conda)。 make的条件表达式 make include sources.mk: SOURCE_FILES := Makefile: include sources.mk OBJECT_FILES = $(SOURCE_FILES:.c=.o) %.o: %.c (CC) -c ^ -o $@ make eval 请注意,使用Make的这个特性的方法可能会让人很困惑,添加一些有用的注释来解释意图是什么,对您未来的自己会很有用! VPATH VPATH是一个特殊的Make变量,它包含Make在查找先决条件和目标时应该搜索的目录列表。 它可以用来将对象文件或其他派生文件发送到./build目录中,而不是把src目录弄得乱七八糟: touch file 调试makefile 对于小问题,我通常使用printf的Make等效函数,即$(info/warning/error)函数,例如当检查不工作的条件路径时: 要调试为什么规则在不应该运行的情况下运行(或者相反),可以使用——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 $ V=1 make make recommendation Liste de suggestions pour tirer le meilleur parti de Make: target devrait généralement être un vrai fichier. Lorsque vous émettez des commandes sous-MAKE, utilisez toujours (MAKE). Essayez d'éviter d'utiliser des cibles .phony. Si la règle génère des artefacts de fichiers, envisagez de les cibler au lieu de usurper leur identité. Essayez d'éviter d'utiliser des règles implicites ! Pour les fichiers C, assurez-vous d'utiliser .d pour inclure automatiquement le traçage. Utilisez la métaprogrammation avec précaution ! Utilisez des variables automatiques dans les règles. Essayez toujours d'utiliser @ comme chemin de sortie de la recette afin que vos règles et les chemins de Make soient exactement les mêmes. Utilisez généreusement les commentaires dans les makefiles, en particulier lorsqu'un comportement complexe ou une syntaxe subtile est utilisé. Vos collègues (et votre futur moi) vous remercieront. Exécutez Make en parallèle en utilisant l'option -j ou -l ! Essayez d'éviter d'utiliser la commande touch pour suivre l'achèvement des règles Autres Vous pouvez également rencontrer automake dans des projets open source (recherchez le ./configure). scénario). Il s'agit d'un outil connexe pour générer des makefiles et mérite le détour (surtout si vous écrivez un logiciel C qui doit être largement porté). Il existe aujourd'hui de nombreux concurrents à GNU Make et j'encourage tout le monde à les rechercher. Quelques exemples : CMake est très populaire (le projet Zephyr l'utilise) et mérite le détour. Cela rend la construction hors arbre très facile. Bazel utilise une syntaxe déclarative (par rapport à l'approche impérative de Make). Meson est un méta-constructeur comme cmake mais utilise Ninja comme backend par défaut et peut être très rapide Recommandations associées : "Linux Tutoriel vidéo"$(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
# 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
# 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
# Note the use of the '$<' automatic variable, specifying the first
# prerequisite, which is the .c file
%.o: %.c
$(CC) -c $< -o $@
OBJ_FILES = foo.o bar.o
# Use CC to link foo.o + bar.o into 'program'. Note the use of the '$^'
# automatic variable, specifying ALL the prerequisites (all the OBJ_FILES)
# should be part of the link command
program: $(OBJ_FILES)
$(CC) -o $@ $^
foo.o: foo.c
# use automatic variables for the input and output file names
$(CC) $^ -c $@
# these are the compiler flags for emitting the dependency tracking file. Note
# the usage of the '$<' 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
# '-' to prevent an error if any of the files do not exist
-include $(wildcard *.d)
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 $@
foo.txt:
# a simple recipe
echo HEYO > $@
.PHONY: clean
clean:
# we don't care if rm fails
-rm -r ./build
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!
USER = linus
print-user:
# print out the shell variable $USER
echo $$USER
# print out the make variable USER
echo $(USER)
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)
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)
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
bar.c
foo.c \# 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)))
# 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 $@
# 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 $@
ifeq ($(CC),clang)
$(error whoops, clang not supported!)
endif
# 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)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!