Déboguer un makefile est un peu de la magie noire. Malheureusement, il n'existe pas de débogueur de makefile pour examiner la progression d'une règle particulière ou comment une variable est développée. La plupart du débogage peut être effectué avec des impressions régulières et en vérifiant le makefile . Bien sûr, GNU make aide un peu avec ses méthodes intégrées et ses options de ligne de commande. Une des meilleures techniques pour déboguer les makefiles est d'ajouter des hooks de débogage et d'utiliser des techniques de programmation sûres sur lesquelles s'appuyer en cas de problème. Voici quelques techniques de débogage de base et pratiques de codage sécurisées qui, à mon avis, seront les plus utiles.
Débogage des capacités de make
Une fonction très utile pour déboguer un makefile qui ne fonctionne pas warning
. Puisque la fonction se warning
développe en une chaîne vide, elle peut être utilisée n'importe où dans le makefile : au niveau supérieur, dans le nom de la cible, dans la liste de dépendances et dans les scripts de commande. Cela permet aux valeurs des variables d'être imprimées là où il est le plus approprié de les valider. Par exemple:
$(warning A top-level warning)
FOO := $(warning Right-hand side of a simple variable)bar
BAZ = $(warning Right-hand side of a recursive variable)boo
$(warning A target)target: $(warning In a prerequisite list)makefile $(BAZ)
$(warning In a command script)
ls
$(BAZ):
Donne sortie:
$ make
makefile:1: A top-level warning
makefile:2: Right-hand side of a simple variable
makefile:5: A target
makefile:5: In a prerequisite list
makefile:5: Right-hand side of a recursive variable
makefile:8: Right-hand side of a recursive variable
makefile:6: In a command script
ls
makefile
Notez que l'exécution de la fonction warning
suit le déroulement normal de l'algorithme make
pour les calculs immédiats et différés. En outre, l'affectation à BAZ
contient warning
et le message n'est pas imprimé tant BAZ
qu'il n'est pas développé dans la liste de dépendances.
La possibilité d'insérer un warning
appel n'importe où en fait un outil de débogage très utile.
Options de ligne de commande
: --just-print (-n)
, --print-data-base (-p)
--warn-undefined-variables
.
--just-print
makefile — make
--just-print (-n)
. make
makefile , . , GNU make
(@
) - .
. , . make
, shell
, . :
REQUIRED_DIRS = ...
_MKDIRS := $(shell for d in $(REQUIRED_DIRS); \
do \
[[ -d $$d ]] || mkdir -p $$d; \
done)
$(objects) : $(sources)
_MKDIRS
. --just-print
, makefile. , make
( ) $(objects)
.
--print-data-base
, . , "" makefile, make
. : , , , , ( ) vpath . .
Variables :
# automatic
<D = $(patsubst %/,%,$(dir $<))
# environment
EMACS_DIR = C:/usr/emacs-21.3.50.7
# default
CWEAVE = cweave
# makefile (from `../mp3_player/makefile', line 35)
CPPFLAGS = $(addprefix -I ,$(include_dirs))
# makefile (from `../ch07-separate-binaries/makefile', line 44)
RM := rm -f
# makefile (from `../mp3_player/makefile', line 14)
define make-library
libraries += $1
sources += $2
$1: $(call source-to-object,$2)
$(AR) $(ARFLAGS) $$@ $$^
endef
- , , , , $(<D)
. origin
(. make manual). , . . .
Directories make
, make
. make, SCCS RCS -, , . : , inode .
Implicit rules make
. , , , :
%.c %.h: %.y
# commands to execute (from `../mp3_player/makefile', line 73):
$(YACC.y) --defines $<
$(MV) y.tab.c $*.c
$(MV) y.tab.h $*.h
%: %.c
# commands to execute (built-in):
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.c
# commands to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
make
. , . , Files, .
makefile. — , . , :
%.c %.h: YYLEXFLAG := -d %.c %.h: %.y $(YACC.y) --defines $< $(MV) y.tab.c $*.c $(MV) y.tab.h $*.h
:
# Pattern-specific variable values
%.c :
# makefile (from `Makefile', line 1)
# YYLEXFLAG := -d
# variable set hash-table stats:
# Load=1/16=6%, Rehash=0, Collisions=0/1=0%
%.h :
# makefile (from `Makefile', line 1)
# YYLEXFLAG := -d
# variable set hash-table stats:
# Load=1/16=6%, Rehash=0, Collisions=0/1=0%
# 2 pattern-specific variable values
Files , - , :
# Not a target:
.p.o:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (built-in):
$(COMPILE.p) $(OUTPUT_OPTION) $<
lib/ui/libui.a: lib/ui/ui.o
# Implicit rule search has not been done.
# Last modified 2004-04-01 22:04:09.515625
# File has been updated.
# Successfully updated.
# commands to execute (from `../mp3_player/lib/ui/module.mk', line 3):
ar rv $@ $^
lib/codec/codec.o: ../mp3_player/lib/codec/codec.c ../mp3_player/lib/codec/codec.c ..
/mp3_player/include/codec/codec.h
# Implicit rule search has been done.
# Implicit/static pattern stem: `lib/codec/codec'
# Last modified 2004-04-01 22:04:08.40625
# File has been updated.
# Successfully updated.
# commands to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
- "Not a target"; — . , make
. , vpath , .
VPATH Search Paths VPATH
vpath
.
makefile', eval
, - , .
--warn-undefined-variables
make
. , , . , , . make
, makefile' , :
$ make --warn-undefined-variables -n makefile:35: warning: undefined variable MAKECMDGOALS makefile:45: warning: undefined variable CFLAGS makefile:45: warning: undefined variable TARGET_ARCH ... makefile:35: warning: undefined variable MAKECMDGOALS make: warning: undefined variable CFLAGS make: warning: undefined variable TARGET_ARCH make: warning: undefined variable CFLAGS make: warning: undefined variable TARGET_ARCH ... make: warning: undefined variable LDFLAGS make: warning: undefined variable TARGET_ARCH make: warning: undefined variable LOADLIBES make: warning: undefined variable LDLIBS
, .
--debug
make
, --debug
. . : basic
, verbose
, implicit
, jobs
, all
, makefile
, .
--debug
, basic
- . -d
, all
. : --debug=option1,option2
, option
( , make ):
basic
. ,make
, .
verbose
basic
, .
implicit
basic
, .
jobs
make
' .basic
.
all
-d
.
makefile
, , makefile . , .make
makefile' .basic
,all
.
,
, makefile , . , makefile , .
, , , . , , , . makefile, . , makefile . , - , , , .
«KISS» — . makefile , , . . , , .
, makefile' , , - , , C++ Java. make
! , .
makefile . , make
, makefile , :
do:
cd i-dont-exist; \
echo *.c
makefile , :
$ make
cd i-dont-exist; \
echo *.c
/bin/sh: line 1: cd: i-dont-exist: No such file or directory
*.c
, .c
, . . -, :
SHELL = /bin/bash
do:
cd i-dont-exist && \
shopt -s nullglob &&
echo *.c
cd
make
, echo
make
. , nullglob
bash
. (, .)
$ make
cd i-dont-exist && \
echo *.c
/bin/sh: line 1: cd: i-dont-exist: No such file or directory
make: *** [do] Error 1
. makefile' , , . ?
_MKDIRS := $(shell for d in $(REQUIRED_DIRS); do [[ -d $$d \
]] || mkdir -p $$d; done)
:
_MKDIRS := $(shell \
for d in $(REQUIRED_DIRS); \
do \
[[ -d $$d ]] || mkdir -p $$d; \
done)
, , , . . , - , , , .
, . , :
TAGS:
cd src \
ctags --recurse
disk_free:
echo "Checking free disk space..." \
df . | awk '{ print $$4 }'
. . , strip
. . , , .
. , . — make . « » .
, — if
, , assert
, , , ( ), , , make
.
— . make — 3.80:
NEED_VERSION := 3.80
$(if $(filter $(NEED_VERSION),$(MAKE_VERSION)),, \
$(error You must be running make version $(NEED_VERSION).))
Java CLASSPATH
.
- .
assert
, :
# $(call assert,condition,message)
define assert
$(if $1,,$(error Assertion failed: $2))
endef
# $(call assert-file-exists,wildcard-pattern)
define assert-file-exists
$(call assert,$(wildcard $1),$1 does not exist)
endef
# $(call assert-not-null,make-variable)
define assert-not-null
$(call assert,$($1),The variable "$1" is null)
endef
assert
makefile , .
:
# $(debug-enter)
debug-enter = $(if $(debug_trace),\
$(warning Entering $0($(echo-args))))
# $(debug-leave)
debug-leave = $(if $(debug_trace),$(warning Leaving $0))
comma := ,
echo-args = $(subst ' ','$(comma) ',\
$(foreach a,1 2 3 4 5 6 7 8 9,'$($a)'))
, . debug_trace
:
$ make debug_trace=1
@
, , :
QUIET := @
…
target:
$(QUIET) some command
:
$ make QUIET=