ภาษาอังกฤษภาษาฝรั่งเศสสเปน

Ad


ไอคอน Fav ของ OnWorks

makepp_cookbook - ออนไลน์ในคลาวด์

เรียกใช้ makepp_cookbook ในผู้ให้บริการโฮสต์ฟรีของ OnWorks ผ่าน Ubuntu Online, Fedora Online, โปรแกรมจำลองออนไลน์ของ Windows หรือโปรแกรมจำลองออนไลน์ของ MAC OS

นี่คือคำสั่ง makepp_cookbook ที่สามารถเรียกใช้ในผู้ให้บริการโฮสติ้งฟรีของ OnWorks โดยใช้หนึ่งในเวิร์กสเตชันออนไลน์ฟรีของเรา เช่น Ubuntu Online, Fedora Online, โปรแกรมจำลองออนไลน์ของ Windows หรือโปรแกรมจำลองออนไลน์ของ MAC OS

โครงการ:

ชื่อ


makepp_cookbook -- วิธีที่ดีที่สุดในการตั้งค่า makefiles สำหรับสถานการณ์ต่างๆ

DESCRIPTION


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

การก่อสร้าง ห้องสมุด
Do เธอ จริงๆ จำเป็นต้อง a ห้องสมุด?

ฉันได้เห็นโปรแกรมขนาดใหญ่จำนวนหนึ่งซึ่งประกอบด้วยโมดูลจำนวนมาก แต่ละโปรแกรม
ซึ่งอยู่ในไดเร็กทอรีของตัวเอง โดยทั่วไป แต่ละไดเร็กทอรีจะถูกใส่ลงในไลบรารีของตัวเอง
จากนั้นโปรแกรมสุดท้ายจะเชื่อมโยงกับไลบรารีทั้งหมด

ในหลายกรณี ฉันคิดว่าแทนที่จะใช้ห้องสมุด มีแนวทางที่ดีกว่า ห้องสมุด
ไม่ใช่วิธีแก้ปัญหาที่ถูกต้องจริง ๆ หากแต่ละโมดูลไม่สามารถหรือจะไม่ถูกนำมาใช้ซ้ำในโมดูลอื่น ๆ
โปรแกรมเพราะคุณจะได้รับข้อเสียทั้งหมดของไลบรารีและไม่มี
ข้อดี. ห้องสมุดมีประโยชน์ในกรณีต่อไปนี้:

1. เมื่อคุณมีรูทีนย่อยจำนวนมากที่ต้องเชื่อมโยงกับหลาย ๆ รูทีน
โปรแกรม และไม่มีโปรแกรมใดใช้รูทีนย่อย 100% จริง ๆ แต่ละโปรแกรมใช้ a
ส่วนย่อยที่แตกต่างกัน ในกรณีนี้ อาจเป็นความคิดที่ดีที่จะใช้ไลบรารีแบบคงที่ (a
.a ไฟล์หรือไฟล์เก็บถาวร)

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

3. เมื่อเวลาลิงก์ของคุณยาวเกินไป ให้ใช้ไลบรารีที่แชร์สำหรับไฟล์ขนาดใหญ่
โปรแกรมสามารถเพิ่มความเร็วของลิงค์ได้อย่างมาก

การใช้ไลบรารีสแตติกมีข้อเสียหลักประการหนึ่ง: ในบางระบบ (เช่น Linux) คำสั่ง
ที่คุณเชื่อมโยงไลบรารีมีความสำคัญอย่างยิ่ง ตัวเชื่อมโยงประมวลผลไลบรารี
ตามลำดับที่ระบุในบรรทัดคำสั่ง คว้าทุกสิ่งที่คิดว่ามันต้องการจาก
แต่ละห้องสมุด แล้วย้ายไปยังห้องสมุดถัดไป ถ้าห้องสมุดต่อมาอ้างถึง a
สัญลักษณ์ที่ยังไม่ได้รวมจากไลบรารีก่อนหน้า ตัวเชื่อมโยงไม่ได้
รู้ว่าต้องย้อนกลับไปและคว้ามันมาจากห้องสมุดก่อนหน้า ส่งผลให้มีความจำเป็น
เพื่อแสดงรายการไลบรารีหลายครั้งบนบรรทัดคำสั่งของลิงเกอร์ (ฉันทำงานในโครงการ
ที่เราต้องทำซ้ำรายการห้องสมุดทั้งหมดสามครั้ง โครงการนี้คือสิ่งที่ทำให้
ฉันชอบวิธีอื่นที่แนะนำด้านล่าง นั่นคือการลิงก์แบบเพิ่มหน่วย)

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

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

นี่คือวิธีที่คุณสามารถทำได้บน Linux:

my_module.o : $(filter_out my_module.o, $(ไวลด์การ์ด *.o))
ld -r -o $(เอาต์พุต) $(อินพุต)

สิ่งนี้จะทำคือสร้างอีกอันหนึ่ง .o ไฟล์ชื่อ my_module.oซึ่งจะประกอบไปด้วย
ทั้งหมด .o ไฟล์ในไดเร็กทอรีย่อยนี้ ตัวเชื่อมโยงจะแก้ไข . ได้มากเท่า
อ้างอิงเท่าที่ทำได้ และจะปล่อยให้การอ้างอิงที่เหลือได้รับการแก้ไขใน
ขั้นต่อไปของการเชื่อมโยง ที่ระดับบนสุด เมื่อคุณสร้างโปรแกรมในที่สุด
แทนที่จะเชื่อมโยงกับ libmy_module.a or libmy_module.soคุณเพียงแค่เชื่อมโยงกับ
my_module.o. เมื่อคุณเชื่อมโยง .o ไฟล์ คุณไม่มีปัญหากับการพึ่งพาคำสั่งในไฟล์
ตัวเชื่อมโยงบรรทัดคำสั่ง

ปล่อยให้ แต่งหน้า คิด ออก ที่ ห้องสมุด โมดูล เป็น จำเป็น

แม้ว่าคุณจะมีไลบรารี่จริงก็ตาม โดยที่โปรแกรมนั้นต้องการไฟล์เพียงไม่กี่ไฟล์จากมัน
(แทนที่จะเป็นทุกโมดูล) makepp อาจสามารถหาได้ว่าโมดูลใดเป็น
จำเป็นจากไลบรารีและรวมเฉพาะสิ่งที่อยู่ในบิลด์ นี้สามารถบันทึกการรวบรวม
เวลาถ้าคุณกำลังพัฒนาห้องสมุดพร้อมกับโปรแกรมเพราะคุณไม่ต้องสนใจ
รวบรวมโมดูลไลบรารีที่ไม่จำเป็นสำหรับโปรแกรมเฉพาะที่คุณกำลังทำงานอยู่

