web-dev-qa-db-fra.com

Comment rechercher un script dans un Makefile?

Existe-t-il un meilleur moyen de générer un script, qui définit env vars, à partir d'un fichier Make?

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

Pour répondre à la question telle que posée: vous ne pouvez pas .

Le problème fondamental est qu'un processus enfant ne peut pas modifier l'environnement du parent. Le shell résout ce problème en ne pas forger un nouveau processus lorsque source 'ing, mais en exécutant simplement ces commandes dans la version actuelle du Shell. Cela fonctionne bien, mais make n'est pas /bin/sh (ou quel que soit le shell pour lequel votre script est destiné) et ne comprend pas cette langue (à l'exception des bits qu'ils ont en commun).

Chris Dodd et Foo Bah ont abordé une solution de contournement possible. Je vais donc en suggérer une autre (en supposant que vous exécutiez GNU make]): post-traitement du script Shell en texte compatible et en incluant le résultat:

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

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

détails en désordre laissés comme un exercice.

36
dmckee

Le shell par défaut du Makefile est /bin/sh qui n'implémente pas source.

Changer Shell en /bin/bash permet:

# Makefile

Shell := /bin/bash

rule:
    source env.sh && YourCommand
39
PureW

Si votre objectif est simplement de définir des variables d'environnement pour Make, pourquoi ne pas le conserver dans la syntaxe Makefile et utiliser la commande include?

include other_makefile

Si vous devez appeler le script Shell, capturez le résultat dans une commande Shell:

JUST_DO_IT=$(Shell source_script)

la commande Shell doit être exécutée avant les cibles. Cependant, cela ne définira pas les variables d'environnement.

Si vous souhaitez définir des variables d'environnement dans la construction, écrivez un script Shell distinct qui identifie vos variables d'environnement et vos appels. Ensuite, dans le fichier Make, demandez aux cibles d’appeler le nouveau script Shell.

Par exemple, si votre makefile d'origine a pour cible a, alors vous voulez faire quelque chose comme ceci:

# 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

Avec GNU Make 3.81, je peux obtenir un script Shell à partir de make en utilisant:

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

build_files.sh "récupère" les variables d'environnement exportées par source_script.sh.

Notez que l'utilisation de:

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

ne fonctionnera pas. Chaque ligne est exécutée dans son propre sous-shell.

16
Samuel

Cela fonctionne pour moi. Remplacez env.sh par le nom du fichier que vous souhaitez créer. Cela fonctionne en recherchant le fichier dans bash et en sortant l'environnement modifié, après l'avoir formaté, dans un fichier appelé makeenv qui est ensuite obtenu par le fichier makefile. 

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

Certaines constructions sont les mêmes dans Shell et dans GNU Make.

var=1234
text="Some text"

Vous pouvez modifier votre script Shell pour trouver la source. Ils doivent tous être de simples types name=value.

C'est à dire,

[script.sh]

. ./vars.sh

[Makefile]

include vars.sh

Ensuite, le script shell et le Makefile peuvent partager la même "source" d'informations. J'ai trouvé cette question parce que je cherchais un manifeste de syntaxe commune pouvant être utilisé dans les scripts Gnu Make et Shell (peu importe le shell).

Éditer: Coquilles et faire comprendre $ {var} . Cela signifie que vous pouvez concaténer, etc., var = "Une chaîne" var = $ {var} "Deuxième chaîne"

5
artless noise

J'aime beaucoup la réponse de Foo Bah où make appelle le script et le script rappelle. Pour développer cette réponse, j'ai fait ceci:

# 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

Cela présente l'avantage supplémentaire d'utiliser $ (MAKE) au cas où quelqu'un utiliserait un programme de création unique et traiterait également toute règle spécifiée sur la ligne de commande, sans devoir dupliquer le nom de chaque règle dans le cas où SOME_DIR n'est pas défini .

3
Samuel

Ma solution à ceci: (en supposant que vous avez bash, la syntaxe pour $@ est différente pour tcsh par exemple)

Avoir un script sourceThenExec.sh, en tant que tel:

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

Ensuite, dans votre makefile, faites précéder vos cibles avec bash sourceThenExec.sh, par exemple:

ExampleTarget:
    bash sourceThenExec.sh gcc ExampleTarget.C

Vous pouvez bien sûr mettre quelque chose comme STE=bash sourceThenExec.sh en haut de votre makefile et raccourcir ceci:

ExampleTarget:
    $(STE) gcc ExampleTarget.C

Tout cela fonctionne car sourceThenExec.sh ouvre un sous-shell, mais les commandes sont exécutées dans le même sous-shell.

L'inconvénient de cette méthode est que le fichier est recherché pour chaque cible, ce qui peut être indésirable.

1
Chris

Un autre moyen possible serait de créer un script sh, par exemple run.sh, de rechercher les scripts requis et d'appeler make dans le script. 

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

make 
1
Veera

Selon votre version de Make et le shell englobant, vous pouvez implémenter une solution Nice via eval, cat et le chaînage d'appels avec &&:

ENVFILE=envfile

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

Et un test rapide:

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

Si vous n'avez besoin que de quelques variables connues, l'exportation dans le fichier Make est un exemple, voici un exemple de ce que j'utilise.

$ 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 vous souhaitez obtenir les variables dans environment , afin qu'elles soient transmises aux processus enfants, vous pouvez utiliser les codes set -a et set +a de bash. Le premier signifie "Lorsque je définis une variable, définissez également la variable d'environnement correspondante". Donc ça marche pour moi:

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

Cela passera tout dans .env.test à cargo test en tant que variables d'environnement.

Notez que cela vous permettra de transmettre un environnement à des sous-commandes, mais ne vous laissera pas définir de variables Makefile (qui sont de toute façon différentes). Si vous avez besoin de ce dernier, vous devriez essayer l'une des autres suggestions ici.

0
Paul A Jungwirth