table des matières
1. Qu'est-ce que Makefile
Il y a longtemps, les gens n'utilisaient pas Makefile pour produire un programme, ils ne pouvaient taper des commandes que manuellement.
Au début, le programme était très petit, avec un seul fichier, il suffit de taper dans le shell:
gcc main.c -o main
Plus tard, le programme est devenu de plus en plus gros, il y avait beaucoup de fichiers, vous devez taper ceci:
gcc main.c 1.c 2.c 3.c ... ... ... -o main
Chaque fois que vous modifiez un fichier, vous devez recompiler tous les fichiers. Cela prend beaucoup de temps et l'efficacité de la compilation est très faible.
Existe-t-il un moyen d'augmenter l'efficacité?
gcc -c main.c 1.c 2.c 3.c ... ... ... 分别生成 所有的.o文件;
gcc main.o 1.o 2.o 3.o ... ... ... -o main 再把生成的.o文件链接成目标文件main;
Si vous modifiez 1.c, il vous suffit de
gcc -c 1.c 生成 1.o 文件;
gcc main.o 1.o 2.o 3.o ... ... ... -o main
Ensuite, liez les fichiers 1.o nouvellement générés et les autres fichiers .o précédemment générés dans le fichier cible principal
L'efficacité de la compilation est améliorée par quelle compilation et laquelle est modifiée. Cependant, taper des commandes suffit. Si vous modifiez beaucoup de fichiers, vous devez vous rappeler ceux que vous avez modifiés. Si vous compilez un projet relativement volumineux, vous devrez simplement taper des commandes. J'ai eu des crampes, alors ça a vu le jour.
Mécanisme de Make: Le mécanisme de make est similaire à "quelle édition qui". Make vérifiera automatiquement l'heure de dernière modification du fichier source .c et le fichier correspondant .o. Si l'heure de dernière modification d'un fichier source .c est supérieure au fichier correspondant .o doit être nouveau, indiquant que ce fichier a été modifié et doit être recompilé, make compilera automatiquement le fichier correspondant, puis liera le nouveau fichier correspondant .o généré par la nouvelle compilation avec le fichier .o précédemment généré Fichier cible xxxx.
Alors, comment savoir quels fichiers je veux compiler? Est-ce pour ne compiler que 1.c 2.c? Ou compiler tout? Ou autre chose?
Cela dépend du Makefile. Make est un chef, et le Makefile est la recette. La recette comprend le nom du plat, les matières premières et les méthodes de traitement.
2. Qu'est-ce que Makefile
Supposons que nous ayons trois fichiers source.
hellomake.c | hellofunc.c | hellomake.h |
---|---|---|
“#Include <hellomake.h> int main () {// appelle une fonction dans un autre fichier myPrintHelloMake (); retour (0); } " | "#Include <stdio.h> #include <hellomake.h> void myPrintHelloMake (void) {printf (" "Hello makefiles! \ N" "); return;}" | "/ * Example include file * / void myPrintHelloMake (void);" |
Si nous utilisons la ligne de commande pour compiler, c'est comme ça
gcc -o hellomake hellomake.c hellofunc.c
Si vous écrivez un makefile simple, c'est le cas, le nom du fichier est enregistré sous Makefile.
hellomake: hellomake.c hellofunc.c
gcc -o hellomake hellomake.c hellofunc.c
Exigences de format de base:
target ... : prerequisites ...
command
....
....
target :
Le fichier cible peut être un fichier objet, un fichier exécutable ou une étiquette;
prerequisites:
Générer des fichiers ou des cibles requis par la cible;
command:
La commande qui doit être exécutée peut être n'importe quelle commande shell.
Dans l'environnement shell Linux, entrez directement make, et un fichier nommé "Makefile" ou "makefile" sera trouvé dans le répertoire courant. S'il est trouvé, il utilisera la première cible du fichier comme fichier cible final.
Nous savons qu'après l'écriture d'un fichier programme, le processus de compilation suivant est ( .c .S) -> ( .o .a) -> ( .bin), mais le processus d'analyse de Makefile par l'outil make est inversé. Afin de générer ( .bin) besoin de s'appuyer sur (* .o .a), afin de générer ( .o .a) indirects et besoins ( .c .S), on peut dire que ( .c * .S) dépend de l'original.
3. La déclaration et l'affectation des variables Makefile.
PS:Makefile里所有变量都是字符串
变量的声明,方法有:
=、?=、:=、+=、
define endef
变量的使用方法:$(var)
=、?=、define
Variable de retard, la valeur n'est déterminée que lorsqu'elle est utilisée
:=
Variable immédiate, la valeur est déterminée lorsqu'elle est définie
+=
Regarde devant, le front c'est le delay c'est le delay, le front c'est l'immédiat c'est l'immédiat
var1=abc
var2=$(var1)def
var1=ghi
echo $(var2)
输出 ghidef
=、?=、define是延时变量,所以,在 echo $(var2) 时,才确定 var2的值是 $(var1)def,var1的值是 ghi
var1=abc
var2:=$(var1)def
var1=ghi
echo $(var2)
输出 abcdef
:= 是立即变量,所以,在var2:=$(var1)def 时,就已经确定了var2的值是 abcdef
?=只有在变量第一次赋值的时候有效,也就是说,如果前面变量没被赋值,就赋值,如果有赋值,则不执行赋值,跳过。
var1?=abc 或者 var1=abc 或者 var1:=abc
var1?=def
echo $(var1)
输出 abc
var1?=def
echo $(var1)
输出 def
+=字符串连接,在原有的字符串上加上后续内容,不过中间会有空格喔,呵呵哒
var1=abc
var1+=def
echo $(var1)
输出 abc def
4. La structure de Makefile
Prenons d'abord un exemple: si nous avons un fichier exécutable nommé edit, cela dépend de 8 fichiers objets, qui à leur tour dépendent de 8 fichiers c et de 3 fichiers d'en-tête.
edit : main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
//每一个目标文件的依赖关系
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
Nous shell en ligne de commande make
pour exécuter ce makefile,
si l'entrée make clean
exécutée simultanément le fichier exécutable éditera et supprimera tous les fichiers objets.
Si un fichier est écrit de cette manière, c'est évidemment trop compliqué et trop long, on peut le simplifier au moyen de définitions de variables.
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
$(objects) : defs.h
kbd.o command.o files.o : command.h
display.o insert.o search.o files.o : buffer.h
//这里类似伪代码,指明clean并不是一个文件,而是一个执行语句的缩写
.PHONY : clean
clean :
rm edit $(objects)
5. Caractères génériques dans Makefile
Pour faciliter l'écriture, makefile prend en charge de nombreuses syntaxes génériques, telles que
CC=gcc
CFLAGS=-I.
DEPS = hellomake.h
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake: hellomake.o hellofunc.o
$(CC) -o hellomake hellomake.o hellofunc.o
% .o:% .c $ (DEPS) Cette phrase définit une règle, ce qui signifie que tous les .c
fichiers qui dépendent de hellomake.h sont compilés pour générer des .o
fichiers.
% Est appelé ici un caractère générique.
On peut aussi voir ce joker
out.o: src.c src.h
$@
signifie "out.o" (cible)
$<
signifie "src.c" (premier prérequis)
$^
signifie "src.c src.h" (tous les prérequis)
Par exemple:
CC=gcc
CFLAGS=-I.
DEPS = hellomake.h
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
Cela signifie utiliser le fichier compilé du premier fichier .c comme fichier cible.
-I
Moyens d'opérer sous le chemin actuel.
6. Fonctions couramment utilisées de Makefile.
Fonctions de remplacement et d'analyse des chaînes:
$ ( subst
de, à, texte)
Remplacez de par à dans le texte.
echo $ (sous-ee, EE, faible dans la rue!) 输出 fEEet sur la rue!
$ ( patsubst
motif, répétition, texte)
Trouvez un mot qui correspond au format du motif dans le texte et remplacez-le par repace.
$ (patsubst% .c,%. o, aa.cc bb.c) sortie aa.co bb.o
$ ( strip
string) supprime le début et la fin, et compresse plusieurs espaces entre les deux en un
$ (strip je suis un homme riche !!) 输出 Je suis un homme riche !!
$ ( findstring
find, string) Recherche de find dans la chaîne, retourne find s'il n'y en a pas, retourne vide si non
$ (findstring homme riche, je suis un homme riche !!) 输出 homme riche
$ ( filter
pat ..., text) renvoie les mots qui "correspondent à pat ..." séparés par des espaces dans le texte, et supprime les mots sans correspondance.
$ (filtre% h% n, je suis un homme riche) 输出 homme riche
$ (filter-out pat ..., text) renvoie les mots qui "correspondent à pat ..." séparés par des espaces dans le texte, et supprime les mots sans correspondance.
$ (filtrage% h% n, je suis un homme riche) 输出 Je suis un
$ ( sort
liste…) Supprimez les mots répétés séparés par des espaces dans la liste… et triez-les par ordre alphabétique, avec les symboles d'abord, puis les chiffres, puis les lettres, sensible à la casse
$ (sorte 1. Je suis un homme riche! homme Un homme riche) 输出! homme 1. Je suis un homme un homme riche
Fonction de nom de fichier:
$ ( dir
dirs…) extrait la partie répertoire de chaque partie, le répertoire commence du premier caractère du nom de fichier au dernier caractère / fin
$ (dir /mnt/src.c hack / ddr / aab.a kko.c) sortie / mnt / hack / ddr / ./
Le répertoire de /mnt/src.c est / mnt /
Le répertoire de hack / ddr / aab.a est hack / ddr /
Le répertoire de kko.c est ./
$ ( notdir
names…) extraire le nom du fichier
$ (notdir /mnt/src.c hack / ddr / aab.a kko.c) sortie src.c aab.a kko.c
$ (suffixes…) extraire le suffixe du nom du fichier
$ ( suffix
/mnt/src.c hack / ddr / aab.a kko.d rich-man) output.c .a .d
$ ( basename
noms…) extrait d'autres caractères sauf le suffixe
$ (basename /mnt/src.c hack / ddr / aab.a kko.d rich-man) 输出 / mnt / src hack / ddr / aab kko rich-man
$ ( addsuffix
suffixe, nom…) plus le suffixe du nom de fichier
$ (adduffix .c, 1413 1314 rich-man) renvoie 1413.c 1314.c rich-man.c
$ (addprefix prefix, names…) add prefix, tel que src /, hack.c bb.c output src / hack.c
$ ( addprefix
riche-, homme femme garçon fille) 输出 homme riche femme riche femme riche garçon riche fille riche
$ ( wildcard
* .c) renvoie le fichier .c dans le dossier courant, sortie 1.c 2.c main.c
Autres fonctions:
$ ( foreach
var, list, text) développe list et var, puis affecte chaque liste à var et le texte fait référence à var pour développer.
dirs: = abcde
fichiers: = $ (pour chaque tmp, $ (dirs), $ (tmp) .txt)
echo $ (fichiers)
输出 : a.txt b.txt c.txt d.txt e.txt
dir première expansion = a, tmp = a
dir deuxième expansion = b, tmp = b
…………
最后 tmp.txt 就是 a.txt b.txt c.txt d.txt e.txt
$ ( if
condition, alors, sinon)
Développez d'abord la condition, si elle n'est pas vide, exécutez puis, si elle est vide, exécutez autrement.
fichier: = abcd
$ (if $ (file), havefile, nothavefile) 返回 havefile
#fichier: =
$ (if $ (file), havefile, nothavefile) 返回 nothavefile