メイクファイル内から環境変数を設定するスクリプトをソースするより良い方法はありますか?
FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) $@'
else
...targets...
endif
質問に答えるには:できません。
基本的な問題は、子プロセスが親の環境を変更できないことです。シェルは、source
'ingのときに新しいプロセスをフォークしないで、これを回避しますが、現在のインカネーションでこれらのコマンドを実行するだけです。シェル。これは正常に機能しますが、make
は/bin/sh
(またはスクリプトのシェル)ではなく、その言語を理解していません(共通する部分は別として)。
Chris DoddとFoo Bahは考えられる回避策の1つに取り組んでいるので、別の方法を提案します(GNU make)を実行している場合:Shellスクリプトを後処理して互換性のあるテキストを作成し、結果を含めます:
Shell-variable-setter.make: Shell-varaible-setter.sh
postprocess.py @^
# ...
else
include Shell-variable-setter.make
endif
演習として残された厄介な詳細。
Makefileのデフォルトのシェルは、source
を実装しない/bin/sh
です。
シェルを/bin/bash
に変更すると、次のことが可能になります。
# Makefile
Shell := /bin/bash
rule:
source env.sh && YourCommand
単にMakeの環境変数を設定することが目的であれば、Makefile構文でそれを維持し、include
コマンドを使用してみませんか?
include other_makefile
シェルスクリプトを呼び出す必要がある場合は、Shell
コマンドで結果をキャプチャします。
JUST_DO_IT=$(Shell source_script)
shellコマンドは、ターゲットの前に実行する必要があります。ただし、これは環境変数を設定しません。
ビルドで環境変数を設定する場合は、環境変数を取得してmakeを呼び出す別のシェルスクリプトを記述します。次に、メイクファイルで、ターゲットが新しいシェルスクリプトを呼び出すようにします。
たとえば、元のmakefileにターゲットa
がある場合、次のようなことを行います。
# 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
GNU Make 3.81を使用すると、makeからシェルスクリプトを取得できます。
rule:
<tab>source source_script.sh && build_files.sh
build_files.shは、source_script.shによってエクスポートされた環境変数を「取得」します。
以下を使用することに注意してください。
rule:
<tab>source source_script.sh
<tab>build_files.sh
動作しないでしょう。各行は、独自のサブシェルで実行されます。
これは私のために動作します。代替env.sh
ソースを取得するファイルの名前。これは、bashでファイルをソーシングし、それをフォーマットした後、変更された環境をmakeenv
と呼ばれるファイルに出力することで機能します。
IGNORE := $(Shell bash -c "source env.sh; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")
include makeenv
いくつかの構造は、Shell
とGNU Make
で同じです。
var=1234
text="Some text"
シェルスクリプトを変更して、定義を取得できます。それらはすべて単純なname=value
型でなければなりません。
すなわち、
[script.sh]
. ./vars.sh
[メイクファイル]
include vars.sh
その後、シェルスクリプトとMakefileは同じ「ソース」の情報を共有できます。この質問を見つけたのは、Gnu MakeおよびShellスクリプトで使用できる一般的な構文のマニフェストを探していたからです(どのShellでも構いません)。
編集:シェルと理解$ {var}。これは、var = "One string" var = $ {var} "Second string"などを連結できることを意味します
Makeがスクリプトを呼び出し、スクリプトがmakeをコールバックするFoo Bahの答えが本当に好きです。その答えを拡張するために、私はこれをしました:
# 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
これには、誰かが一意のmakeプログラムを使用している場合に$(MAKE)を使用するという利点があり、SOME_DIRが定義されていない場合に各ルールの名前を複製することなく、コマンドラインで指定されたルールも処理します。
これに対する私の解決策:(bash
、$@
は、たとえばtcsh
では異なります)
スクリプトを持っているsourceThenExec.sh
、 など:
#!/bin/bash
source whatever.sh
$@
次に、メイクファイルで、ターゲットの前にbash sourceThenExec.sh
、 例えば:
ExampleTarget:
bash sourceThenExec.sh gcc ExampleTarget.C
もちろん、STE=bash sourceThenExec.sh
メイクファイルの先頭で、これを短くします。
ExampleTarget:
$(STE) gcc ExampleTarget.C
これはすべて、sourceThenExec.sh
はサブシェルを開きますが、コマンドは同じサブシェルで実行されます。
この方法の欠点は、ファイルがターゲットごとに取得されることです。これは望ましくない場合があります。
変数をenvironmentに取得して、子プロセスに渡す場合は、bashのset -a
およびset +a
を使用できます。前者は、「変数を設定するときに、対応する環境変数も設定する」という意味です。だからこれは私のために働く:
check:
bash -c "set -a && source .env.test && set +a && cargo test"
これは.env.test
のすべてをcargo test
に環境変数として渡します。
これにより、環境をサブコマンドに渡すことができますが、Makefile変数を設定することはできません(とにかく異なるものです)。後者が必要な場合は、ここで他の提案のいずれかを試してください。
別の可能な方法は、shスクリプトを作成することです。たとえば、run.sh
、必要なスクリプトを入手し、スクリプト内でmakeを呼び出します。
#!/bin/sh
source script1
source script2 and so on
make
使用しているMakeおよびシェルのバージョンに応じて、eval
、cat
、および&&
を使用した呼び出しのチェーンを介してNiceソリューションを実装できます。
ENVFILE=envfile
source-via-eval:
@echo "FOO: $${FOO}"
@echo "FOO=AMAZING!" > $(ENVFILE)
@eval `cat $(ENVFILE)` && echo "FOO: $${FOO}"
そして簡単なテスト:
> make source-via-eval
FOO:
FOO: AMAZING!
Makefileでエクスポートする既知の変数をいくつかしか必要としない場合は、ここで私が使用しているものの例を示します。
$ 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