Depurando o Makefile / parte 1 /

Depurar um makefile  é um pouco de magia negra. Infelizmente, não existe um depurador makefile para examinar o progresso de uma regra específica ou como uma variável é expandida. A maior parte da depuração pode ser feita com impressões regulares e verificação do makefile . Claro, GNU make ajuda um pouco com seus métodos embutidos e opções de linha de comando. Uma das melhores técnicas para depurar makefiles é adicionar ganchos de depuração e usar técnicas de programação seguras para se apoiar quando as coisas dão errado. A seguir estão algumas técnicas básicas de depuração e práticas seguras de codificação que considero mais úteis.





Recursos de depuração do make

Uma  função muito útil para depurar um makefile que não funciona warning



. Uma vez que a função se warning



expande para uma string vazia, ela pode ser usada em qualquer lugar no makefile : no nível superior, no nome do destino, na lista de dependências e em scripts de comando. Isso permite que os valores das variáveis ​​sejam impressos onde for mais apropriado para validá-los. Por exemplo:





$(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):
      
      



Dá saída:





$ 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
      
      



Observe que a execução da função warning



segue o fluxo normal do algoritmo make



para cálculos imediatos e adiados. Além disso, a atribuição a BAZ



contém warning



e a mensagem não é impressa até BAZ



que seja expandida para a lista de dependências.





A capacidade de inserir uma warning



chamada em qualquer lugar o torna uma ferramenta de depuração muito útil.





Opções de linha 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=
      
      










All Articles