tutorial make makefile gnu-make

tutorial - makefile linux



¿Por qué patsubst deja de funcionar cuando usa expansión secundaria de $$*? (2)

Los caracteres de porcentaje están siendo leídos por make como coincidencias con el comodín en el tallo y están siendo reemplazados por el tallo coincidente. Si make -p el resultado make -p para su ejemplo, verá que la línea objetivo analizada tiene este aspecto:

%.a: $(patsubst %.c,%.o,$($*_SRCS))

Lo cual, en lo que respecta a la marca, es solo un conjunto realmente extraño de objetivos con patrones (o algo así).

Si escapa del porcentaje de caracteres del análisis sintáctico de una manera similar a la forma en que escapa a la evaluación $ from make, puede obtener lo que desea que funcione:

pc := % $$(patsubst $$(pc).c,$$(pc).o,$$($$*_SRCS))

Para obtener información adicional, las referencias de sustitución (es decir, $(foo_SRCS:.c=.o) ) se pueden usar para transformaciones como esta en lugar de la llamada más larga a patsubst. En este caso, sin embargo, mientras funciona en este escenario con un escape similar de : (a través de c := : :) no parece funcionar como el único requisito previo del objetivo (con make dando un Makefile:23: *** commands commence before first target. Stop. error que no entiendo del todo) al menos con GNU Make 3.81.

Aquí hay un ejemplo de la sección de manual de GNU Make en Expansión secundaria (ligeramente simplificada):

foo_SRCS := bar.c baz.c .SECONDEXPANSION: # $$@ expands to the target ("foo" in this case) foo: $$(patsubst %.c,%.o,$$($$@_SRCS))

Esto funciona genial; construye bar.o y baz.o :

cc -c -o bar.o bar.c cc -c -o baz.o baz.c

Pero si modifico este ejemplo solo ligeramente, la patsubst deja de funcionar:

all: foo.a foo_SRCS := bar.c baz.c .SECONDEXPANSION: # $$* expands to the stem of the match ("foo" in this case). %.a: $$(patsubst %.c,%.o,$$($$*_SRCS)) ar rcs $@ $^

Ya no está bar.o y baz.o , y en su lugar está usando los archivos *.c directamente como prerrequisitos.

ar rcs foo.a bar.c baz.c

Tenga en cuenta que la parte $$($$*_SRCS) está funcionando claramente, como lo demuestra el hecho de que encontró foo_SRCS y lo usó como requisitos previos. ¡Pero por alguna razón, la parte de patsubst ha convertido en un no-op! En lugar de reemplazar %.c con %.o , simplemente usa foo_SRCS directamente.

¿Que esta pasando aqui? ¿Cómo puedo hacer que mi ejemplo funcione?

EDITAR: Tenía una teoría de que el % caracteres dentro de la patsubst estaba evaluando temprano, usando la coincidencia raíz (foo), de modo que la propia copiadora se veía así:

$(patsubst foo.c,foo.o,bar.c baz.c)

Para probar esta teoría, agregué un archivo llamado foo.c a foo_SRCS :

all: foo.a foo_SRCS := foo.c bar.c baz.c .SECONDEXPANSION: # $$* expands to the stem of the match ("foo" in this case). %.a: $$(patsubst %.c,%.o,$$($$*_SRCS)) ar rcs $@ $^

Eso resultó en algo aún más extraño:

make: *** No rule to make target `foo.a'', needed by `all''. Stop.


Está mezclando tres características que no van bien juntas: expansión secundaria , reglas de patrones y patsubst . Trataré de explicar en detalle qué hace la marca al evaluar tu código (AFAIUI).

Comencemos con tu primer Makefile:

foo_SRCS := bar.c baz.c .SECONDEXPANSION: %.a: $$(patsubst %.c,%.o,$$($$*_SRCS)) ar rcs $@ $^

Fase de lectura Se escapan todos los signos de dólar, por lo que no se realiza ninguna evaluación aquí. Make ingresa la siguiente regla en su base de datos:

%.a: $(patsubst %.c,%.o,$($*_SRCS))

Sustitución de patrones En lo que concierne a make, esta es solo otra regla de patrón, con el objetivo %.a y dos prerrequisitos separados por espacios en blanco: $(patsubst y %.c,%.o,$($*_SRCS)) .

foo.a coincide con el patrón objetivo, por lo que el primer % en cada requisito previo será reemplazado por foo . La regla se convierte en:

foo.a: $(patsubst foo.c,%.o,$($*_SRCS))

Fase de actualización de destino Como solicitó la expansión secundaria, el patrón se evalúa nuevamente en la fase de actualización del objetivo:

foo.a: $(patsubst foo.c,%.o,$($*_SRCS)) ==> foo.a: $(patsubst foo.c,%.o,bar.c baz.c) ==> foo.a: bar.c baz.c

Y así termina ejecutando el comando

ar rcs foo.a bar.c baz.c

¿Y qué hay de foo.c? Si agrega foo.c a foo_SRCS, la expansión secundaria se ve así:

foo.a: $(patsubst foo.c,%.o,$($*_SRCS)) ==> foo.a: $(patsubst foo.c,%.o,foo.c bar.c baz.c) ==> foo.a: %.o bar.c baz.c

Y la regla falla porque make no sabe cómo construir %.o .

Work-around. Puede escapar del % caracteres con una barra diagonal inversa:

.SECONDEXPANSION: %.a: $(patsubst /%.c,/%.o,$$($$*_SRCS)) ar rcs $@ $^