การส่งตัวแปรเพิ่มเติมจากบรรทัดคำสั่งเพื่อสร้าง


614

ฉันสามารถส่งตัวแปรไปยัง GNU Makefile เป็นอาร์กิวเมนต์บรรทัดคำสั่งได้หรือไม่ กล่าวอีกนัยหนึ่งฉันต้องการผ่านการขัดแย้งบางอย่างซึ่งในที่สุดจะกลายเป็นตัวแปรใน Makefile

คำตอบ:


753

คุณมีหลายตัวเลือกในการตั้งค่าตัวแปรจากนอก makefile ของคุณ:

  • From environment - แต่ละตัวแปรสภาพแวดล้อมจะถูกแปลงเป็นตัวแปร makefile ด้วยชื่อและค่าเดียวกัน

    คุณอาจต้องการตั้งค่า-eตัวเลือก (aka --environments-override) และตัวแปรสภาพแวดล้อมของคุณจะแทนที่การมอบหมายที่ทำไว้ใน makefile (ยกเว้นว่าการมอบหมายเหล่านี้ใช้overrideคำสั่งอย่างไรก็ตามไม่แนะนำให้ใช้และจะดีกว่าและยืดหยุ่นกว่าในการใช้การ?=มอบหมาย ผู้ประกอบการที่ได้รับมอบหมายมันจะมีผลเฉพาะถ้าตัวแปรยังไม่ได้กำหนด):

    FOO?=default_value_if_not_set_in_environment
    

    โปรดทราบว่าตัวแปรบางอย่างไม่ได้รับมาจากสภาพแวดล้อม:

    • MAKE ได้มาจากชื่อของสคริปต์
    • SHELLถูกตั้งค่าภายใน makefile หรือค่าเริ่มต้นเป็น/bin/sh(เหตุผล: คำสั่งถูกระบุไว้ใน makefile และพวกเขากำลังเฉพาะเชลล์)
  • จากบรรทัดคำสั่ง - makeสามารถรับการกำหนดตัวแปรเป็นส่วนหนึ่งของบรรทัดคำสั่งของเขาผสมกับเป้าหมาย:

    make target FOO=bar
    

    แต่การมอบหมายทั้งหมดให้กับFOOตัวแปรภายใน makefile จะถูกละเว้นเว้นแต่คุณจะใช้overrideคำสั่งในการมอบหมาย (เอฟเฟกต์เหมือนกับ-eตัวเลือกสำหรับตัวแปรสภาพแวดล้อม)

  • การส่งออกจาก Make หลัก - ถ้าคุณเรียกใช้ Make จาก Makefile โดยปกติคุณไม่ควรเขียนการกำหนดตัวแปรอย่างชัดเจนดังนี้:

    # Don't do this!
    target:
            $(MAKE) -C target CC=$(CC) CFLAGS=$(CFLAGS)
    

    แต่ทางออกที่ดีกว่าคือการส่งออกตัวแปรเหล่านี้ การส่งออกตัวแปรทำให้เป็นสภาพแวดล้อมของการเรียกใช้เชลล์ทุกครั้งและการโทรจากคำสั่งเหล่านี้จะเลือกตัวแปรสภาพแวดล้อมเหล่านี้ตามที่ระบุไว้ข้างต้น

    # Do like this
    CFLAGS=-g
    export CFLAGS
    target:
            $(MAKE) -C target
    

    คุณสามารถส่งออกตัวแปรทั้งหมดโดยใช้exportโดยไม่มีอาร์กิวเมนต์


10
ที่จะผ่านจากบรรทัดคำสั่งสิ่งที่มีช่องว่างทำmake A='"as df"'
Ciro Santilli 法轮功冠状病六四事件法轮功

4
ดูเหมือนว่าคุณกำลังถามปัญหาหากคุณใส่ใจกับตัวแปรสภาพแวดล้อม สำหรับสิ่งหนึ่งมันเป็นฝันร้ายในการดีบั๊กถ้ามันทำงานในสถานที่ A และไม่ได้อยู่ในสถานที่ B เพียงเพราะมีสภาพแวดล้อมที่แตกต่างกัน
James Moore

