Depurar un archivo MAKE es un poco de magia negra. Desafortunadamente, no existe un depurador de archivos MAKE para examinar el progreso de una regla en particular o cómo se expande una variable. La mayor parte de la depuración se puede realizar con impresiones regulares y comprobando el archivo MAKE . Por supuesto, GNU make ayuda un poco con sus métodos integrados y opciones de línea de comandos. Uno de los mejores métodos para depurar archivos MAKE es agregar ganchos de depuración y usar técnicas de programación seguras para apoyarse cuando las cosas van mal. Las siguientes son algunas técnicas básicas de depuración y prácticas de codificación segura que creo que serán de gran utilidad.
Capacidades de depuración de make
Una función muy útil para depurar un archivo MAKE que no funciona warning
. Dado que la función se warning
expande a una cadena vacía, se puede usar en cualquier lugar del archivo MAKE : en el nivel superior, en el nombre del objetivo, en la lista de dependencias y en los scripts de comandos. Esto permite imprimir los valores de las variables donde sea más apropiado validarlos. Por ejemplo:
$(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):
Da salida:
$ 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
Tenga en cuenta que la ejecución de la función warning
sigue el flujo normal del algoritmo make
para cálculos inmediatos y diferidos. Además, la asignación a BAZ
contiene warning
y el mensaje no se imprime hasta BAZ
que se expande en la lista de dependencias.
La capacidad de insertar una warning
llamada en cualquier lugar la convierte en una herramienta de depuración muy útil.
Opciones de línea de comando
: --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=