makefile gitignore heredoc

¿Heredoc en un makefile?



gitignore (7)

Depende de cuán determinado estés. Es mejor asumir que no funcionará. Escriba un script de shell para ser lanzado en lugar de un documento aquí en el archivo make.

Falla 1

heredoc: cat - <<! This is the heredoc. !

Esto produce:

cat - <<! This is the heredoc. make: This: No such file or directory make: *** [heredoc] Error 1

Cada línea se ejecuta por separado - oops.

Falla 2

heredoc: cat - <<! / This is the heredoc./ !

Esto generó:

cat: This: No such file or directory cat: is: No such file or directory cat: the: No such file or directory cat: heredoc.!: No such file or directory make: *** [heredoc] Error 1

Puede haber métodos que utilicen una versión específica de make (creo que GNU make, por ejemplo, puede ejecutar todos los comandos para una acción en una única subshell), pero luego tiene que especificar sus requisitos de portabilidad. Para una make normal (por ejemplo, compatible con POSIX), suponga que aquí los documentos no funcionan.

¿Es esto posible y cómo?

Actualización: Necesito esto porque creo un archivo a partir de datos dinámicos y estáticos.

Caso de uso: Tengo un directorio de prueba. Cada archivo C produce un ejecutable de prueba. Con

SRCS = $(wildcard [a-z]*.c)

Puedo agregar nuevas pruebas según sea necesario y hacer que encuentren las nuevas pruebas, compilarlas, ejecutarlas y realizarlas. Yo también uso git. Me gustaría que .gitignore incluya los ejecutables.

Por lo tanto, allí. ¿Cómo crear .gitignore e incluir datos estáticos, es decir, los archivos que quiero que se ignoren ( *.o y depend ) y también los ejecutables de forma dinámica?


GNU Makefile puede hacer cosas como las siguientes. Es feo, y no diré que debas hacerlo, pero lo hago en ciertas situaciones.

.profile = / /#!/bin/sh.exe/n/ /#/n/ /# A MinGW equivalent for .bash_profile on Linux. In MinGW/MSYS, the file/n/ /# is actually named .profile, not .bash_profile./n/ /#/n/ /# Get the aliases and functions/n/ /#/n/ if [ -f /$${HOME}/.bashrc ]/n/ then/n/ . /$${HOME}/.bashrc/n/ fi/n/ /n/ export CVS_RSH="ssh"/n # .profile: echo -e "$($(@))" | sed -e ''s/^[ ]//'' >$(@)

make .profile crea un archivo .profile si no existe uno.

Esta solución se usó donde la aplicación solo utilizará GNU Makefile en un entorno de shell POSIX. El proyecto no es un proyecto de código abierto donde la compatibilidad de la plataforma es un problema.

El objetivo era crear un Makefile que facilite la configuración y el uso de un tipo particular de espacio de trabajo. El Makefile trae consigo varios recursos simples sin requerir cosas como otro archivo especial, etc. Es, en cierto sentido, un archivo de shell. Luego, un procedimiento puede decir cosas como colocar este Makefile en la carpeta para trabajar. Configure su área de trabajo ingrese a make workspace , luego haga bla, ingrese make blah , etc.

Lo que puede ser complicado es averiguar qué hacer con la cita. Lo anterior hace el trabajo y está cerca de la idea de especificar un documento aquí en el Makefile. Si es una buena idea para uso general es otro tema.


Otra solución de GNU Make.

Puedes hacerlo usando los comandos de define y export siguiente manera:

define GITIGNOREDS *.o depend endef SRCS = $(wildcard [a-z]*.c) EXES = $(SRCS:.c=) export GITIGNOREDS .gitignore: $(SRCS) echo $(EXES) | sed ''s/ //n/g'' > $@ echo "$$GITIGNOREDS" >> $@

Sin embargo, debe tener cuidado de hacer expansiones (es decir, $(x) ) dentro del bloque de definición.


Parece que no hay manera de hacer un documento aquí en Makefile. Sin embargo, hay una posible solución. Use echo para enviar los datos del documento aquí:

