it-swarm.dev

¿Cómo obtener un script en un Makefile?

¿Hay una mejor manera de obtener un script, que establezca las variables env, desde un archivo make?

FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) $@'
else
...targets...
endif
64
brooksbp

Para responder a la pregunta como se le pregunta: no puede .

El problema básico es que un proceso hijo no puede alterar el entorno de los padres. El Shell soluciona esto al no forking un nuevo proceso cuando source 'ing, pero simplemente ejecuta esos comandos en la encarnación actual del Shell. Eso funciona bien, pero make no es /bin/sh (o para lo que Shell sea su script) y no entiende ese lenguaje (aparte de los bits que tienen en común).

Chris Dodd y Foo Bah han abordado una posible solución alternativa, por lo que sugeriré otra (suponiendo que esté ejecutando GNU make): postprocese el script de Shell para hacer un texto compatible e incluya el resultado:

Shell-variable-setter.make: Shell-varaible-setter.sh
    postprocess.py @^

# ...
else
include Shell-variable-setter.make
endif

detalles desordenados dejados como ejercicio.

39
dmckee

El Shell predeterminado de Makefile es /bin/sh que no implementa source.

Cambiar Shell a /bin/bash lo hace posible:

# Makefile

Shell := /bin/bash

rule:
    source env.sh && YourCommand
55
PureW

Si su objetivo es simplemente establecer variables de entorno para Make, ¿por qué no mantenerlo en la sintaxis de Makefile y usar el comando include?

include other_makefile

Si tiene que invocar el script de Shell, capture el resultado en un comando Shell:

JUST_DO_IT=$(Shell source_script)

el comando de shell debe ejecutarse antes de los objetivos. Sin embargo, esto no establecerá las variables de entorno.

Si desea establecer variables de entorno en la compilación, escriba un script de Shell separado que genere las variables de entorno y las llamadas que realice. Luego, en el archivo make, haga que los destinos llamen al nuevo script de Shell.

Por ejemplo, si su makefile original tiene el objetivo a, entonces quiere hacer algo como esto:

# mysetenv.sh
#!/bin/bash
. <script to source>
export FLAG=1
make "$@" 

# Makefile
ifeq($(FLAG),0)
export FLAG=1
a: 
    ./mysetenv.sh a
else
a:
    .. do it
endif
21
Foo Bah

Usando GNU Make 3.81 Puedo obtener una secuencia de comandos de Shell desde make:

rule:
<tab>source source_script.sh && build_files.sh

build_files.sh "obtiene" las variables de entorno exportadas por source_script.sh.

Tenga en cuenta que utilizando:

rule:
<tab>source source_script.sh
<tab>build_files.sh

no trabajará. Cada línea se ejecuta en su propia subshell.

16
Samuel

Esto funciona para mi Sustituya env.sh con el nombre del archivo que desea obtener. Funciona mediante la fuente del archivo en bash y la salida del entorno modificado, después de formatearlo, a un archivo llamado makeenv, que luego se genera en el archivo makefile.

IGNORE := $(Shell bash -c "source env.sh; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")                         
include makeenv   
10
gdw2

Algunas construcciones son las mismas en Shell y en GNU Make.

var=1234
text="Some text"

Puedes alterar tu script de Shell para obtener las definiciones. Todos deben ser tipos name=value simples.

Es decir,

[script.sh]

. ./vars.sh

[Makefile]

include vars.sh

Luego, el script de Shell y el Makefile pueden compartir la misma 'fuente' de información. Encontré esta pregunta porque estaba buscando un manifiesto de sintaxis común que se pueda usar en los scripts Gnu Make y Shell (no me importa cuál Shell).

Editar: Shells y hacer entender $ {var} . Esto significa que puede concatenar, etc, var = "Una cadena" var = $ {var} "Segunda cadena"

5
artless noise

Realmente me gusta la respuesta de Foo Bah, donde hacer llamadas al script, y la secuencia de comandos vuelve a llamar. Para ampliar esa respuesta hice esto:

# Makefile
.DEFAULT_GOAL := all 

ifndef SOME_DIR

%:
<tab>. ./setenv.sh $(MAKE) $@

else

all:
<tab>...

clean:
<tab>...

endif

-

# setenv.sh
export SOME_DIR=$PWD/path/to/some/dir

if [ -n "$1" ]; then
    # The first argument is set, call back into make.
    $1 $2
fi

Esto tiene la ventaja adicional de usar $ (MAKE) en caso de que alguien use un programa make exclusivo, y también manejará cualquier regla especificada en la línea de comandos, sin tener que duplicar el nombre de cada regla en el caso cuando SOME_DIR no esté definido .

3
Samuel

Mi solución a esto: (asumiendo que tienes bash, la sintaxis de $@ es diferente para tcsh por ejemplo)

Tener un script sourceThenExec.sh, como tal:

#!/bin/bash
source whatever.sh
$@

Luego, en su makefile, comience sus objetivos con bash sourceThenExec.sh, por ejemplo:

ExampleTarget:
    bash sourceThenExec.sh gcc ExampleTarget.C

Por supuesto, puede poner algo como STE=bash sourceThenExec.sh en la parte superior de su makefile y acortar esto:

ExampleTarget:
    $(STE) gcc ExampleTarget.C

Todo esto funciona porque sourceThenExec.sh abre una subshell, pero luego los comandos se ejecutan en la misma subshell.

La desventaja de este método es que el archivo se obtiene para cada objetivo, lo que puede ser indeseable.

1
Chris

Otra forma posible sería crear un script sh, por ejemplo run.sh, obtener los scripts requeridos y hacer make dentro del script.

#!/bin/sh
source script1
source script2 and so on

make 
1
Veera

Dependiendo de su versión de Make y del shell, puede implementar una solución de Niza a través de eval, cat, y encadenar llamadas con &&:

ENVFILE=envfile

source-via-eval:
  @echo "FOO: $${FOO}"
  @echo "FOO=AMAZING!" > $(ENVFILE)
  @eval `cat $(ENVFILE)` && echo "FOO: $${FOO}"

Y una prueba rápida:

> make source-via-eval
FOO:
FOO: AMAZING!
0
tankthinks

Si solo necesita unas pocas variables conocidas, exportar en makefile puede ser una opción, aquí hay un ejemplo de lo que estoy usando.

$ grep ID /etc/os-release 

ID=ubuntu
ID_LIKE=debian


$ cat Makefile

default: help rule/setup/lsb

source?=.

help:
        -${MAKE} --version | head -n1

rule/setup/%:
        echo ID=${@F}

rule/setup/lsb: /etc/os-release
        ${source} $< && export ID && ${MAKE} rule/setup/$${ID}


$ make

make --version | head -n1
GNU Make 3.81
. /etc/os-release && export ID && make rule/setup/${ID}
make[1]: Entering directory `/tmp'
echo ID=ubuntu
ID=ubuntu

- http://rzr.online.fr/q/gnumake

0
RzR

Si desea incluir las variables en el entorno, para que se pasen a procesos secundarios, puede usar el set -a y set +a de bash. El primero significa: "Cuando establezco una variable, establezca también la variable de entorno correspondiente". Así que esto funciona para mí:

check:
    bash -c "set -a && source .env.test && set +a && cargo test"

Eso pasará todo en .env.test a cargo test como variables de entorno.

Tenga en cuenta que esto le permitirá pasar un entorno a los subcomandos, pero no le permitirá establecer las variables de Makefile (que son cosas diferentes de todos modos). Si necesita este último, debe probar una de las otras sugerencias aquí.

0
Paul A Jungwirth