12
เพียงแค่มีประสบการณ์การส่งออกสิ่งต่าง ๆ เช่น CFLAGS เป็นสูตรสำหรับฝันร้ายสำหรับโครงการขนาดใหญ่ โครงการขนาดใหญ่มักจะมีห้องสมุดบุคคลที่สามที่รวบรวมเฉพาะชุดธงที่กำหนด (ซึ่งไม่มีใครรบกวนจิตใจได้) หากคุณส่งออก CFLAGS CFLAGS ของโครงการของคุณจะจบลงด้วยการแทนที่ไลบรารี่ของบุคคลที่สามและทำให้เกิดข้อผิดพลาดในการคอมไพล์ อีกทางหนึ่งอาจจะมีการกำหนดและผ่านมันไปเป็นexport PROJECT_MAKE_ARGS = CC=$(CC) CFLAGS=$(CFLAGS) make -C folder $(PROJECT_MAKE_FLAGS)หากมีวิธีที่จะบอกให้ makefile ของห้องสมุดเพิกเฉยต่อสภาพแวดล้อมนั่นจะเป็นอุดมคติ (ตรงข้ามกับ -e)
RD

24
คำเตือน: ในส่วน "การส่งออกจากยี่ห้อหลัก" ด้านบน "อย่าทำอย่างนี้!" เป็นอย่างยิ่งที่ทำให้เข้าใจผิด การส่งตัวแปรในบรรทัดคำสั่งจะแทนที่การกำหนดใน sub-makefile แต่ตัวแปรที่ส่งออกจะไม่แทนที่การกำหนดใน sub-makefile ทั้งสองวิธีสำหรับการส่งผ่านตัวแปรไปยัง sub-makefile นั้นไม่เท่ากันและไม่ควรสับสน
Jonathan Ben-Avraham

4
ความแตกต่างใด ๆ make target FOO=bar make FOO=bar target?
gfan

213

วิธีที่ง่ายที่สุดคือ:

make foo=bar target

จากนั้นใน Makefile $(foo)ของคุณคุณสามารถอ้างถึง โปรดทราบว่าสิ่งนี้จะไม่เผยแพร่ไปยังการย่อยโดยอัตโนมัติ

หากคุณกำลังใช้งานย่อยทำดูบทความนี้: การสื่อสารตัวแปรเพื่อทำย่อย


2
โดยย่อยทำให้คุณหมายถึง makefiles includedใน makefile หลักหรือไม่
Pablo

2
@Michael: มันหมายถึงการเรียก make อีกครั้งจากภายใน makefile ฉันได้อัปเดตคำตอบของฉันแล้วเนื่องจากคุณสนใจรายละเอียดนี้
Mark Byers

2
"โปรดทราบว่าสิ่งนี้จะไม่เผยแพร่ไปยังการย่อยโดยอัตโนมัติ" ไม่จริง! "โดยค่าเริ่มต้นเฉพาะตัวแปรที่มาจากสภาพแวดล้อมหรือบรรทัดคำสั่งจะถูกส่งผ่านไปยังการเรียกซ้ำคุณสามารถใช้คำสั่งส่งออกเพื่อส่งผ่านตัวแปรอื่น ๆ ได้" gnu.org/software/make/manual/html_node/…
ThomasMcLeod

82

สมมติว่าคุณมี makefile เช่นนี้:

action:
    echo argument is $(argument)

จากนั้นคุณจะเรียกมันว่า make action argument=something


5
ดังนั้นเป้าหมายและข้อโต้แย้งสามารถถูกสับเปลี่ยนในแง่ของตำแหน่ง?
Pablo

4
@Michael: ใช่ (ดูคำตอบของ Mark Byers)
nc3b

25

จากคู่มือ :