หากห้องสมุดของคุณปฏิบัติตามแบบแผนอย่างเคร่งครัดว่าฟังก์ชันหรือคลาสทั้งหมดที่ประกาศใน
ไฟล์ xyz.h ถูกนำไปใช้อย่างสมบูรณ์ในไฟล์ต้นฉบับที่คอมไพล์ไปยัง xyz.o (กล่าวคือ คุณ
อย่าแบ่งการใช้งานออกเป็น xyz1.o และ xyz2.o) จากนั้นคุณสามารถใช้
ฟังก์ชั่น "$(infer_objects)" เพื่อบอกให้ makepp ดึงเฉพาะโมดูลที่เกี่ยวข้องออกจาก
ห้องสมุด. สิ่งนี้สามารถทำงานได้ดีอย่างน่าประหลาดใจสำหรับไลบรารีที่มีไฟล์รวมอยู่หลายสิบไฟล์
โดยทั่วไป "$(infer_objects)" ตรวจสอบรายการของ .h ไฟล์ที่รวมและดู
สำหรับที่สอดคล้องกัน .o ไฟล์. หากคุณกำลังพัฒนาห้องสมุดและโปรแกรมอย่างรวดเร็ว
ร่วมกันจะช่วยประหยัดเวลาในการคอมไพล์ เพราะคุณไม่ต้องเสียเวลาคอมไพล์โมดูลของ
ไลบรารี่ที่โปรแกรมไม่ได้ใช้

นี่คือตัวอย่างวิธีการใช้:

