Encontro o seguinte sed
comando no manualmake
do .
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g'
E tem o seguinte efeito (este é um exemplo no manual):
main.o : main.c defs.h
# is turned into:
main.o main.d : main.c defs.h
No meu entendimento, '\($*\)\.o'
pretende-se corresponder ao nome do arquivo filename.o
, mas não entendo como '\($*\)'
conseguir isso. Eu sei $
que é especial no final de linha em uma expressão regular, mas isso não se aplica aqui.
Então, o que significa '\($*\)'
aqui?
O código completo:
%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
O
$
usado aqui é o cifrão da$*
variável Make automática , e não algo que denota o fim da linha.Você tem um exemplo semelhante disso na parte de substituição da
sed
substituição, onde$@
é usado.Make irá substituir os valores dessas variáveis na
sed
expressão antes de executar osed
comando.O uso de
\($*\)
na expressão regular significa que o "radical" do alvo Make (a stringmain
no exemplo) é capturado e pode ser reutilizado posteriormente como\1
no texto de substituição.O seguinte
sed
comando teria o mesmo efeito, mas sem usar um grupo de captura:É importante ter em mente que normalmente expressões regulares fornecidas na linha de comando to
sed
estão sujeitas a duas rodadas de análise: uma vez porsh
(é por isso que você coloca entre'
aspas) e novamente porsed
si só (é por isso que você coloca\
antes(
e)
quando você deseja que eles controlem o agrupamento).Quando você coloca algo dentro de um Makefile, há uma terceira rodada de análise antes delas, por
make
.sed
só vê$
como fim de linha se$
sobreviver às duas rodadas anteriores de análise.Em um Makefile,
$
informamake
que o texto a seguir é uma variável (ou função) a ser expandida; se o próximo símbolo for(
ou{
, tudo até a próxima correspondência)
ou}
será usado como nome de variável ou função; caso contrário, apenas o próximo símbolo será o nome da variável.$(FOO)BAR
expande para o conteúdo da variávelFOO
, seguido porBAR
;$FOOBAR
expande para o conteúdo da variávelF
, seguido porOOBAR
;$*
expande para o conteúdo da variável especial chamada*
, que contém o destino atual, e$$
expande para o conteúdo da variável especial chamada$
, que simplesmente contém um literal$
; isso é para que você possa alimentar$
o shell (a segunda fase de análise) escrevendo$$
em seu Makefile.$$foobar
expande para um único$
seguido porfoobar
; e então o shell expande isso para o conteúdo da variável shellfoobar
(mas apenas se não estiver entre aspas simples). Variáveis Shell e variáveis Makefile são separadas por padrão; não presuma que o mesmo nome se refere ao mesmo valor em ambos os contextos.(Versões antigas
make
suportam apenas$(
...)
e não${
...}
, então use a primeira para máxima portabilidade.)