ตัวแปรใน make อาจมาจากสภาพแวดล้อมที่ make ถูกเรียกใช้ ตัวแปรสภาพแวดล้อมทุกตัวที่ทำให้เห็นเมื่อเริ่มต้นจะถูกแปลงเป็นตัวแปรทำให้มีชื่อและค่าเหมือนกัน อย่างไรก็ตามการกำหนดอย่างชัดเจนใน makefile หรือด้วยอาร์กิวเมนต์คำสั่งแทนที่สภาพแวดล้อม

ดังนั้นคุณสามารถทำได้ (จาก bash):

FOOBAR=1 make

ส่งผลให้ตัวแปรFOOBARใน Makefile ของคุณ


2
วิธีอื่นดีกว่าแน่นอนในเกือบทุกกรณี ฉันจะออกจากที่นี่เพื่อความสมบูรณ์
โทมัส

นี่เป็นคำตอบเดียวที่แสดงการกำหนดตัวแปรก่อนคำสั่ง make ในบรรทัดเดียวกัน - มันคุ้มค่าที่จะรู้ว่านี่ไม่ใช่ข้อผิดพลาดทางไวยากรณ์
M_M

7

มีตัวเลือกอื่นที่ไม่ได้อ้างถึงที่นี่ซึ่งรวมอยู่ใน GNU Make book โดย Stallman และ McGrath (ดูhttp://www.chemie.fu-berlin.de/chemnet/use/info/make/make_7.html ) มันมีตัวอย่าง:

archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
        +touch archive.a
        +ranlib -t archive.a
else
        ranlib archive.a
endif

MAKEFLAGSมันเกี่ยวข้องกับการตรวจสอบถ้าพารามิเตอร์ให้ปรากฏใน ตัวอย่างเช่น .. สมมติว่าคุณกำลังศึกษาเกี่ยวกับเธรดใน c ++ 11 และคุณแบ่งการศึกษาของคุณออกเป็นหลายไฟล์ ( class01, ... , classNM) และคุณต้องการ: คอมไพล์แล้วทั้งหมดและเรียกใช้ทีละรายการหรือคอมไพล์ที่ เวลาและรันหากระบุแฟล็ก ( -rตัวอย่างเช่น) ดังนั้นคุณสามารถคิดสิ่งต่อไปนี้Makefile:

CXX=clang++-3.5
CXXFLAGS = -Wall -Werror -std=c++11
LDLIBS = -lpthread

SOURCES = class01 class02 class03

%: %.cxx
    $(CXX) $(CXXFLAGS) -o $@.out $^ $(LDLIBS)
ifneq (,$(findstring r,  $(MAKEFLAGS)))
    ./$@.out
endif

all: $(SOURCES)

.PHONY: clean

clean:
    find . -name "*.out" -delete

คุณมี:

  • สร้างและเรียกใช้ไฟล์ w / make -r class02;
  • สร้างทั้งหมดด้วย / makeหรือmake all;
  • สร้างและเรียกใช้ w / ทั้งหมดmake -r(สมมติว่าพวกเขาทั้งหมดมีเนื้อหายืนยันบางประเภทและคุณต้องการทดสอบทั้งหมด)

6

มันดูเหมือน

คำสั่ง args เขียนทับตัวแปรสภาวะแวดล้อม

Makefile

send:
    echo $(MESSAGE1) $(MESSAGE2)

เรียกใช้ตัวอย่าง

$ MESSAGE1=YES MESSAGE2=NG  make send MESSAGE2=OK
echo YES OK
YES OK

5

หากคุณสร้างไฟล์ชื่อ Makefile และเพิ่มตัวแปรเช่น $ (unittest) คุณจะสามารถใช้ตัวแปรนี้ใน Makefile ได้แม้จะมีสัญลักษณ์แทน

ตัวอย่าง:

make unittest=*

ฉันใช้ BOOST_TEST และให้การแทนที่สัญลักษณ์กับพารามิเตอร์ --run_test = $ (ไม่ตอบ) แล้วฉันจะสามารถใช้นิพจน์ทั่วไปเพื่อกรองการทดสอบที่ฉันต้องการให้ Makefile ทำงาน


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.