Apakah ada cara yang lebih baik untuk mendapatkan skrip, yang menetapkan env vars, dari dalam makefile?
FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) $@'
else
...targets...
endif
Apakah ada cara yang lebih baik untuk mendapatkan skrip, yang menetapkan env vars, dari dalam makefile?
FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) $@'
else
...targets...
endif
Untuk menjawab pertanyaan seperti yang ditanyakan: Anda tidak bisa.
Masalah mendasarnya adalah bahwa proses anak tidak dapat mengubah lingkungan induknya. Shell mengatasi hal ini dengan tidak melakukan forking proses baru saat source
'ing, namun hanya menjalankan perintah tersebut dalam inkarnasi shell saat ini. Itu berfungsi dengan baik, tetapi make
bukan /bin/sh
(atau apa pun shell skrip Anda) dan tidak memahami bahasa itu (selain kesamaan yang mereka miliki).
Chris Dodd dan Foo Bah telah membahas satu kemungkinan solusi, jadi saya akan menyarankan solusi lain (dengan asumsi Anda menjalankan GNU make): proses pasca skrip shell menjadi teks yang kompatibel dan sertakan hasilnya:
shell-variable-setter.make: shell-varaible-setter.sh
postprocess.py @^
# ...
else
include shell-variable-setter.make
endif
detail berantakan dibiarkan sebagai latihan.
source compilationEnv.sh; $(CC) -c -o $< $^
atau serupa akan berfungsi sebagai garis tindakan.
- person dmckee --- ex-moderator kitten; 04.04.2019
include .env
(atau file nilai kunci apa pun) untuk membuat variabel dapat diakses oleh seluruh Makefile dan kemudian hanya meneruskan variabel yang diperlukan ke dalam resep masing-masing.
- person rypel; 24.08.2019
Shell default Makefile adalah /bin/sh
yang tidak mengimplementasikan source
.
Mengubah shell menjadi /bin/bash
memungkinkan:
# Makefile
SHELL := /bin/bash
rule:
source env.sh && YourCommand
make
dan bukan hanya untuk digunakan dalam baris tindakan. Ini adalah cara melakukan yang terakhir, namun tidak ada cara langsung untuk melakukan yang pertama.
- person dmckee --- ex-moderator kitten; 10.04.2019
SHELL
ke pembungkus Anda sendiri untuk mencapai hal ini. Tampil di sini gist.github.com/ingydotnet/99f7e259319f6b90e50a754f3053be7f
- person ingydotnet; 24.09.2019
Jika tujuan Anda hanya menyetel variabel lingkungan untuk Make, mengapa tidak menyimpannya dalam sintaksis Makefile dan menggunakan perintah include
?
include other_makefile
Jika Anda harus menjalankan skrip shell, ambil hasilnya dalam perintah shell
:
JUST_DO_IT=$(shell source_script)
perintah shell harus dijalankan sebelum target. Namun ini tidak akan mengatur variabel lingkungan.
Jika Anda ingin mengatur variabel lingkungan dalam build, tulis skrip shell terpisah yang menjadi sumber variabel lingkungan dan panggilan Anda. Kemudian, di makefile, minta target memanggil skrip shell baru.
Misalnya, jika makefile asli Anda memiliki target a
, maka Anda ingin melakukan sesuatu seperti ini:
# 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
Menggunakan GNU Make 3.81 saya dapat mengambil skrip shell dari make menggunakan:
rule:
<tab>source source_script.sh && build_files.sh
build_files.sh "mendapatkan" variabel lingkungan yang diekspor oleh source_script.sh.
Perhatikan bahwa menggunakan:
rule:
<tab>source source_script.sh
<tab>build_files.sh
Tidak akan berhasil. Setiap baris dijalankan dalam subkulitnya sendiri.
source
dan perintah pada baris yang sama menjadi penting dengan GNU Make 4.1 (dan mungkin 4.0 juga). Menggunakan 3.81, saya dapat menggunakan baris yang berbeda. Untuk portabilitas, satu baris berfungsi di seluruh versi ini. Namun, menjalankan skrip eksternal lebih mudah dibaca jika barisnya menjadi terlalu panjang!
- person Eric Platon; 12.02.2018
Ini berhasil untuk saya. Gantikan env.sh
dengan nama file yang ingin Anda jadikan sumber. Ia bekerja dengan mengambil sumber file di bash dan mengeluarkan lingkungan yang dimodifikasi, setelah memformatnya, ke file bernama makeenv
yang kemudian bersumber dari makefile.
IGNORE := $(shell bash -c "source env.sh; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")
include makeenv
env.sh
Anda berisi karakter Make khusus seperti #
atau $
. Ketika Anda melakukan include makeenv
nilai-nilai itu akan menjadi kacau.
- person donhector; 07.02.2020
Beberapa konstruksi sama di shell
dan GNU Make
.
var=1234
text="Some text"
Anda dapat mengubah skrip shell Anda untuk menentukan sumbernya. Semuanya harus tipe name=value
sederhana.
Ie,
[skrip.sh]
. ./vars.sh
[Makefile]
include vars.sh
Kemudian skrip shell dan Makefile dapat berbagi 'sumber' informasi yang sama. Saya menemukan pertanyaan ini karena saya sedang mencari manifes sintaksis umum yang dapat digunakan dalam skrip Gnu Make dan shell (saya tidak peduli shell yang mana).
Edit: Kerang dan pahami ${var}. Ini berarti Anda dapat menggabungkan, dll, var="One string" var=${var} "Second string"
shell
dan variabel make
tidak selalu dapat dipertukarkan secara transparan. Saat Anda include
di Makefile
Anda, mereka harus mematuhi sintaks make
, yang mengharuskan karakter tertentu untuk di-escape. Misalnya nilai variabel shell seperti SECRET='12#34$56'
di .vars.sh
Anda akan menyebabkan masalah saat menggunakannya setelah include vars.sh
- person donhector; 07.02.2020
Saya sangat suka jawaban Foo Bah di mana skrip dipanggil, dan skrip dipanggil kembali untuk dibuat. Untuk memperluas jawaban itu saya melakukan ini:
# 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
Ini memiliki keuntungan tambahan menggunakan $(MAKE) jika ada orang yang menggunakan program make yang unik, dan juga akan menangani aturan apa pun yang ditentukan pada baris perintah, tanpa harus menduplikasi nama setiap aturan jika SOME_DIR tidak ditentukan .
Solusi saya untuk ini: (dengan asumsi Anda memiliki bash
, sintaks untuk $@
berbeda untuk tcsh
misalnya)
Miliki skrip sourceThenExec.sh
, seperti:
#!/bin/bash
source whatever.sh
$@
Kemudian, di makefile Anda, awali target Anda dengan bash sourceThenExec.sh
, misalnya:
ExampleTarget:
bash sourceThenExec.sh gcc ExampleTarget.C
Anda tentu saja dapat meletakkan sesuatu seperti STE=bash sourceThenExec.sh
di bagian atas makefile Anda dan mempersingkatnya:
ExampleTarget:
$(STE) gcc ExampleTarget.C
Semua ini berfungsi karena sourceThenExec.sh
membuka subkulit, tetapi kemudian perintah dijalankan di subkulit yang sama.
Kelemahan dari metode ini adalah file tersebut diambil dari setiap target, yang mungkin tidak diinginkan.
Jika Anda ingin memasukkan variabel ke dalam lingkungan, sehingga variabel tersebut diteruskan ke proses anak, maka Anda dapat menggunakan set -a
dan set +a
bash. Yang pertama berarti, "Saat saya menyetel variabel, setel juga variabel lingkungan yang sesuai." Jadi ini berfungsi untuk saya:
check:
bash -c "set -a && source .env.test && set +a && cargo test"
Itu akan meneruskan semuanya di .env.test
ke cargo test
sebagai variabel lingkungan.
Perhatikan bahwa ini akan memungkinkan Anda meneruskan lingkungan ke sub-perintah, tetapi tidak memungkinkan Anda menyetel variabel Makefile (yang merupakan hal yang berbeda). Jika Anda memerlukan yang terakhir, Anda harus mencoba salah satu saran lain di sini.
Jika Anda hanya memerlukan beberapa variabel yang diketahui, mengekspor dalam makefile dapat menjadi pilihan, berikut adalah contoh yang saya gunakan.
$ 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
Bergantung pada versi Make dan shell yang disertakan, Anda dapat menerapkan solusi yang bagus melalui eval
, cat
, dan panggilan berantai dengan &&
:
ENVFILE=envfile
source-via-eval:
@echo "FOO: $${FOO}"
@echo "FOO=AMAZING!" > $(ENVFILE)
@eval `cat $(ENVFILE)` && echo "FOO: $${FOO}"
Dan tes cepat:
> make source-via-eval
FOO:
FOO: AMAZING!
Solusi elegan dapat ditemukan di sini:
ifneq (,$(wildcard ./.env))
include .env
export
endif
Cara lain yang mungkin adalah dengan membuat skrip sh, misalnya run.sh
, sumber skrip yang diperlukan dan panggil make di dalam skrip.
#!/bin/sh
source script1
source script2 and so on
make
target: output_source
bash ShellScript_name.sh
coba ini akan berhasil, skrip ada di dalam direktori saat ini.