2011-09-21 16 views
40

Esiste un modo migliore per generare uno script, che imposta env vars, all'interno di un makefile?Come trovare uno script in un Makefile?

FLAG ?= 0 
ifeq ($(FLAG),0) 
export FLAG=1 
/bin/myshell -c '<source scripts here> ; $(MAKE) [email protected]' 
else 
...targets... 
endif 
+1

Suona come quello che vuoi veramente è scrivere uno script che indirizzi il tuo script per impostare envvars e poi esegua make, piuttosto che avere lo stesso script sorgente ... –

risposta

28

Per rispondere alla domanda come chiesto: non si può.

Il problema di base è che un processo figlio non può alterare l'ambiente del genitore. La shell si aggira intorno a questo per non creando un nuovo processo quando source ', ma semplicemente eseguendo quei comandi nell'attuale incarnazione della shell. Funziona bene, ma make non è /bin/sh (o qualsiasi altra shell è per il tuo script) e non capisce quel linguaggio (a parte i bit che hanno in comune).

Chris Dodd e Foo Bah hanno affrontato una possibile soluzione, quindi dovrò suggerire un altro (supponendo che si sta eseguendo GNU make): post-processo lo script di shell in testo compatibile marca e comprendono il risultato:

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

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

dettagli disordinati lasciati come esercizio.

17

Se il vostro obiettivo è quello di impostare solo le variabili d'ambiente per Make, perché non tenerlo nella sintassi Makefile e utilizzare il comando include?

include other_makefile 

Se si deve richiamare lo script di shell, catturare il risultato in un comando shell:

JUST_DO_IT=$(shell source_script) 

il comando di shell deve essere eseguito prima dei bersagli. Tuttavia questo non imposterà le variabili d'ambiente.

Se si desidera impostare le variabili di ambiente nella generazione, scrivere uno script di shell separato che indirizzi le variabili e le chiamate di ambiente create. Quindi, nel makefile, gli obiettivi chiamano il nuovo script della shell.

Ad esempio, se il makefile originale ha bersaglio a, poi si vuole fare qualcosa di simile:

# mysetenv.sh 
#!/bin/bash 
. <script to source> 
export FLAG=1 
make "[email protected]" 

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

Non ho il controllo dello script. Deve provenire. – brooksbp

+0

@brooksbp modificato. –

+0

Acquisisce le variabili di ambiente se non vengono esportate? A prima vista sembra che invochi una nuova shell, esegua il comando, quindi esca e ritorni al vecchio ambiente ..? – brooksbp

4

Alcuni costrutti sono uguali nello shell e nello GNU Make.

var=1234 
text="Some text" 

È possibile modificare lo script della shell per l'origine delle definizioni. Devono essere tutti semplici tipi name=value.

Vale a dire,

[script.sh]

. ./vars.sh 

[Makefile]

include vars.sh 

Poi lo script di shell e il Makefile possono condividere lo stesso 'fonte' di informazioni. Ho trovato questa domanda perché stavo cercando un manifest di sintassi comune che possa essere usato in Gnu Make e negli script di shell (non mi interessa quale shell).

Modifica: Conchiglie e far capire $ {var}. Ciò significa che è possibile concatenare, ecc, var = "Una stringa" var = $ {var} "Seconda stringa"

+0

Err, uno script di shell come sopra non crea ** dettagli disordinati ** come nella risposta accettata. Finisce per essere un po 'come un file [tag: kbuild]. –

9

Questo funziona per me. Sostituire env.sh con il nome del file che si desidera importare. Funziona tramite il sourcing del file in bash e l'output dell'ambiente modificato, dopo averlo formattato, in un file chiamato makeenv che viene quindi estratto dal makefile.

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

'ifdef _intel64onosx'
' GCC =/opt/intel/bin/icc'
'CFLAGS = -g -m64 -std = c99' ' IGNORA: = $ (shell bash -c "fonte/opt/intel /bin/iccvars.sh intel64; env | sed 's/= /: = /' | sed 's/^/export /'> makeenv ")' 'include makeenv' – revher

+0

Nice per l'impostazione degli ambienti di compilazione corretti (qui 64 -po). Grazie. – revher

11

Utilizzando GNU Make 3.81 mi possibile fonte di uno script di shell da make utilizzando:

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

