คุณบังคับให้ makefile สร้างเป้าหมายใหม่ได้อย่างไร


184

ฉันมี makefile ที่สร้างแล้วเรียก makefile อื่น เนื่องจาก makefile นี้เรียกใช้ makefiles เพิ่มเติมที่ใช้งานได้จริง ๆ มันจึงไม่เปลี่ยน ดังนั้นจึงยังคงคิดว่าโครงการนี้ถูกสร้างขึ้นและทันสมัย

dnetdev11 ~ # make
make: `release' is up to date.

ฉันจะบังคับให้ makefile สร้างเป้าหมายใหม่ได้อย่างไร

clean = $(MAKE) -f ~/xxx/xxx_compile.workspace.mak clean


build = svn up ~/xxx                                                       \
        $(clean)                                                                \
        ~/cbp2mak/cbp2mak -C ~/xxx ~/xxx/xxx_compile.workspace        \
        $(MAKE) -f ~/xxx/xxx_compile.workspace.mak $(1)                    \


release:
        $(build )

debug:
        $(build DEBUG=1)

clean:
        $(clean)

install:
        cp ~/xxx/source/xxx_utility/release/xxx_util /usr/local/bin
        cp ~/xxx/source/xxx_utility/release/xxxcore.so /usr/local/lib

หมายเหตุ: ลบชื่อเพื่อป้องกันผู้บริสุทธิ์

แก้ไข: รุ่นสุดท้ายคงที่:

clean = $(MAKE) -f xxx_compile.workspace.mak clean;


build = svn up;                                         \
        $(clean)                                        \
        ./cbp2mak/cbp2mak -C . xxx_compile.workspace;   \
        $(MAKE) -f xxx_compile.workspace.mak    $(1);   \


.PHONY: release debug clean install

release:
        $(call build,)

debug:
        $(call build,DEBUG=1)

clean:
        $(clean)

install:
        cp ./source/xxx_utillity/release/xxx_util /usr/bin
        cp ./dlls/Release/xxxcore.so /usr/lib

Lodle เนื่องจากเป็นคำถามที่พบบ่อยคุณต้องการแก้ไขคำถามให้ทันสมัยกว่านี้หรือไม่ (ดูเหมือนว่า.PHONYไม่ใช่ปัญหาเดียวของคุณและคุณไม่ควรแก้ไขคำตอบให้กับคำถามหรืออย่างน้อยก็ไม่ใช่อีกต่อไป)
Keith M

คำตอบ:


23

คุณสามารถประกาศเป้าหมายของคุณอย่างน้อยหนึ่งรายการให้เป็นของปลอมได้

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

...

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


68
คำตอบนี้ในขณะที่มันเป็น "ยอมรับ" และ "upvoted" ที่สูงเป็นสิ่งที่ผิด ก่อนอื่นมันบอกว่า "ประกาศเป้าหมายเป็นของปลอม" แต่แล้วมันก็บอกว่า "เป้าหมายของปลอมนั้นไม่ใช่ชื่อของไฟล์" ถ้าเป้าหมายของคุณคือไฟล์นั่นคือความขัดแย้งในคำตอบ ข้อที่สองมันบอกว่า "เป้าหมายของปลอมไม่ควรเป็นข้อกำหนดเบื้องต้นของจริง" - ถ้าเป็นเช่นนั้นจะเกิดอะไรขึ้น? คำถามเดิมไม่ได้ระบุว่ามันเป็นหรือไม่ คำตอบที่ถูกต้องคือไม่ประกาศเป้าหมายของคุณว่าเป็นของปลอม แต่ให้ประกาศเป้าหมายปลอมเพิ่มเติมจากนั้นขึ้นอยู่กับเป้าหมายที่คุณต้องการสร้างขึ้นมาใหม่
Mark Galeck

2
@MarkGaleck เมื่อคำตอบระบุว่า "เป้าหมายของปลอมเป็นสิ่งที่ไม่ใช่ชื่อของไฟล์" มันเป็นการอ้างอิงโดยตรงจาก gcc ทำให้เป็นคู่มือ มันถูกต้องสมบูรณ์แบบ
drlolly

"Target" เป็นคำ Make ที่อ้างถึงข้อความทางด้านซ้ายของโคลอน:ไม่ใช่แค่ผลลัพธ์สุดท้ายที่คุณต้องการสร้าง (เช่นไฟล์ไบนารีของคุณ) ในคำถามrelease, debug, cleanและinstallมีเป้าหมายทำไม่ได้xxx_utilหรือxxxcore.soหรือสิ่งอื่นใด
Keith M

728

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


4
@ MarkKCowan ฉันเห็นด้วยอย่างสมบูรณ์! ตัวเลือกนี้เป็นสิ่งที่ฉันกำลังมองหาไม่ใช่การแฮ็กบางอย่างตามที่ Dave แนะนำ
Maarten Bamelis

8
ข้อแม้ที่ใช้วิธีการนี้คือมันแค่สร้างสิ่งต่างๆมากมาย โดยเฉพาะกับเครื่องมืออัตโนมัติฉันเห็นว่ากำหนดค่าซ้ำแล้วซ้ำอีก .. ฉันหวังว่าจะสามารถสร้างโซลูชันที่ใช้ LD_PRELOAD ได้ !!
vrdhn

ใช่และมันยังสามารถเขียนไฟล์ที่คุณไม่ต้องการ! เช่นไลบรารีระบบส่วนกลางที่ปรากฏในการขึ้นต่อกันและสร้างใหม่และเขียนทับ ...
Julio Guerra

18

เคล็ดลับหนึ่งที่เคยบันทึกไว้ในคู่มือการใช้งานของซันmakeคือการใช้เป้าหมาย '.FORCE' (ไม่มีอยู่จริง) คุณสามารถทำได้โดยการสร้างไฟล์ force.mk ที่มี:

.FORCE:
$(FORCE_DEPS): .FORCE

จากนั้นสมมติว่า makefile ที่มีอยู่ของคุณถูกเรียกmakefileคุณสามารถเรียกใช้:

make FORCE_DEPS=release -f force.mk -f makefile release

เนื่องจาก.FORCEไม่มีอยู่สิ่งที่ขึ้นอยู่กับมันจะล้าสมัยและสร้างใหม่

ทั้งหมดนี้จะใช้ได้กับเวอร์ชันใด ๆ ของmake; บน Linux คุณมี GNU Make และสามารถใช้เป้าหมาย. PHONY ตามที่กล่าวไว้

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


14

มีคนอื่นแนะนำ. PHONY ซึ่งถูกต้องแน่นอน .PHONY ควรใช้สำหรับกฎใด ๆ ที่การเปรียบเทียบวันที่ระหว่างอินพุตกับเอาต์พุตไม่ถูกต้อง เนื่องจากคุณไม่มีเป้าหมายใด ๆ ของแบบฟอร์มoutput: inputคุณควรใช้. PHONY สำหรับพวกเขาทั้งหมด!

จากทั้งหมดที่กล่าวมาคุณควรกำหนดตัวแปรบางตัวที่ด้านบนของ makefile สำหรับชื่อไฟล์ต่าง ๆ และกำหนดกฎการสร้างจริงที่มีทั้งส่วนอินพุตและเอาต์พุตเพื่อให้คุณสามารถใช้ประโยชน์จาก make คือกล่าวคือคุณจะรวบรวมเท่านั้น สิ่งที่จำเป็นในการ copmile!

แก้ไข: เพิ่มตัวอย่าง ยังไม่ทดลอง แต่นี่เป็นวิธีการที่คุณทำ

.PHONY: clean    
clean:
    $(clean)

1
ถ้าคุณแสดงตัวอย่างให้ฉันฟังได้มันคงจะดี Atm im เพิ่งแฮ็คมันเพื่อพยายามทำให้เขื่อนทำงาน: P
Lodle

1
ตำแหน่งของ.PHONYเป้าหมายไม่สำคัญ Makefileมันอาจจะเป็นที่ใดก็ได้ใน
เอเดรียน

5

หากฉันจำได้อย่างถูกต้อง 'ทำให้' ใช้การประทับเวลา (เวลาแก้ไขไฟล์) เพื่อตรวจสอบว่าเป้าหมายเป็นปัจจุบันหรือไม่ วิธีทั่วไปในการบังคับให้สร้างใหม่คือการอัพเดตเวลาประทับนั้นโดยใช้คำสั่ง 'touch' คุณสามารถลองเรียกใช้ 'touch' ใน makefile ของคุณเพื่ออัปเดตการประทับเวลาของหนึ่งในเป้าหมาย (อาจเป็นหนึ่งใน sub-makefiles เหล่านั้น) ซึ่งอาจบังคับให้ Make เรียกใช้คำสั่งนั้น


5

เทคนิคง่าย ๆ นี้จะอนุญาตให้ makefile ทำงานตามปกติเมื่อไม่ต้องการบังคับใช้ สร้างเป้าหมายใหม่ที่เรียกว่าแรงในตอนท้ายของคุณMakefile แรงเป้าหมายจะสัมผัสแฟ้มที่เป้าหมายเริ่มต้นของคุณขึ้นอยู่กับ ในตัวอย่างด้านล่างผมได้เพิ่มmyprogram.cpp สัมผัส ฉันยังเพิ่มโทร recursive ทำให้ นี้จะทำให้เป้าหมายเริ่มต้นจะได้รับการทำทุกครั้งที่คุณพิมพ์แรงทำให้

yourProgram: yourProgram.cpp
       g++ -o yourProgram yourProgram.cpp 

force:
       touch yourProgram.cpp
       make

คุณไม่ควรใช้makeใน Makefile ใช้$(MAKE)แทน
Benjamin Crawford Ctrl-Alt-Tut

3

ฉันลองสิ่งนี้และมันก็ได้ผลสำหรับฉัน

เพิ่มบรรทัดเหล่านี้ใน Makefile

clean:
    rm *.o output

new: clean
    $(MAKE)     #use variable $(MAKE) instead of make to get recursive make calls

บันทึกและโทรตอนนี้

make new 

และมันจะรวบรวมทุกอย่างอีกครั้ง

เกิดอะไรขึ้น?

1) การโทร 'ใหม่' สะอาด 'clean' do 'rm' ซึ่งจะลบไฟล์อ็อบเจ็กต์ทั้งหมดที่มีนามสกุลเป็น '.o'

2) 'การโทร' ใหม่ 'ทำการ' 'ทำให้' ดูว่าไม่มีไฟล์ '.o' ดังนั้นมันจะสร้าง '.o' ทั้งหมดอีกครั้ง จากนั้นตัวลิงก์จะลิงก์ไฟล์. o ทั้งหมดหนึ่งเอาต์พุตที่สามารถเรียกใช้งานได้

โชคดี


1
ในสูตรสำหรับการnewใช้งานที่ดี$(MAKE)กว่าmake
Basile Starynkevitch

1

ตามการเรียกซ้ำของมิลเลอร์ถือว่าเป็นอันตรายคุณควรหลีกเลี่ยงการโทร$(MAKE)! ในกรณีที่คุณแสดงมันไม่เป็นอันตรายเพราะนี่ไม่ใช่ makefile จริง ๆ เป็นเพียงสคริปต์ตัวหุ้มซึ่งอาจถูกเขียนใน Shell ด้วยเช่นกัน แต่คุณบอกว่าคุณทำต่อไปเช่นนั้นในระดับการเรียกซ้ำที่ลึกกว่าดังนั้นคุณอาจพบปัญหาที่แสดงในบทความที่เปิดหูเปิดตา

แน่นอนด้วย GNU ทำให้ยุ่งยากในการหลีกเลี่ยง และถึงแม้ว่าพวกเขาจะตระหนักถึงปัญหานี้ แต่มันเป็นวิธีการทำเอกสารของพวกเขา

OTOH, makeppถูกสร้างขึ้นเพื่อแก้ปัญหานี้ คุณสามารถเขียน makefiles ของคุณในระดับไดเรกทอรีต่อ แต่พวกเขาทั้งหมดได้รับการดึงเข้าด้วยกันเป็นมุมมองแบบเต็มของโครงการของคุณ

แต่ makefiles มรดกถูกเขียนซ้ำ ดังนั้นจึงมีวิธีการแก้ปัญหาที่$(MAKE)ไม่ทำอะไรเลยนอกจากจะทำช่องทางการย่อยย่อยกลับไปที่กระบวนการแต่งหน้าหลัก เฉพาะในกรณีที่คุณทำสิ่งที่ซ้ำซ้อนหรือแย่กว่านั้นในระหว่างการส่งผลงานคุณจะต้องขอ--traditional-recursive-make(ซึ่งแน่นอนว่าข้อได้เปรียบของ makepp นี้) ฉันไม่รู้จัก makefiles อื่น ๆ ของคุณ แต่ถ้าพวกเขาเขียนอย่างหมดจดกับ makepp ที่จำเป็นต้องมีการสร้างใหม่ควรจะเกิดขึ้นโดยอัตโนมัติโดยไม่จำเป็นต้องมีแฮ็กใด ๆ


ไม่ได้ตอบคำถาม: แทนเจนต์ถึงประเด็นหลักและควรเป็นความคิดเห็นไม่ใช่คำตอบ
flungo

บางทีฉันอาจจะไม่ชัดเจนพอ ด้วยmakepp makefile wrapper ทั้งหมดนี้ไม่จำเป็น โดยการรู้ถึงการพึ่งพาที่แน่นอน (ทั้งหมดนั้นไม่ใช่เฉพาะสิ่งที่อยู่ในรายการหลังจากนั้น:) มันจะสร้างใหม่เมื่อจำเป็น
แดเนียล

1

หากคุณไม่จำเป็นต้องเก็บรักษาเอาท์พุทใด ๆ ที่คุณรวบรวมเรียบร้อยแล้ว

nmake /A 

สร้างใหม่ทั้งหมด


0

มันขึ้นอยู่กับว่าเป้าหมายคืออะไร หากเป็นเป้าหมายปลอม (เช่นเป้าหมายไม่เกี่ยวข้องกับไฟล์) คุณควรประกาศว่าเป็น. PHYY

หากเป้าหมายไม่ได้เป็นของปลอม แต่คุณต้องการสร้างใหม่ด้วยเหตุผลบางอย่าง (ตัวอย่างคือเมื่อคุณใช้มาโครการประมวลผลล่วงหน้า __TIME__) คุณควรใช้ FORCE Scheme ที่อธิบายไว้ในคำตอบที่นี่



0

มันถูกกล่าวถึงแล้ว แต่คิดว่าฉันสามารถเพิ่มการใช้ touch

หากคุณtouchไฟล์ต้นฉบับทั้งหมดที่จะรวบรวมtouchคำสั่งจะเปลี่ยนการประทับเวลาของไฟล์เป็นเวลาของระบบที่touchคำสั่งถูกดำเนินการ

timstamp ไฟล์ต้นฉบับคือสิ่งที่makeใช้ในการ "รู้" ไฟล์ที่มีการเปลี่ยนแปลงและจะต้องรวบรวมใหม่

ตัวอย่างเช่น: หากโครงการเป็นโครงการ c ++ ให้ทำtouch *.cppแล้วเรียกใช้makeอีกครั้งและทำให้ควรคอมไพล์โครงการใหม่ทั้งหมด


0

ตามที่ระบุไว้ abernier มีคำแนะนำในคู่มือการทำ GNU ซึ่งใช้เป้าหมาย 'ปลอม' เพื่อบังคับให้สร้างเป้าหมายใหม่

clean: FORCE
        rm $(objects)
FORCE: ; 

การดำเนินการนี้จะสะอาดโดยไม่คำนึงถึงการพึ่งพาอื่น ๆ

ฉันเพิ่มเซมิโคลอนลงในโซลูชันจากคู่มือมิฉะนั้นต้องมีบรรทัดว่าง


-1

บนระบบ Linux ของฉัน (Centos 6.2) มีความแตกต่างอย่างมีนัยสำคัญระหว่างการประกาศเป้าหมาย. PHONY และการสร้างการอ้างอิงปลอมบน FORCE เมื่อกฎจริงสร้างไฟล์ที่ตรงกับเป้าหมาย เมื่อไฟล์นั้นจะต้องถูกสร้างใหม่ทุกครั้งมันจำเป็นต้องมีทั้งการพึ่งพาปลอมในไฟล์และ. PHONY สำหรับการพึ่งพาปลอม

ไม่ถูกต้อง:

date > $@

ขวา:

FORCE
    date > $@
FORCE:
    .PHONY: FORCE

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