Cree una variable en un archivo MAKE leyendo el contenido de otro archivo

81

¿Cómo puedo crear una variable sobre la marcha a partir de un archivo MAKE, cuyo valor sería el contenido completo de otro archivo de datos?

Srinath
fuente

Respuestas:

49

Supongo que le gusta establecer una variable en su Makefile al contenido de otro archivo:

FILE=test.txt
VARIABLE=`cat $(FILE)`

target:
    echo $(VARIABLE)
generación bb
fuente
3
En realidad, no puedo poner la definición VARIABLE por encima de todo: porque PATH_TO_MY_DATA_FILE no existe hasta que se hayan ejecutado algunos comandos en all: target. Como alternativa, lo que hice es dividir las cosas en dos archivos MAKE (crear una sub-marca) y declarar VARIABLE en la parte superior de la sub-marca y ahora funciona como un encanto.
Srinath
26
Esta es una respuesta incorrecta. El valor de VARIABLEes una cadena cat $(FILE)(entre comillas) que solo se expande en una receta por el shell. Intente imprimir el valor de la misma como $(info ${VARIABLE}).
Maxim Egorushkin
3
@MaximEgorushkin No está mal. Solo hay que considerarlo VARIABLEcomo una promesa. Esta es la única versión que funciona con versiones anteriores de make. Ambos :=y $(shell ...)son extensiones GNU.
hasta el
7
Voto en contra. Esto se ejecutará catcada vez que se ejecute la regla. Por lo general, esto no es una intención y se debe advertir contra ello, porque es lento. Además, si el archivo es una tubería, tiene efectos secundarios no deseados. La asignación debe ser con :=para que la regla no se evalúe cuando se reemplaza la variable sino cuando se define la variable. El valor de reemplazo debe ser $(shell cat $(FILE))tal que el catcomando se ejecute en el lugar por marca, no más tarde por las reglas de la receta.
Christian Hujer
2
@antred, make es parte del conjunto de herramientas estándar de UNIX / POSIX que también incluye cat. Si instala make, es normal instalar todas las demás herramientas básicas y hay circunstancias muy raras en las que eso causará dificultades. Confiar en catreglas alternativas en lugar de complejas hará que sus archivos MAKE sean mucho más simples de entender y casi tan portátiles o, a veces, más portátiles.
Michael
81

Suponiendo que GNU haga:

file := whatever.txt
variable := $(shell cat ${file})
Maxim Egorushkin
fuente
4
@ceving Usa la marca GNU estándar. Solaris make es una aplicación no portátil.
Maxim Egorushkin
7
La marca GNU no es estándar ni más portátil que la marca solaris. "Popular" es tu palabra. Si consideramos seriamente la portabilidad y la conformación estándar, quédese con posix.
把 友情 留 在 无 盐
3
En este caso me decantaría por "Popular"; un Make que no sea de GNU es demasiado primitivo. Si su objetivo es seguir admitiendo los sistemas operativos de la década de 1990, entonces la respuesta de @ bb-generation es probablemente lo que necesita (aunque en muchos casos le traerá problemas). En todos los demás casos, GNU Make está fácilmente disponible o, más probablemente, es el predeterminado, así que úselo.
Guss
1
GNU hace que se ejecute en cualquier lugar, así que sí, es mucho más portátil que cualquier otra marca. "estándar" puede ser subjetivo, concedido.
MarcH
26

GNU make versión 4.2 admite la operación de lectura de archivos, por lo que con respecto a la gran respuesta de Maxim Egorushkin , hay una forma opcional de resolver este problema ahora:

FILE     := test.txt
variable :=$(file < $(FILE))
yurimz
fuente
Se corrigió un error. Los nombres de las variables distinguen entre mayúsculas y minúsculas. Los nombres 'foo', 'FOO' y 'Foo' se refieren a diferentes variables. ( gnu.org/software/make/manual/html_node/Using-Variables.html )
Yaroslav Nikitenko
las comillas tampoco son necesarias, $ (file <"$ (FILE)") intenta abrir "test.txt".
cagney
14

catno existe en Windows. Solución que funciona para Linux y Windows:

cat := $(if $(filter $(OS),Windows_NT),type,cat)
variable := $(shell $(cat) filename)

Explicación: Parece que en Windows siempre hay OSuna variable de entorno definida para ser igual a 'Windows_NT'. De esta manera, typese usa el comando para Windows , para los que no son de Windows cat.

Pavel P
fuente
4

Si está usando GNU make, otra forma de obtener este efecto es usar un make "include" de otro makefile:

Desde Makefile:

include "./MyFile.mak"

Cree un archivo "MyFile.mak" con contenido:

FILE := "my file content"
FILE += "more content 1"
FILE += "more content 2"
Bill Moore
fuente
esto no parece funcionar, lo entiendoMakefile:1: "./MyFile.mak": No such file or directory
Knocte
eso probablemente significa que está usando una versión de make ... sin GNU o una versión realmente antigua de make ... intente: "make -v"
Bill Moore
usando make en mac, no estoy seguro si está incluido o instalado por homebrew, make -vdaGNU Make 3.81
knocte
¿Se asegura de no haber convertido accidentalmente caracteres TAB en caracteres ESPACIO en el Makefile? Make es casi molesto como Python en este sentido.
Bill Moore
Conseguí que esto funcionara en mi Mac eliminando las comillas, por ejemplo: include ./MyFile
Charlie Tran
3

Como no se ha especificado la plataforma, esta es la forma en que funciona en Solaris:

VERSION:sh = cat VERSION

all:
        echo $(VERSION)
ceving
fuente
0

Aquí hay una solución más portátil, que funciona con la MAKEversión 3, donde la filedirectiva no está disponible. La desventaja es que requiere crear un archivo temporal en el proceso.

$(shell echo define my_variable > file.tmp)
$(shell cat my_file.txt >> file.tmp)
$(shell echo endef >> file.tmp)
include file.tmp

La idea principal es utilizar la definedirectiva, que está específicamente diseñada para declarar variables de varias líneas. Por supuesto, puede evitar el uso de shellun archivo temporal y si puede escribir explícitamente el contenido del archivo para el uso de Makefile.

Tenga en cuenta que, si su archivo contiene $signos, MAKEintentará expandirlos como variables / directivas cuando my_variablese expanda (o cuando se asigne, lo defina con :=). Si desea evitarlo, debe escapar de ellos antes de incluir el contenido del archivo. Por ejemplo, en lugar de cathacer esto:

$(shell sed 's/\$$/$$$$/g' my_file.txt >> file.tmp)
Thunderbeef
fuente