build_files.sh "ottiene" le variabili di ambiente esportate da source_script.sh.

noti che usare:

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

non funzionerà. Ogni riga viene eseguita nella sua sottotitola.

+0

Bel trucco, grazie! – Timmmm

+0

Si noti che mantenere 'source' e comandi sulla stessa linea diventa necessario con GNU Make 4.1 (e forse anche 4.0). Usando 3.81, posso usare diverse linee. Per la portabilità, una linea funziona attraverso queste versioni. Invocare uno script esterno è più leggibile se la linea diventa troppo lunga, però! –

+0

Sei sicuro? Le linee multiple non hanno funzionato per me in 3.81, come ho menzionato nella risposta. Make esegue ogni riga nella sua subshell, quindi più righe non dovrebbero funzionare su nessuna versione. Forse hai un SO non comune o fai build? – Samuel

0

Se sono necessarie solo alcune variabili note che esportano in makefile può essere un'opzione, ecco un esempio di ciò che sto utilizzando.

$ 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

1

La mia soluzione a questo: (supponendo che si sta avere bash, la sintassi per [email protected] è diversa per tcsh per esempio)

avere uno script sourceThenExec.sh, in quanto tale :

#!/bin/bash 
source whatever.sh 
[email protected] 

Quindi, nel tuo makefile, prefazione del tuo targe ts con bash sourceThenExec.sh, per esempio:

ExampleTarget: 
    bash sourceThenExec.sh gcc ExampleTarget.C 

Ovviamente si può mettere qualcosa come STE=bash sourceThenExec.sh nella parte superiore del makefile e accorciare questo:

ExampleTarget: 
    $(STE) gcc ExampleTarget.C 

Tutto questo funziona perché sourceThenExec.sh apre una subshell, ma quindi i comandi vengono eseguiti nella stessa subshell.

Lo svantaggio di questo metodo è che il file viene prelevato per ciascun target, il che potrebbe non essere desiderabile.

3

Mi piace molto la risposta di Foo Bah in cui effettuare chiamate chiama la sceneggiatura e la sceneggiatura richiama per rendere. Per espandere su quella risposta che ho fatto questo:

# Makefile 
.DEFAULT_GOAL := all 

ifndef SOME_DIR 

%: 
<tab>. ./setenv.sh $(MAKE) [email protected] 

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 

Questo ha il vantaggio di utilizzare $ (MAKE) nel caso qualcuno sta usando un programma di rendere unico, e sarà anche di gestire qualsiasi regola specificata sulla riga di comando, senza dover duplicare il nome di ogni regola nel caso in cui SOME_DIR non sia definito.

+0

Se si ha una versione precedente di make e .DEFAULT_GOAL non è supportato, il primo ramo di ifndef fallirà con "make: *** No targets. Stop.". Puoi risolvere questo problema aggiungendo "all" alla regola implicita, in questo modo: "all%:". Si noti che ciò causerà un avvertimento "*** implicito e normale misto: sintassi deprecata" con le versioni più recenti di make. – Samuel

+0

Per rendere il '%' target _.SILENT_, avviare il comando con '@' – ITL

1

Un altro modo possibile è quello di creare uno script sh, ad esempio run.sh, immettere gli script richiesti e chiamare make all'interno dello script.

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

make 
0

Se si desidera ottenere le variabili in ambiente, in modo che essi vengono passati a processi figli, quindi è possibile utilizzare di set -a e set +a bash. Il primo significa "Quando imposto una variabile, imposta anche la variabile d'ambiente corrispondente". Quindi, questo funziona per me:

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

che passerà tutto in .env.test a cargo test come variabili d'ambiente.

Nota che questo ti permetterà di passare un ambiente ai sotto-comandi, ma non ti permetterà di impostare variabili Makefile (che sono comunque cose diverse). Se hai bisogno di quest'ultimo, dovresti provare uno degli altri suggerimenti qui.

8

La shell di default di Makefile è /bin/sh che non implementa source.

Cambiare shell per /bin/bash rende possibile:

# Makefile 

SHELL := /bin/bash 

rule: 
    source env.sh && YourCommand 
0
target: output_source 
    bash ShellScript_name.sh 

provare questo funzionerà, lo script si trova all'interno della directory corrente.

Problemi correlati