all: echo "some text" | myScript.sh


Sí tu puedes. Como otros señalan, probablemente no deberías, pero puedes. La respuesta de Ash tiene una solución que involucra comandos de definición, pero es complicada y puede dificultar la expansión de las variables a los valores correctos. Otro truco es usar el .ONESHELL: objetivo especial .

A veces, es preferible que todas las líneas de la receta se pasen a una sola invocación del shell. En general, hay dos situaciones en las que esto es útil: primero, puede mejorar el rendimiento en los archivos make, donde las recetas constan de muchas líneas de comando, al evitar procesos adicionales. En segundo lugar, es posible que desee que se incluyan nuevas líneas en el comando de su receta (por ejemplo, quizás esté usando un intérprete muy diferente como su SHELL). Si el objetivo especial .ONESHELL aparece en cualquier parte del archivo MAKE, todas las líneas de receta para cada objetivo se proporcionarán a una sola invocación del shell. Se conservarán nuevas líneas entre líneas de recetas.

Un par de palabras de advertencia:

  • Esto afectará cómo funcionan todas las recetas en su Makefile.
  • Los operadores de prefijo de línea como - o @ para suprimir la salida o ignorar errores solo funcionan en la primera línea de todas las recetas y tienen efecto para todas las líneas siguientes.
  • Algunas versiones antiguas o GNU Make (como la que se ejecuta de forma predeterminada en el sistema CI de Travis, incluso en los nuevos contenedores) pueden ignorar esta directiva que conduce a errores extraños y errores. Asegúrese de conocer sus entornos de destino.

Con eso fuera del camino, esto es lo que podría parecer generar un archivo de rebajas:

SHELL = bash .ONESHELL: MYVAR = "Some Title" file.md: cat <<- EOF > $@ $(MYVAR) ======== This stuff will all be written to the target file. Be sure to escape dollar-signs and backslashes as Make will be scanning this text for variable replacements before bash scans it for its own strings. Otherwise formatting is just as in any other bash heredoc. Note I used the <<- operator which allows for indentation. This markdown file will not have whitespace at the start of lines. Here is a programmatic way to generate a markdwon list all PDF files in the current directory: `find -maxdepth 1 -name ''*.pdf'' -exec echo " + {}" /;` EOF

Tenga en cuenta que un error adicional es que Make omite líneas en blanco. Si es importante tener una línea en blanco en el contenido de su heredoc, debe asegurarse de sangrar esa línea con el nivel apropiado de espacio en blanco para que coincida con el heredoc o Make lo comerá y ¡ni siquiera se lo pasará al gato!


Según lo solicitado por Jack Kelly:

SRCS = (wildcard [a-z]*.c) EXES = $(SRCS:.c=) GITIGNOREDS = *.o depend .gitignore: $(SRCS) echo $(EXES) | sed ''s/ //n/g'' > $@ echo $(GITIGNOREDS) | sed ''s/ //n/g'' > $@

Importante es la línea GITIGNOREDS . Hubiera preferido un heredoc como

GITIGNOREDS = <<EOT *.o depend EOT

pero también estoy contento con una lista de archivos, separados por espacios y un script sed para traducir el espacio en nuevas líneas.

Editar Según lo propuesto por Ryan V. Bissell: Use un subdirectorio de prueba separado que agregue a gitignore. Y todo cae en su lugar. Es sencillo.


Si está utilizando Gnu Make, use "definir" para crear una variable de texto de varias líneas y una regla para incluirla en su archivo. Consulte 6.8 Definición de variables multilínea en https://www.gnu.org/software/make/manual/make.html#Appending

Me gusta esto:

define myvar # line 1/nline 2/nline 3/n#etc/n endef myfile.txt: /bin/echo -e "$(myvar)) >myfile.txt

Para crear esto, es útil usar un editor, crear el archivo que desea tener, agregar "/ n" al final de cada línea y luego unirlos a todos en una sola cadena. Pega eso en tu makefile.

Probado con GNU Make 3.81 en linux.