มีวิธีที่ดีกว่าในการจัดหาสคริปต์ซึ่งตั้งค่า env vars จากภายใน makefile หรือไม่
FLAG ?= 0
ifeq ($(FLAG),0)
export FLAG=1
/bin/myshell -c '<source scripts here> ; $(MAKE) $@'
else
...targets...
endif
มีวิธีที่ดีกว่าในการจัดหาสคริปต์ซึ่งตั้งค่า env vars จากภายใน makefile หรือไม่
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 ได้แก้ไขวิธีแก้ปัญหาที่เป็นไปได้อย่างหนึ่ง ดังนั้นฉันจะแนะนำวิธีอื่น (สมมติว่าคุณกำลังใช้งาน GNU make): โพสต์ประมวลผลเชลล์สคริปต์ให้เป็นข้อความที่เข้ากันได้และรวมผลลัพธ์ไว้ด้วย:
shell-variable-setter.make: shell-varaible-setter.sh
postprocess.py @^
# ...
else
include shell-variable-setter.make
endif
รายละเอียดยุ่งๆ เหลือไว้เป็นแบบฝึกหัด
source compilationEnv.sh; $(CC) -c -o $< $^
หรือคล้ายกันจะใช้เป็นบรรทัดการดำเนินการ
- person dmckee --- ex-moderator kitten; 04.04.2019
include .env
(หรือไฟล์คีย์-ค่าใดก็ได้) เพื่อทำให้ Makefile ทั้งหมดสามารถเข้าถึงตัวแปรได้ จากนั้นจึงส่งเฉพาะตัวแปรที่จำเป็นไปยังสูตรที่เกี่ยวข้อง
- person rypel; 24.08.2019
เชลล์เริ่มต้นของ Makefile คือ /bin/sh
ซึ่งไม่ได้ใช้ source
การเปลี่ยนเชลล์เป็น /bin/bash
ทำให้เป็นไปได้:
# Makefile
SHELL := /bin/bash
rule:
source env.sh && YourCommand
make
และไม่ใช่แค่สำหรับใช้ในบรรทัดการดำเนินการเท่านั้น นี่คือวิธีการทำอย่างหลัง แต่ไม่มีวิธีโดยตรงที่จะทำอย่างหลัง
- person dmckee --- ex-moderator kitten; 10.04.2019
SHELL
เป็น wrapper ของคุณเองได้อย่างง่ายดายเพื่อทำสิ่งนี้ให้สำเร็จ แสดงที่นี่ gist.github.com/ingydotnet/99f7e259319f6b90e50a754f3053be7f
- person ingydotnet; 24.09.2019
หากเป้าหมายของคุณคือเพียงตั้งค่าตัวแปรสภาพแวดล้อมสำหรับ Make ทำไมไม่เก็บไว้ในไวยากรณ์ Makefile และใช้คำสั่ง include
include other_makefile
หากคุณต้องเรียกใช้เชลล์สคริปต์ ให้บันทึกผลลัพธ์ในคำสั่ง shell
:
JUST_DO_IT=$(shell source_script)
คำสั่งเชลล์ควรทำงานก่อนเป้าหมาย อย่างไรก็ตาม สิ่งนี้จะไม่ตั้งค่าตัวแปรสภาพแวดล้อม
หากคุณต้องการตั้งค่าตัวแปรสภาพแวดล้อมในบิลด์ ให้เขียนเชลล์สคริปต์แยกต่างหากที่เป็นแหล่งตัวแปรสภาพแวดล้อมและการเรียกใช้ของคุณ จากนั้นใน makefile ให้เป้าหมายเรียกเชลล์สคริปต์ใหม่
ตัวอย่างเช่น หาก 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
จะไม่ทำงาน. แต่ละบรรทัดจะรันในเชลล์ย่อยของตัวเอง
source
และคำสั่งไว้ในบรรทัดเดียวกันนั้นจำเป็นสำหรับ GNU Make 4.1 (และบางทีอาจเป็น 4.0 ด้วย) การใช้ 3.81 ฉันสามารถใช้บรรทัดที่แตกต่างกันได้ สำหรับการพกพา บรรทัดเดียวใช้ได้กับเวอร์ชันเหล่านี้ การเรียกใช้สคริปต์ภายนอกนั้นสามารถอ่านได้มากขึ้นหากบรรทัดยาวเกินไป!
- person Eric Platon; 12.02.2018
สิ่งนี้ใช้ได้ผลสำหรับฉัน แทนที่ env.sh
ด้วยชื่อไฟล์ที่คุณต้องการแหล่งที่มา มันทำงานโดยการจัดหาไฟล์ใน bash และส่งออกสภาพแวดล้อมที่แก้ไขหลังจากฟอร์แมตแล้ว ไปยังไฟล์ชื่อ makeenv
ซึ่งต่อมามาจาก makefile
IGNORE := $(shell bash -c "source env.sh; env | sed 's/=/:=/' | sed 's/^/export /' > makeenv")
include makeenv
make
.
- person gdw2; 01.10.2019
env.sh
ของคุณมีอักขระ Make พิเศษ เช่น #
หรือ $
เมื่อคุณทำ include makeenv
ค่าเหล่านั้นจะเละเทะไปหมด
- person donhector; 07.02.2020
โครงสร้างบางอย่างเหมือนกันใน shell
และใน GNU Make
var=1234
text="Some text"
คุณสามารถแก้ไขเชลล์สคริปต์ของคุณเพื่อกำหนดแหล่งที่มาได้ ทั้งหมดต้องเป็นประเภท name=value
แบบง่าย
Ie,
[script.sh]
. ./vars.sh
[เมคไฟล์]
include vars.sh
จากนั้นเชลล์สคริปต์และ Makefile สามารถใช้ 'แหล่งที่มา' ของข้อมูลเดียวกันได้ ฉันพบคำถามนี้เพราะฉันกำลังมองหารายการของไวยากรณ์ทั่วไปที่สามารถใช้ใน Gnu Make และเชลล์สคริปต์ได้ (ฉันไม่สนใจว่าเชลล์ใด)
แก้ไข: เชลล์และทำให้เข้าใจ ${var} ซึ่งหมายความว่าคุณสามารถเชื่อมต่อ ฯลฯ var="One string" var=${var} "Second string"
shell
และตัวแปร make
ไม่สามารถใช้แทนกันได้อย่างโปร่งใสเสมอไป เมื่อคุณ include
พวกเขาอยู่ใน Makefile
ของคุณ พวกเขาจะต้องสอดคล้องกับไวยากรณ์ make
ซึ่งกำหนดให้อักขระบางตัวต้องถูกหลีก ตัวอย่างเช่น ค่าตัวแปรเชลล์เช่น SECRET='12#34$56'
ใน .vars.sh
ของคุณจะทำให้คุณเกิดปัญหาเมื่อใช้งานหลังจาก include vars.sh
- person donhector; 07.02.2020
ฉันชอบคำตอบของ 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
$@
จากนั้นใน makefile ของคุณ นำหน้าเป้าหมายของคุณด้วย bash sourceThenExec.sh
เช่น:
ExampleTarget:
bash sourceThenExec.sh gcc ExampleTarget.C
แน่นอนคุณสามารถใส่บางอย่างเช่น STE=bash sourceThenExec.sh
ที่ด้านบนของ makefile ของคุณและย่อให้สั้นลง:
ExampleTarget:
$(STE) gcc ExampleTarget.C
ทั้งหมดนี้ได้ผลเพราะ sourceThenExec.sh
เปิดเชลล์ย่อย แต่คำสั่งต่างๆ จะถูกรันในเชลล์ย่อยเดียวกัน
ข้อเสียของวิธีนี้คือไฟล์ได้รับแหล่งที่มาสำหรับแต่ละเป้าหมายซึ่งอาจไม่เป็นที่พึงปรารถนา
หากคุณต้องการให้ตัวแปรเข้าสู่ สภาพแวดล้อม เพื่อให้ตัวแปรเหล่านั้นถูกส่งไปยังกระบวนการลูก คุณสามารถใช้ set -a
และ set +a
ของ bash แบบแรกหมายถึง "เมื่อฉันตั้งค่าตัวแปร ให้ตั้งค่าตัวแปรสภาพแวดล้อมที่เกี่ยวข้องด้วย" สิ่งนี้ใช้ได้กับฉัน:
check:
bash -c "set -a && source .env.test && set +a && cargo test"
นั่นจะส่งทุกอย่างใน .env.test
ไปยัง cargo test
เป็นตัวแปรสภาพแวดล้อม
โปรดทราบว่าการดำเนินการนี้จะช่วยให้คุณสามารถส่งผ่านสภาพแวดล้อมไปยังคำสั่งย่อยได้ แต่จะไม่อนุญาตให้คุณตั้งค่าตัวแปร Makefile (ซึ่งมีความแตกต่างกันอยู่แล้ว) หากคุณต้องการอย่างหลัง คุณควรลองใช้คำแนะนำอื่นๆ ที่นี่
หากคุณต้องการตัวเลือกตัวแปรที่รู้จักเพียงไม่กี่ตัวที่ส่งออกใน 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
-- http://rzr.online.fr/q/gnumake
ขึ้นอยู่กับเวอร์ชันของ Make และการปิดเชลล์ คุณสามารถใช้โซลูชันที่ดีผ่านทาง eval
, cat
และการโทรแบบผูกมัดด้วย &&
:
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!
พบโซลูชันที่ยอดเยี่ยมได้ที่นี่:
ifneq (,$(wildcard ./.env))
include .env
export
endif
อีกวิธีที่เป็นไปได้คือการสร้างสคริปต์ sh เช่น run.sh
แหล่งที่มาของสคริปต์ที่จำเป็นและการโทรภายในสคริปต์
#!/bin/sh
source script1
source script2 and so on
make
target: output_source
bash ShellScript_name.sh
ลองทำเช่นนี้ มันจะได้ผล สคริปต์อยู่ในไดเร็กทอรีปัจจุบัน