my_program: $(infer_objects *.o, $(LIB1)/*.o $(LIB2)/*.o)
$(CXX) $(อินพุต) -o $(เอาต์พุต) $(SYSTEM_LIBRARIES)

ฟังก์ชัน "$(infer_objects )" ส่งคืนอาร์กิวเมนต์แรก (หลังจากทำ wildcard
ขยาย) และยังดูรายการไฟล์ในอาร์กิวเมนต์ที่สอง for
ไฟล์ที่มีชื่อเหมือนกับชื่อของ any .h ไฟล์ที่รวมอยู่ในไฟล์ใด ๆ ในไฟล์แรก
การโต้แย้ง. หากพบไฟล์ดังกล่าว ไฟล์เหล่านี้จะถูกเพิ่มลงในรายการ

การก่อสร้าง a คงที่ ห้องสมุด

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

LIBRARY_FILES = abcde

libmine.a: $(LIBRARY_FILES).o
&rm -f $(เอาต์พุต)
$(AR) cr $(เอาต์พุต) $(อินพุต)
ranlib $(output) # อาจไม่จำเป็น ขึ้นอยู่กับระบบปฏิบัติการของคุณ

&rm เป็นคำสั่ง "rm" ในตัวของ makepp หากคุณเคยชินกับการเขียน makefiles คุณอาจจะ
แปลกใจเล็กน้อยกับคำสั่งนี้ คุณอาจคุ้นเคยกับสิ่งนี้มากกว่า:

libmine.a: $(LIBRARY_FILES).o
$(AR) เจอ $@ $? # ไม่แนะนำ!!!!!!!
ranlib $(เอาท์พุท)

ที่ไหน $? (เรียกอีกอย่างว่า "$(changed_inputs)") เป็นตัวแปรอัตโนมัติที่หมายถึงไฟล์ใดๆ
ซึ่งเปลี่ยนแปลงไปจากการสร้างห้องสมุดครั้งล่าสุด และ $@ ก็ประมาณเดียวกัน
เป็น "$(เอาต์พุต)"

ไม่แนะนำให้ใช้วิธีนี้ด้วยเหตุผลหลายประการ:

· สมมติว่าคุณลบไฟล์ต้นฉบับออกจากไดเร็กทอรีปัจจุบัน มันยังคงอยู่ใน
ห้องสมุด เพราะคุณไม่ได้สร้างห้องสมุดใหม่ตั้งแต่ต้น ส่งผลให้อะไรก็ได้
ที่เชื่อมกับห้องสมุดนี้จะมีความค้าง .o ไฟล์และนั่นอาจทำให้คุณเสียหาย
สร้าง (ฉันเคยสับสนกับสิ่งนี้เมื่อฉันพยายามลบโค้ดที่ตายแล้ว
จากโปรเจ็กต์: ฉันลบไฟล์ไปเรื่อย ๆ และมันยังคงลิงก์อยู่ ดังนั้นฉันคิดว่าโค้ดคือ
ตาย. อย่างไรก็ตาม เมื่อคนอื่นสร้างโปรเจ็กต์ใหม่ตั้งแต่ต้น กลับไม่ลิงก์ใดๆ เลย
มากกว่า! ปัญหาอยู่ที่ตัวเก่า .o ไฟล์ยังอยู่ในไฟล์เก็บถาวร)

นอกจากนี้ ขึ้นอยู่กับตัวเลือกของคุณสำหรับ "ar" และการใช้งาน "ar" ของคุณ (เช่น ถ้าคุณ
ใช้ตัวเลือก "q" แทน "r") คุณสามารถสิ้นสุดการมีหลายเวอร์ชันของ
เดียวกัน .o ภายใน .a ไฟล์. หากเวอร์ชันต่าง ๆ กำหนด globals ที่แตกต่างกัน
ลิงเกอร์อาจพยายามดึงทั้งสองอย่างเข้ามา นี่อาจเป็นสิ่งที่ไม่ดี

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

· วิธีหนึ่งที่ makepp พยายามรับประกันการสร้างที่ถูกต้องคือมันจะ
สร้างใหม่โดยอัตโนมัติหากบรรทัดคำสั่งเพื่อสร้างเป้าหมายที่กำหนดมีการเปลี่ยนแปลง แต่
ใช้ $? ตัวแปรอาจทำให้เกิดปัญหาได้ เพราะทุกครั้งที่มีการอัพเดทไลบรารี่
คำสั่ง build นั้นแตกต่างกัน (คุณสามารถระงับสิ่งนี้ได้โดยใช้
":build_check forget_action"; ดู makepp_build_check สำหรับรายละเอียด)

· การอัปเดตไฟล์เก็บถาวรแทนที่จะสร้างใหม่จะทำให้ makepp to . ไม่ได้
ใส่ไฟล์ลงใน build cache อย่างถูกต้อง (ดูรายละเอียดที่ makepp_build_cache)

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

libmine.a: $(only_targets *.o)
&rm $(เอาต์พุต)
$(AR) cr $(เอาต์พุต) $(อินพุต)

สิ่งนี้ทำให้ .o ไฟล์ในไดเร็กทอรีปัจจุบันลงในไลบรารี ตัวแทน
ตรงกับทุก .o ไฟล์ที่มีอยู่หรือสร้างได้จึงทำงานได้แม้ว่าไฟล์จะไม่
ยังอยู่

ฟังก์ชัน "only_targets" ใช้เพื่อแยก .o ไฟล์ที่ไม่มีความสอดคล้อง
ไฟล์ต้นฉบับอีกต่อไป สมมติว่าคุณมีไฟล์ชื่อ xyz.c ที่คุณเคยใส่ในของคุณ
ห้องสมุด. ซึ่งหมายความว่ามี xyz.o ไฟล์ที่อยู่รอบๆ ตอนนี้คุณลบ xyz.c
เพราะมันล้าสมัย แต่คุณลืมที่จะลบ xyz.o. ไม่มี "only_targets"
ฟังก์ชั่น xyz.o จะยังคงรวมอยู่ในรายการของ .o ไฟล์ที่รวมอยู่ในไลบรารี

การก่อสร้าง a พลวัต ห้องสมุด

กระบวนการสร้างไลบรารีแบบไดนามิกขึ้นอยู่กับระบบทั้งหมด ฉันจะอย่างมาก
แนะนำให้ใช้ libtool เพื่อสร้างไลบรารีไดนามิก (ดู
<http://www.gnu.org/software/libtool/>) จะได้ไม่ต้องคิดหาวิธีทำ
แพลตฟอร์มของคุณ และเพื่อให้ makefile ของคุณทำงานต่อไปแม้ว่าคุณจะเปลี่ยนไปใช้ a
ระบบปฏิบัติการที่แตกต่างกัน ดูเอกสารประกอบ libtool สำหรับรายละเอียด นี่คือตัวอย่าง Makefile:

LIBTOOL := ลิบทูล

libflick.la : $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(อินพุต) -o $(เอาท์พุท)

%.lo : %.ค
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(INCLUDES) -c $(input) -o $(เอาท์พุต)

การก่อสร้าง on หลาย ต่าง เครื่อง or เครือข่าย
ปัญหาที่น่ารำคาญที่สุดอย่างหนึ่งของ makefiles คือมันแทบจะไม่ทำงานเลยเมื่อคุณ
เปลี่ยนไปใช้เครื่องอื่นหรือเครือข่ายอื่น หาก makefiles ของคุณต้องทำงานต่อไป
ทุกเครื่องที่เป็นไปได้ในโลก ถ้าอย่างนั้นคุณอาจต้องการการกำหนดค่าบางอย่าง
สคริปต์ แต่ถ้าต้องทำงานบนเครื่องที่แตกต่างกันไม่กี่เครื่องก็มีหลายวิธี
คุณสามารถแก้ไขปัญหานี้:

ใช้ a ต่าง ประกอบด้วย ไฟล์ in ทั้งหมด สภาพแวดล้อม

ที่จุดเริ่มต้นของแต่ละ makefile คุณสามารถรวมบรรทัดดังนี้:

รวม system_defs.mk

ไฟล์ system_defs.mk ปกติจะอยู่คนละที่กัน
สิ่งแวดล้อม. หากคุณต้องการให้ไดเร็กทอรี build ของคุณเหมือนกันทุกเครื่อง ให้ใส่
system_defs.mk ในไดเร็กทอรีเหนือไดเร็กทอรี build หรืออื่น ๆ ให้รวม path
เพื่อ makepp โดยใช้ตัวเลือกบรรทัดคำสั่ง "-I"

การทำเช่นนี้มักจะค่อนข้างเจ็บปวด แต่จะได้ผลดีหากมี .จำนวนมาก
ความแตกต่าง

ใช้ if งบ

นี่เป็นวิธีที่น่าเกลียดที่สุด แต่ก็มักจะได้ผล

ไอฟซิส i386
ซีซี := gcc
อื่น ifsys sun4u
ซีซี := ซีซี
อื่น ifsys hpux11
ซีซี = c89
endif

ถ้าสิ่งที่คุณต้องทำคือค้นหาโปรแกรมหรือไลบรารีสองสามตัวหรือรวมไฟล์ต่าง ๆ ไว้ด้วย
สถานที่อาจมีวิธีที่ดีกว่า (ดูด้านล่าง)

find_โปรแกรม, first_available, ค้นหาไฟล์

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

CXX ;= $(find_program g++ c++ pg++ cxx CC acc)
# เลือกคอมไพเลอร์ C ++ ตัวแรกซึ่งมีอยู่ใน PATH
# (อนึ่งถ้าคุณไม่กำหนด CXX เลย นี่
#เป็นวิธีที่กำหนดไว้)
TCL_INCLUDE ;= -I$(dir_noslash $(ค้นหาไฟล์ tcl.h, \
/usr/local/stow/tcl-8.4.5-nothread/include \
/usr/include/tcl8.4 /usr/include/tcl \
/net/na1/tcl8.4a3/include /net/na1/tcl8.4a3/include))
# $(findfile ) ค้นหา tcl.h ในแต่ละที่ระบุ
# ไดเรกทอรีและส่งคืนเส้นทางแบบเต็ม นี่คือ
# แปลงเป็นตัวเลือกการรวบรวมโดยปอก
# ชื่อไฟล์ (ออกจากไดเร็กทอรี) และนำหน้าด้วย -I.
%.o : %.ซีพีพี
$(CXX) $(CXXFLAGS) $(TCL_INCLUDE) $(อินพุต) -o $(เอาต์พุต)

TCL_LIB ;= $((first_available .)
/usr/local/stow/tcl-8.4.5-nothread/lib/libtcl8.4.so
/usr/lib/libtcl8.4.so /usr/lib/libtcl.so
/net/na1/tcl8.4a3/lib/libtcl8.4.a
/net/na1/tcl8.4a3/lib/libtcl8.4.sl))
# ค้นหาว่าห้องสมุด Tcl อยู่ที่ไหน นี่คืออย่างชัดเจนแล้ว
# อยู่ในคำสั่งลิงค์:
my_program : *.o
$(CXX) $(CXXFLAGS) $(อินพุต) -o $(เอาต์พุต) $(TCL_LIB)

เอา ความได้เปรียบ of Perl's การตั้งค่า ข้อมูล

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

สคริปต์กำหนดค่าอัตโนมัติของ Perl ทำให้ข้อมูลการกำหนดค่าทั้งหมดพร้อมใช้งานผ่าน
แฮช %Config ไม่มีไวยากรณ์ในการเข้าถึงแฮช Perl โดยตรงใน makepp แต่คุณสามารถ
วางลงใน Perl และตั้งค่าตัวแปรสเกลาร์ ซึ่งสามารถเข้าถึงได้โดยตรงจาก makepp:

perl_begin
# ดึงค่าจากแฮชการกำหนดค่า
ใช้การกำหนดค่า;
$CC = $Config{'cc'}; # C คอมไพเลอร์ที่ใช้ Perl;
$byteorder_flags = "-DBYTEORDER=$Config{'byteorder'}";
$longdouble_defined = $Config{'d_longdbl'} eq 'define';
$CFLAGS_for_shared_libs = $Config{'cccdlflags'};
$LDFLAGS_for_shared_libs = $Config{'ccdlflags'};
perl_end

นอกจากนี้ เมื่อคุณทำ 'use Config' เสร็จแล้ว คุณสามารถใช้คำสั่ง "$(perl )" ได้ เช่น
นี้:

SHARED_LIB_EXTENSION := $(perl $Config{'dext'})

พิมพ์ "perldoc Config" เพื่อดูว่ามีข้อมูลใดบ้างผ่านแฮช %Config

การกำหนดค่าของ Perl เป็นที่ที่ดีในการรับข้อมูลต่างๆ เช่น ข้อมูลเกี่ยวกับประเภทจำนวนเต็ม byte
ลำดับ และสิ่งอื่น ๆ ที่มักจะต้องใช้สคริปต์การกำหนดค่าแยกต่างหากเพื่อค้นหา บางส่วนของ
ข้อมูลที่เกี่ยวข้องกับการมีอยู่ของสิ่งต่าง ๆ ในระบบไฟล์อาจไม่
ถูกต้อง. ตัวอย่างเช่น $Config{'cc'} หมายถึงคอมไพเลอร์ C ที่ Perl สร้างขึ้นด้วย
ซึ่งอาจไม่ใช่คอมไพเลอร์ C ตัวเดียวกับที่คุณต้องการใช้ อันที่จริงมันอาจจะไม่มีก็ได้
ในระบบของคุณ เนื่องจากคุณอาจติดตั้ง Perl ผ่านแพ็คเกจไบนารี

เคล็ดลับ for การใช้ สัญลักษณ์แทน
แม็ทชิ่ง ทั้งหมด ไฟล์ ยกเว้น a บาง ชุดย่อย

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

ตัวอย่างเช่น สมมติว่าคุณมีโปรแกรมทดสอบสำหรับแต่ละโมดูลในไลบรารี แต่คุณไม่มี
ต้องการรวมโปรแกรมทดสอบในห้องสมุด หากโปรแกรมทดสอบทั้งหมดเริ่มต้นด้วย
ทดสอบจากนั้นคุณสามารถยกเว้นได้ดังนี้:

libproduction.a: $(filter_out test*, $(ไวลด์การ์ด *.o))

ฟังก์ชัน "$(filter )" และ "$(filter_out )" เป็นชุดตัวกรองที่ทรงพลังมาก
เซตของจุดตัดและการดำเนินการต่าง ตัวอย่างเช่น,

ย่อย ;= $(filter_out *test* *$(ARCH)*, $(shell find . -type d -print))
# ส่งกลับไดเรกทอรีย่อยทั้งหมดที่ไม่มี
# "test" หรือ $(ARCH) ในนั้น

$(ตัวกรอง $(patsubst test_dir/test_%.o, %.o, $(สัญลักษณ์แทน test_dir/*.o)), \
$(สัญลักษณ์แทน *.o))
# ส่งคืนรายการไฟล์ .o ในปัจจุบัน
# ไดเรกทอรีที่มีความสอดคล้อง
# test_*.o ไฟล์ในไดเร็กทอรีย่อย test_dir
$(filter_out $(patsubst man/man3/%.3, %.o, $(ตัวแทน man/man3/*.3)), \
$(สัญลักษณ์แทน *.o))
# ส่งคืนรายการไฟล์ .o ในปัจจุบัน
# ไดเรกทอรีที่ไม่มีหน้าคู่มือ
# ด้วยชื่อไฟล์เดียวกันในไดเร็กทอรีย่อย man/man3

การใช้ "$(only_targets )" ฟังก์ชัน ไปยัง กำจัด ค้าง .o ไฟล์

สมมติว่าคุณกำลังสร้างโปรแกรมหรือไลบรารีด้วยคำสั่ง build ดังนี้:

โปรแกรม: *.o
$(CC) $(อินพุต) -o $(เอาต์พุต)

สมมติว่าตอนนี้คุณลบไฟล์ต้นฉบับ หากคุณลืมลบที่เกี่ยวข้อง .o ไฟล์,
มันจะยังคงเชื่อมโยงอยู่แม้ว่าจะไม่มีทางสร้างมันได้อีก ใน
ในอนาคต makepp คงจะรับรู้สถานการณ์นี้โดยอัตโนมัติและแยกมันออกจาก
รายการสัญลักษณ์แทน แต่ปัจจุบัน คุณต้องบอกให้ยกเว้นด้วยตนเอง:

โปรแกรม: $(only_targets *.o)
$(CC) $(อินพุต) -o $(เอาต์พุต)

Makepp ไม่รู้วิธีสร้างกลิ่นอับ .o file อีกต่อไปเนื่องจากไฟล์ต้นฉบับของมันคือ
หายไป ดังนั้นฟังก์ชัน "$(only_targets )" จะแยกออกจากรายการการพึ่งพา

เคล็ดลับ for หลาย ไดเรกทอรี
เหตุผลหลักประการหนึ่งในการเขียน makepp คือการทำให้การจัดการหลายรายการง่ายขึ้น
ไดเรกทอรี Makepp สามารถรวมคำสั่ง build จาก makefile หลายไฟล์ได้
จัดการกับกฎอย่างถูกต้องใน makefile เดียวที่ขึ้นอยู่กับไฟล์ที่สร้างโดยa
makefile ที่แตกต่างกัน

อะไร ไปยัง do in สถานที่ of ซ้ำ ทำ

Makepp รองรับ recursive make สำหรับความเข้ากันได้แบบย้อนหลัง แต่ขอแนะนำอย่างยิ่ง
นั่นคุณ ไม่ ใช้มัน. ถ้าไม่รู้ว่ามันคืออะไรก็ดี

ดู "ระบบที่ดีกว่าสำหรับการสร้างลำดับชั้น" ใน makepp สำหรับรายละเอียดว่าทำไมคุณถึงไม่ต้องการ
ใช้ make แบบเรียกซ้ำหรือค้นหาบนเว็บสำหรับ "recursive make ถือเป็นอันตราย"

แทนที่จะทำการเรียกซ้ำเพื่อสร้างเป้าหมาย "ทั้งหมด" ในทุก makefile มันคือ
มักจะง่ายกว่าเพื่อให้ makepp ทราบว่าจะต้องสร้างเป้าหมายใด
นอกจากนี้ หากคุณใส่ทั้งหมดของคุณ .o และไฟล์ไลบรารีในไดเร็กทอรีเดียวกันกับ the
makefiles จากนั้น makepp จะค้นหาโดยอัตโนมัติว่าต้องใช้ makefiles ใดเช่นกัน - the
สิ่งเดียวที่จำเป็นคือให้ระดับบนสุดของคุณสร้างรายการไฟล์ที่จำเป็น
สำหรับขั้นตอนการเชื่อมโยงขั้นสุดท้าย ดูตัวอย่างด้านล่าง

หนึ่ง ทำไฟล์ for แต่ละ ไดเรกทอรี: กับ โดยปริยาย โหลด

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

นี่คือตัวอย่าง makefile ระดับบนสุดสำหรับลำดับชั้นไดเร็กทอรีที่ใช้การโหลดโดยปริยาย
เพื่อสร้างโปรแกรมที่ประกอบด้วยไลบรารีที่ใช้ร่วมกันจำนวนมาก (แต่โปรดดู "คุณต้องการ . จริงๆ หรือไม่
ห้องสมุด?" ใน makepp_cookbook เพราะการสร้างโปรแกรมจากไลบรารีที่แชร์จำนวนมาก
ไม่จำเป็นต้องเป็นความคิดที่ดี):

# makefile ระดับบนสุด:
โปรแกรม : main.o **/*.la # ลิงก์ในไลบรารีที่แชร์จากไดเรกทอรีย่อยทั้งหมด
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(อินพุต) -o $(เอาท์พุท) $(LIBS)

นั่นคือทั้งหมดที่คุณต้องการใน makefile ระดับบนสุด ในแต่ละไดเร็กทอรีย่อย คุณ
คงจะทำสิ่งนี้:

# Makefile ในแต่ละไดเรกทอรีย่อย:
รวม standard_defs.mk # ค้นหา ., .., ..-ฯลฯ จนกระทั้ง
# ค้นหาไฟล์รวมที่ระบุ
# แทนที่คำจำกัดความของตัวแปรบางส่วนที่นี่
SPECIAL_FLAGS := -do_something_different

makefile แต่ละอันอาจจะเหมือนกันมากถ้าคำสั่งเพื่อสร้างเป้าหมาย
ค่อนข้างจะคล้ายกัน

ในที่สุด คุณจะใส่สิ่งต่อไปนี้ลงใน standard_defs.mk ไฟล์ (ซึ่งน่าจะ
จะอยู่ในไดเรกทอรีระดับบนสุด):

# การตั้งค่าตัวแปรทั่วไปและกฎการสร้างสำหรับไดเรกทอรีทั้งหมด
CFLAGS := -g -O2
INCLUDE_DIR := $(รวม find_upwards)
# ค้นหา ., .., ..-, ฯลฯ สำหรับไฟล์หรือ
# ไดเร็กทอรีที่เรียกว่า include ดังนั้นหากคุณใส่
# ไฟล์รวมทั้งหมดของคุณในนั้น จะ
# หาพวกเขา.
รวม:= -I$(INCLUDE_DIR)

%.lo : %.ค
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(INCLUDES) -c $(input) -o $(เอาท์พุต)

lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(output) $(อินพุต)
# $(relative_to ., ..) ส่งกลับชื่อของค่าปัจจุบัน
# ไดเรกทอรีย่อยที่สัมพันธ์กับระดับบน
#ไดเรกทอรีย่อย ดังนั้นหาก makefile นี้เป็น xyz/Makefile
# กฎนี้จะสร้าง xyz/libxyz.la

# เผยแพร่สู่สาธารณะรวมไฟล์ในไดเร็กทอรี include ระดับบนสุด:
$(INCLUDE_DIR)/public_%.h : public_%.h
:build_check สัญลักษณ์
&ln -fr $(อินพุต) $(เอาต์พุต)

หนึ่ง ทำไฟล์ for แต่ละ ไดเรกทอรี: ชัดเจน โหลด

หากคุณต้องการใส่ทั้งหมดของคุณ .o ไฟล์ลงในไดเร็กทอรีย่อยที่ขึ้นกับสถาปัตยกรรม แล้ว
ตัวอย่างข้างต้นควรแก้ไขให้มีลักษณะดังนี้:

# makefile ระดับบนสุด:
MAKEFILES := $(wildcard **/Makeppfile) # รายการไดเรกทอรีย่อยทั้งหมดไปยัง
# รับ makefiles จาก

load_makefile $(MAKEFILES) # โหลดพวกมันทั้งหมดเข้าไป

รวม standard_defs.mk # รับคำสั่งคอมไพล์สำหรับ main.o

โปรแกรม : $(ARCH)/main.o */**/$(ARCH)/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(อินพุต) -o $(เอาท์พุท) $(LIBS)
# */**/$(ARCH) ไม่รวมไดเรกทอรีย่อย
# $(ARCH) ที่เราไม่อยากสร้าง
#ห้องสมุดที่ใช้ร่วมกัน

makefile แต่ละอันจะเหมือนเดิมทุกประการ:

# Makefile ในแต่ละไดเรกทอรีย่อย:
รวม standard_defs.mk
# ... แทนที่ตัวแปรที่นี่

และในที่สุด standard_defs.mk จะมีบางสิ่งดังต่อไปนี้:

# การตั้งค่าตัวแปรทั่วไปและกฎการสร้างสำหรับไดเรกทอรีทั้งหมด
ARCH ;= $(เชลล์ uname -s)-$(เชลล์ uname -m)-$(เชลล์ uname -r)
# บางครั้งคนใช้เพียง $(shell uname -m) แต่
# สิ่งนี้จะเหมือนกันสำหรับ FreeBSD และ Linux บน
# x86. -r ไม่มีประโยชน์จริง ๆ บน Linux
# แต่สำคัญสำหรับ OS อื่นๆ: ไบนารีสำหรับ
# SunOS 5.8 โดยทั่วไปจะไม่ทำงานบน SunOS 5.7
&mkdir -p $(ARCH) # ตรวจสอบให้แน่ใจว่าไดเร็กทอรีเอาต์พุตอยู่
CFLAGS := -g -O2
INCLUDE_DIR := $(รวม find_upwards)
# ค้นหา ., .., ..-, ฯลฯ สำหรับไฟล์หรือ
# ไดเร็กทอรีที่เรียกว่า include ดังนั้นหากคุณใส่
# ไฟล์รวมทั้งหมดของคุณในนั้น จะ
# หาพวกเขา.
รวม:= -I$(INCLUDE_DIR)

$(ARCH)/%.lo : %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(INCLUDES) -c $(input) -o $(เอาท์พุต)

$(อาร์ช)/ lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(output) $(อินพุต)
# $(relative_to ., ..) ส่งกลับชื่อของค่าปัจจุบัน
# ไดเรกทอรีย่อยที่สัมพันธ์กับระดับบน
#ไดเรกทอรีย่อย ดังนั้นหาก makefile นี้เป็น xyz/Makefile
# กฎนี้จะสร้าง xyz/$(ARCH)/libxyz.la

# คัดลอกไฟล์รวมสาธารณะไปยังไดเร็กทอรี include ระดับบนสุด:
$(INCLUDE_DIR)/public_%.h : public_%.h
&cp $(อินพุต) $(เอาต์พุต)

อัตโนมัติ การทำ ทำไฟล์

หาก makefile ของคุณคล้ายกันมาก (ดังในตัวอย่างด้านบน) คุณสามารถบอก Makepp . ได้
เพื่อสร้างโดยอัตโนมัติหากไม่มีอยู่ เพียงเพิ่มสิ่งต่อไปนี้ในระดับบนสุดของคุณ
ทำไฟล์:

SUBDIRS := $(filter_out suitable_dir1 suitable_dir2, $(wildcard */**)) ย่อย
$(foreach)/Makeppfile: : foreach $(ย่อย)
&echo "รวม standard_defs.mk" -o $(เอาต์พุต)
&echo "_include added_defs.mk" -o >>$(เอาต์พุต)
# หากไฟล์ added_defs.mk มีอยู่แล้ว
#จะรวมไว้แต่ถ้าไม่มี
# คำสั่ง _include จะถูกละเว้น

ตอนนี้ makefiles จะถูกสร้างขึ้นโดยอัตโนมัติ

หนึ่ง ทำไฟล์ เพียง at ด้านบน ระดับ

หาก makefile ของคุณเหมือนกันทั้งหมด คุณอาจถามว่า: ทำไมฉันถึงต้องมี makefile ในแต่ละอัน
ระดับ? ทำไมไม่ใส่ทั้งหมดลงใน makefile ระดับบนสุดล่ะ

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

นี่คือตัวอย่างของการทำเช่นนั้น:

# makefile ระดับบนสุดสำหรับลำดับชั้นของไดเร็กทอรี สร้างโปรแกรม
# จากชุดของไลบรารีที่ใช้ร่วมกันเป็นตัวอย่าง (ดูคำเตือนด้านบน
#เพราะเหตุใดคุณอาจต้องการใช้การลิงก์แบบเพิ่มหน่วยหรืออื่นๆ
# วิธีการมากกว่าไลบรารีที่ใช้ร่วมกัน)
makepp_percent_subdirs := 1 # อนุญาตให้ % จับคู่หลายไดเร็กทอรี
ย่อย := $(filter_out *CVS* other-unwanted_dirs $(wildcard **))
CFLAGS := -g -O2
รวม := -Iincludes

%.lo: %.ค
$(LIBTOOL) --mode=คอมไพล์ $(CC) $(INCLUDES) $(CFLAGS) -c $(input) -o $(output)

$( foreach)/ lib$(notdir $(foreach)).la: $(foreach)/*.lo : foreach $(SUBDIRS)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(output) $(อินพุต)
#กฎการสร้างห้องสมุดทั้งหมด

โปรแกรม : main.o **/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(output) $(อินพุต)

รวม/$(notdir $(foreach)) : $(foreach) : foreach **/public_*.h
&cp $(อินพุต) $(เอาต์พุต)
#กฎตัวอย่างสำหรับการคัดลอกแบบสาธารณะ
# ไฟล์ .h ที่เข้าถึงได้ ถูกที่แล้ว

A ปลาเดยส์ เป้า

makefiles ดั้งเดิมมีเป้าหมายที่ชัดเจน ซึ่งช่วยให้ลบทุกอย่างที่เคยเป็น
สร้าง. มีสาเหตุสามประการที่คุณไม่ควรทำเช่นนี้กับ makepp:

1. Makepp พยายามอย่างยิ่งยวดเพื่อให้แน่ใจว่ามีการสร้างที่ถูกต้อง ดังนั้นคนหมดหวัง "ฉันไม่
รู้ว่าอะไรผิด" ทำให้อยากเริ่มต้นใหม่ก็เป็นเรื่องของอดีต

2. บางครั้งผู้คนจะพยายามประหยัดเวลาด้วยการทำสองสิ่งที่ขัดแย้งกันในคราวเดียว:
"ทำความสะอาดทั้งหมด". สิ่งนี้อาจทำให้ระบบไวด์การ์ดอัจฉริยะของ makepp สับสนเพราะจะทำให้
หาข้อเท็จจริงก่อนทำอะไร แล้วก็มาถึงการกระทำที่สะอาดซึ่งไม่
ไม่บอก makepp ว่าทำอะไร
ตรงกันข้ามกับเครื่องมือสร้าง) แล้วก็มา "ทั้งหมด" แต่ไฟล์ล่าสุด
ซึ่งที่นั่นได้หายไปอย่างลึกลับ

3. มีคำสั่ง "makeppclean" ซึ่งทำสิ่งเดียวกัน และมีประสิทธิภาพมากขึ้น

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

$(ปลอมสะอาด):
&rm -fm $(สัญลักษณ์แทน *.o .makepp_log)
# -m และ .makepp_log กำจัดขยะของ makepp ทั้งหมด

แทนที่จะระบุไฟล์ที่คุณต้องการลบอย่างชัดเจน คุณสามารถบอก makepp to
ลบทุกอย่างที่รู้วิธีสร้างดังนี้:

$(ปลอมสะอาด):
&rm -fm .makepp_log $(only_targets *)

มีข้อดีตรงที่ว่าถ้าไฟล์ต้นทางของคุณสามารถสร้างจากไฟล์อื่นได้
พวกเขาจะถูกลบด้วย ในทางกลับกัน, เหม็นอับ .o ไฟล์ (ไฟล์ที่เคยเป็น
สร้างได้ แต่ไฟล์ต้นฉบับถูกลบไปแล้ว) จะไม่ถูกลบ

หากคุณมีบิลด์ที่เกี่ยวข้องกับ makefiles ในไดเร็กทอรีต่างๆ
makefile ระดับอาจอ้างอิงเป้าหมาย "สะอาด" (หรือเป้าหมายปลอมอื่น ๆ ) ในอีก
ทำไฟล์:

# makefile ระดับบนสุด
ย่อย := sub1 sub2

#สร้างกฎที่นี่

# ทำความสะอาดหลังการสร้าง:
$(หลอกลวง): $(SUBDIRS)/clean
&rm -fm .makepp_log $(only_targets *)

อีกวิธีหนึ่ง คุณสามารถใส่เป้าหมายที่ "สะอาด" ไว้ใน makefile ระดับบนสุดเท่านั้น แล้วมี
ประมวลผลไดเร็กทอรีทั้งหมดดังนี้:

$(ปลอมสะอาด):
&rm -fm $(only_targets **/*)

การใช้ Qt's มอค ตัวประมวลผลล่วงหน้า
ตัวอย่างนี้แสดง makefile สำหรับยูทิลิตี้ที่ใช้ไลบรารี Qt GUI ของ Nokia (ดู
<http://qt.nokia.com>). สิ่งเดียวที่ผิดปกติเล็กน้อยเกี่ยวกับเรื่องนี้คือคุณ
ต้องเรียกใช้ตัวประมวลผลล่วงหน้าที่เรียกว่า "moc" ในไฟล์ ".h" ส่วนใหญ่ที่มีคำจำกัดความของวิดเจ็ต
แต่คุณไม่ต้องการเรียกใช้ "moc" ในไฟล์ ".h" ใดๆ ที่ไม่ได้ใช้มาโคร "Q_OBJECT"

อัตโนมัติ การกำหนด ที่ ไฟล์ จำเป็นต้อง มอค ไฟล์

แน่นอน คุณสามารถแสดงรายการไฟล์ ".h" ทั้งหมดที่จำเป็นต้องมี "moc" ทำงานอยู่
อย่างไรก็ตาม หากคุณกำลังพัฒนาวิดเจ็ตใหม่อย่างรวดเร็ว อาจเป็นสิ่งที่สร้างความรำคาญให้กับ
อัปเดตรายการต่อไปใน makefile คุณสามารถหลีกเลี่ยงความจำเป็นในการแสดงรายการ moc
โมดูลอย่างชัดเจนด้วยสิ่งนี้:

กระทรวงพาณิชย์ := $(QTDIR)/bin/moc
MODULES := โมดูลใดก็ตามที่คุณมีในโปรแกรมของคุณ
MOC_MODULES := $(patsubst %.h, moc_%, $(&grep -l /Q_OBJECT/ *.h))
# สแกนไฟล์ .h ทั้งหมดสำหรับมาโคร Q_OBJECT

my_program: $(MODULES).o $(MOC_MODULES).o
$(CXX) $(อินพุต) -o $(เอาต์พุต)

moc_%.cxx: %.h # ทำให้ไฟล์ moc จากไฟล์ .h
$(MOC) $(อินพุต) -o $(เอาต์พุต)

%.o: %.cxx
$(CXX) $(CXXFLAGS) -c $(อินพุต) -o $(เอาต์พุต)

วิธีการนี้จะสแกน .ของคุณ .h ไฟล์ทุกครั้งที่เรียกใช้ makepp โดยมองหา
มาโคร "Q_OBJECT" ฟังดูมีราคาแพง แต่อาจใช้เวลาไม่นานเลย (NS .h
ไฟล์ทั้งหมดจะต้องถูกโหลดจากดิสก์โดยกระบวนการคอมไพล์ ดังนั้นพวกเขาจะ
เก็บไว้ในแคช)

#include .ม็อค ไฟล์

อีกวิธีหนึ่งคือ "#รวม" เอาต์พุตจากตัวประมวลผลล่วงหน้า "moc" ในวิดเจ็ตของคุณ
ไฟล์การนำไปใช้ ซึ่งหมายความว่าคุณต้องไม่ลืมเขียน "#include" แต่มี
ข้อดีคือมีโมดูลให้คอมไพล์น้อยลง ดังนั้นการคอมไพล์จึงเร็วขึ้น
(สำหรับการรวบรวม C++ ส่วนใหญ่ ส่วนใหญ่จะใช้เวลาอ่านไฟล์ส่วนหัวและ
เอาต์พุตจากตัวประมวลผลล่วงหน้าจำเป็นต้องรวมไฟล์เกือบเท่าวิดเจ็ตของคุณ
อย่างไรก็ตาม) ตัวอย่างเช่น:

// my_widget.h
คลาส MyWidget: QWidget สาธารณะ {
Q_วัตถุ
-
}

// my_widget.cpp

#include "my_widget.h"
#include "my_widget.moc" // my_widget.moc เป็นผลลัพธ์จาก
// ตัวประมวลผลล่วงหน้า moc
// สิ่งอื่น ๆ ในการใช้งานที่นี่
MyWidget::MyWidget(ชื่อ QWidget * parent, const char * name) :
QWidget(พาเรนต์, ชื่อ)
{
-
}

ตอนนี้ คุณต้องมีกฎใน makefile ของคุณเพื่อสร้างไฟล์ ".moc" ทั้งหมดดังนี้:

กระทรวงพาณิชย์ := $(QTDIR)/bin/moc
# กฎในการสร้างไฟล์ .moc:
%.moc: %.ชม
$(MOC) $(อินพุต) -o $(เอาต์พุต)

Makepp ฉลาดพอที่จะรู้ว่าจำเป็นต้องสร้าง "my_widget.moc" หากไม่เป็นเช่นนั้น
มีอยู่แล้วหรือถ้ามันล้าสมัย

วิธีที่สองนี้เป็นวิธีที่ฉันมักจะใช้เพราะมันเร่งการคอมไพล์

เปลี่ยน for เลิก ทำ สำนวน
สร้างเป้าหมาย

บางครั้งผู้คนมีกฎเกณฑ์ใน makefile ขึ้นอยู่กับเป้าหมายที่พวกเขากำลังสร้าง
โดยใช้ตัวแปรพิเศษ "MAKECMDGOALS" ตัวอย่างเช่น บางครั้งเราเห็นสิ่งต่าง ๆ เช่น
นี้:

ifneq ($(การผลิตตัวกรอง, $(MAKECMDGOALS)),)
CFLAGS := -O2
อื่น
CFLAGS := -g
endif

สิ่งนี้จะทำงานได้ดีกับ makepp อย่างไรก็ตาม ฉันไม่แนะนำให้ใช้ "MAKECMDGOALS" สำหรับสิ่งนั้น
กรณี (และ GNU ทำด้วยตนเองเช่นกัน) คุณควรปรับให้เหมาะสมและ
ดีบักคอมไพล์ .o ไฟล์ในไดเร็กทอรีแยกกัน หรือให้คำนำหน้าต่างกันหรือ
คำต่อท้าย หรือใช้ที่เก็บ เพื่อแยกพวกมันออกจากกัน

อาจเป็นครั้งเดียวที่คุณอาจต้องการอ้างอิง "MAKECMDGOALS" จริงๆ ก็คือถ้ามัน
ใช้เวลานานในการโหลด makefiles ของคุณ และคุณไม่จำเป็นต้องทำเช่นนั้นสำหรับเป้าหมาย "สะอาด" ของคุณ
(แต่คุณไม่จำเป็นต้องมีเป้าหมายที่ชัดเจน) ตัวอย่างเช่น,

ifneq ($(MAKECMDGOALS)สะอาด)
load_makefile $(ตัวแทน **/Makeppfile)
อื่น
no_implicit_load . # ป้องกันการโหลดอัตโนมัติของ makefile อื่น ๆ
endif

$(ปลอมสะอาด):
&rm -f $(สัญลักษณ์แทน **/*.o)

ซ้ำ ทำ ไปยัง สร้าง in ต่าง ไดเรกทอรี

ดู "เคล็ดลับสำหรับหลายไดเรกทอรี" ใน makepp_cookbook

ซ้ำ ทำ ไปยัง เปลี่ยนแปลง ความคุ้มค่า of a ตัวแปร

makefiles บางตัวเรียกตัวเองอีกครั้งด้วยค่าตัวแปรที่แตกต่างกัน เช่น debug
เป้าหมายในส่วน makefile ต่อไปนี้

.PHONY: ดีบักทั้งหมด

ปรับให้เหมาะสม:
$(MAKE) โปรแกรม CFLAGS=-O2

ดีบัก:
$(MAKE) โปรแกรม CFLAGS=-g

โปรแกรม: อ่าวบ่อ
$(CC) $(CFLAGS) $^ -o $@

%.o : %.ค
$(CC) $(CFLAGS) -c $< -o $@

หากผู้ใช้พิมพ์ "make debug" จะเป็นการสร้างโปรแกรมในโหมดเริ่มต้นโดยเปิดใช้งานการดีบัก
แทนที่จะใช้การเพิ่มประสิทธิภาพ

วิธีที่ดีกว่าคือสร้างโปรแกรมสองโปรแกรมที่แตกต่างกัน โดยมีชุด .สองชุดที่ต่างกัน
ไฟล์วัตถุเช่นนี้:

CFLAGS := -O2
DEBUG_FLAGS := -g
โมดูล := ab

โปรแกรม: $(MODULES).o
$(CC) $(CFLAGS) $(อินพุต) -o $(เอาต์พุต)

ดีบัก/โปรแกรม: debug/$(MODULES).o
$(CC) $(DEBUG_FLAGS) $(อินพุต) -o $(เอาต์พุต)

%.o : %.ค
$(CC) $(CFLAGS) -c $(อินพุต) -o $(เอาต์พุต)

แก้จุดบกพร่อง/%.o : %.c
$(CC) $(DEBUG_FLAGS) -c $(อินพุต) -o $(เอาต์พุต)

$(ดีบักปลอม): debug/program

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

ข้างต้นสามารถเขียนค่อนข้างกระชับมากขึ้นโดยใช้ที่เก็บ ต่อไปนี้
makefile เทียบเท่ากับ:

ดีบักที่เก็บ=. # ทำให้ไดเร็กทอรีย่อยการดีบักดูเหมือนสำเนาของ
# ไดเรกทอรีย่อยปัจจุบัน
load_makefile ดีบัก CFLAGS=-g
# แทนที่ CFLAGS เมื่อเรียกใช้ในไดเรกทอรีย่อยการดีบัก
CFLAGS := -O2 # ค่าของ CFLAGS เมื่อเรียกใช้ในไดเรกทอรีย่อยนี้

โปรแกรม: อ่าวบ่อ
$(CC) $(CFLAGS) $^ -o $@

%.o : %.ค
$(CC) $(CFLAGS) -c $< -o $@

$(ดีบักปลอม): debug/program
# หากผู้ใช้พิมพ์ "makepp debug" ให้ builds
# debug/program แทนโปรแกรม

เบ็ดเตล็ด เคล็ดลับ
สรุป ความน่าเชื่อถือของ Olymp Trade? do I สร้าง หนึ่ง ส่วนหนึ่ง ต่างกัน เพียงแค่ ครั้งหนึ่ง?

Makepp ทำให้สิ่งนี้ทำได้ยากเพราะผลลัพธ์ไม่สอดคล้องกับกฎเกณฑ์
แต่มีบางสถานการณ์ที่คุณอาจต้องการสิ่งนี้ เช่น รวบรวมเพียงหนึ่งโมดูลด้วย
ข้อมูลการดีบักหนัก คุณสามารถบรรลุสิ่งนี้ได้ในสองขั้นตอนโดยสร้าง .ก่อน
การพึ่งพาแยกจากกัน แล้วแยกออกจากเฟสลิงก์:

makepp DEBUG=3 buggy.o # สร้างด้วยตัวเลือกอื่น
makepp --dont-build=buggy.o buggy # ใช้มัน แม้จะมีตัวเลือกการสร้าง "ผิด"

สรุป ความน่าเชื่อถือของ Olymp Trade? do I ทำ แน่ใจ my เอาท์พุต ไดเรกทอรี มีอยู่?

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

#วิถีคลาสสิค
หุ่นจำลอง := $(shell test -d $(OUTPUT_DIRECTORY) || mkdir -p $(OUTPUT_DIRECTORY))
# นี้มักจะง่ายกว่าการทำให้ไฟล์ทั้งหมดขึ้นอยู่กับ
# $(OUTPUT_DIRECTORY) และมีกฎให้ทำ
# โปรดทราบว่าคุณต้องใช้ := แทน = เพื่อบังคับให้เป็น
#ดำเนินการทันที
# แนวทางอื่น: ใช้รหัส Perl, OUTPUT_DIRECTORY local var
perl_begin
-d $OUTPUT_DIRECTORY หรือ mkdir $OUTPUT_DIRECTORY;
perl_end
# วิธีที่ทันสมัย ​​ไม่ทำอะไรกับไดเร็กทอรีที่มีอยู่
&mkdir -p $(OUTPUT_DIRECTORY)

หนึ่งในข้อความสั่งเหล่านี้ควรอยู่ใกล้ด้านบนสุดของ makefile ของคุณ ดังนั้นมันจึงถูกดำเนินการ
ก่อนสิ่งอื่นที่อาจต้องการไดเร็กทอรี

สรุป ความน่าเชื่อถือของ Olymp Trade? do I บังคับให้ a คำสั่ง ไปยัง ดำเนินการ on ทุกๆ สร้าง?

วิธีที่ง่ายที่สุดคือไม่ใช้กลไกของกฎเลย แต่เพียงเพื่อดำเนินการ เช่น
นี้:

dummy := $(shell date > last_build_timestamp)

หรือใส่ไว้ในบล็อก Perl ดังนี้:

perl_begin
ระบบ ("คำสั่งเพื่อดำเนินการ");
perl_end

วิธีการนี้มีข้อเสียที่จะดำเนินการแม้ว่าเป้าหมายที่ไม่เกี่ยวข้องคือ
กำลังวิ่ง

วิธีที่สองคือการประกาศไฟล์เป็นเป้าหมายปลอม แม้ว่าจะเป็นไฟล์จริงก็ตาม
สิ่งนี้จะบังคับให้ makepp รันคำสั่งใหม่เพื่อสร้างมันทุกครั้ง แต่ถ้ามัน
ปรากฏในรายการการพึ่งพาของกฎบางอย่าง

สรุป ความน่าเชื่อถือของ Olymp Trade? do I ร่น แสดง สร้าง คำสั่ง?

มักจะมีตัวเลือกมากมายในการคอมไพล์คำสั่งที่แสดงบน
หน้าจอไม่สามารถอ่านได้ คุณสามารถเปลี่ยนสิ่งที่แสดงได้โดยระงับการแสดงผลของ
คำสั่งทั้งหมด แล้วพิมพ์ส่วนที่น่าสนใจของคำสั่งออกมาอย่างชัดเจน มันคือ
ง่ายต่อการพิมพ์เฉพาะส่วนที่เกี่ยวข้องของคำสั่งโดยใช้ "$(filter_out )" เช่น
นี้:

ALL_CFLAGS = $(CFLAGS) $(รวม) $(ADDL_CXX_FLAGS) $(DEBUG_FLAGS)

%.o : %.ค
@&echo $(notdir $(CC)) ... \
$(filter_out -I* $(ADDL_CXX_FLAGS), $(ALL_CFLAGS)) \
-c $(อินพุต)
@$(CC) $(ALL_CFLAGS) -c $(อินพุต) -o $(เอาต์พุต)

(เครื่องหมาย "@" หน้าคำสั่งระงับการพิมพ์คำสั่ง)

วิธีนี้จะช่วยให้คุณเห็นตัวเลือกที่น่าสนใจส่วนใหญ่ได้ แต่จะไม่แสดงตัวเลือกทั้งหมด
รวมไดเร็กทอรี (ซึ่งมักจะมีมากมาย!) หากสนใจส่วนไหน
in ต่อเนื่องกันในคำสั่งของคุณ คุณยังสามารถใช้ฟังก์ชัน "print" (ซึ่งเพิ่ม a
ขึ้นบรรทัดใหม่ ดังนั้นคุณไม่ต้องการหลายรายการ):

เป้า:
@... $(พิมพ์ส่วนที่น่าสนใจ) ...

สรุป ความน่าเชื่อถือของ Olymp Trade? do I แปลง a ไฟล์ เข้าไป การพึ่งพา?

สำหรับรูปแบบไฟล์ที่ไม่ชัดเจนบางรูปแบบ ไม่ควรใช้เครื่องสแกน ในโครงการเดียว
เรามีไฟล์ xml พูด foobar.xml ซึ่งมีการพึ่งพาสำหรับ foobar.out:


NS
NS



เราตัดสินใจที่จะยึดตามรูปแบบที่เรียบง่ายนี้ ดังนั้นเราจึงไม่จำเป็นต้องแยกวิเคราะห์ xml กับ
ในตัว &sed นี่คือสิ่งที่เราทำด้วยการแทนที่อย่างง่ายสามตัวสำหรับ .สามชนิด
บรรทัด:

%.d: %.xml
&sed ของ! !$(ต้นกำเนิด).ออก: \\! || NS! (.+) !$$1 \\! || NS! !# ว่างเปล่า!' \
$(อินพุต) -o $(เอาต์พุต)

รวม foobar.d

พยายามรวมสิ่งนี้ไว้ ให้สร้าง "foobar.d" ก่อน:

foobar.out: \
NS \
NS \
ค \
# ว่างเปล่า

บรรทัดว่าง (แค่ความคิดเห็นหรือว่างจริงๆ) ไม่ต้องกังวลกับการต่อท้าย
แบ็กสแลช ทางเลือกอื่นที่สร้างรายการหลายบรรทัดคือ:

%.d: %.xml
&sed ของ! !$(ต้นกำเนิด).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(อินพุต) -o $(เอาต์พุต)

รวม foobar.d

สิ่งนี้สร้างสิ่งที่เทียบเท่า:

foobar.out: $((
a
b
c
))

หากคุณมีการเขียนใหม่ที่ซับซ้อนกว่านั้น ให้กำหนดฟังก์ชันภายใน makefile หรือใน a
โมดูลที่คุณรวมไว้ เช่น การกำหนด $_ จะข้ามบรรทัดอินพุต:

ตัวกรองย่อย {
คืนค่า undef $_ ถ้า /
$stem ของฉัน = f_stem;
NS! !$stem.out: \$((! || s! !))! || s!<.+?>!!g;
}

%.d: %.xml
&sed ของ! !$(ต้นกำเนิด).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(อินพุต) -o $(เอาต์พุต)

รวม foobar.d

ใช้ makepp_cookbook ออนไลน์โดยใช้บริการ onworks.net


เซิร์ฟเวอร์และเวิร์กสเตชันฟรี

ดาวน์โหลดแอพ Windows & Linux

คำสั่ง Linux

Ad