การทำความเข้าใจไวยากรณ์ Makefile: ปัญหาทั่วไปและแนวทางแก้ไข (รวมถึง 'ตัวดำเนินการที่หายไป' และ 'ไม่พบจุดเข้าใช้งาน')

Kar Thakhwam Kheaci Wiyakrn Makefile Payha Thawpi Laea Naewthang Kaekhi Rwm Thung Taw Danein Kar Thi Hay Pi Laea Mi Phb Cud Khea Chi Ngan



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

ทำความเข้าใจเกี่ยวกับไวยากรณ์พื้นฐานของ Makefile

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







ตัวแปร s: ข้อมูลพื้นฐานที่จัดเก็บอ็อบเจ็กต์ที่จำเป็นเพื่อใช้ใน makefile ตัวแปรเหล่านี้ใช้เพื่อระบุคอมไพลเลอร์ แฟล็ก ไฟล์ต้นฉบับ ไฟล์อ็อบเจ็กต์ และไฟล์เป้าหมาย ภายใน makefile ตัวอย่างต่อไปนี้ มีตัวแปรทั้งหมดห้าตัว ได้แก่ CXX (เพื่อตั้งค่าคอมไพลเลอร์ C++), CXXFLAGSc (แฟล็กคอมไพเลอร์), TARGET (เพื่อตั้งชื่อไฟล์ปฏิบัติการเป้าหมาย), SRCS (เพื่อตั้งค่าไฟล์ซอร์สโค้ด) , OBJS (เพื่อให้มีไฟล์อ็อบเจ็กต์ที่สร้างขึ้นผ่านไฟล์ซอร์สโค้ด)



เป้าหมาย: เอาต์พุตที่คาดว่าจะสร้างจากแหล่งที่มา อาจเป็นไฟล์เป้าหมายหรือชื่อสัญลักษณ์ใดก็ได้: “all” เป็นเป้าหมายเริ่มต้นที่ควรสร้างผ่านตัวแปร “TARGET” “$TARGET” ขึ้นอยู่กับตัวแปร “OBJS” และเป้าหมาย “clean” จะลบเป้าหมายและ ไฟล์อ็อบเจ็กต์จากไดเร็กทอรีการทำงาน



กฎและคำสั่งการสร้าง: ชุดคำสั่งพื้นฐานที่จะดำเนินการเพื่อสร้างเป้าหมายจากไฟล์ต้นฉบับหรือการอ้างอิง ตัวอย่างเช่น กฎ “%.o: %.cpp” แสดงว่าไฟล์ที่มีนามสกุล “cpp” ใช้เพื่อสร้างไฟล์อ็อบเจ็กต์ที่มีนามสกุล “o” ในขณะที่ทั้งสองไฟล์มีชื่อเดียวกัน ในทางกลับกันคำสั่ง build $(CXX) $(CXXFLAGS) -o $(เป้าหมาย) $(OBJS) ใช้เพื่อเชื่อมโยงไฟล์อ็อบเจ็กต์และไฟล์เป้าหมายใหม่เข้าด้วยกัน ในทำนองเดียวกันคำสั่ง build $(CXX) $(CXXFLAGS) -c $< -o $@ รวบรวมไฟล์ต้นฉบับเป็นไฟล์อ็อบเจ็กต์





การพึ่งพา: การขึ้นต่อกันจะอยู่ที่นั่นเสมอเมื่อคุณต้องการสร้าง makefile ตัวอย่างเช่น เป้าหมาย 'ทั้งหมด' ขึ้นอยู่กับตัวแปร 'TARGET' ในขณะที่ 'TARGET' ขึ้นอยู่กับตัวแปร 'OBJS' ในเวลาเดียวกัน ตัวแปร “OBJS” ขึ้นอยู่กับไฟล์ต้นฉบับผ่านตัวแปร “SRCS”

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



ซีเอ็กซ์ = ก++
CXXFLAGS = -มาตรฐาน =ค++ สิบเอ็ด -กำแพง
เป้าหมาย = ใหม่
SRCS = main.cpp
OBJS = $ ( SRCS:.cpp=.o )
ทั้งหมด: $ ( เป้า )
$ ( เป้า ) : $ ( โอบีเจ )
$ ( ซีเอ็กซ์เอ็กซ์ ) $ ( CXXFLAGS ) -โอ $ ( เป้า ) $ ( โอบีเจ )
% .โอ: % .ซีพีพี
$ ( ซีเอ็กซ์เอ็กซ์ ) $ ( CXXFLAGS ) -ค $ < -โอ $ @
ทำความสะอาด:
RM -ฉ $ ( เป้า ) $ ( โอบีเจ )

ปัญหาทั่วไปและแนวทางแก้ไข

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

1: ไม่ใช้ตัวแปร

การใช้ตัวแปรใน makefile เป็นสิ่งที่ต้องมี เนื่องจากจำเป็นต้องตั้งค่าคอมไพลเลอร์ เป้าหมาย ไฟล์ต้นฉบับ ฯลฯ ปัญหาที่พบบ่อยที่สุดที่สามารถพบได้คือการไม่ใช้ตัวแปรใดๆ ใน makefile ดังนั้น ตรวจสอบให้แน่ใจว่าใช้ตัวแปรที่จำเป็น เช่น CXX, CXXFLAGSc(แฟล็กคอมไพเลอร์), TARGET, SRCS และ OBJS ใน makefile ตัวอย่างก่อนหน้า

2: ปัญหาตัวคั่นหายไป

ในขณะที่เขียน makefile จำเป็นต้องพิจารณากฎการเยื้องอย่างระมัดระวัง เนื่องจากการใช้ช่องว่างแทนแท็บจะนำคุณไปสู่ปัญหา “ตัวคั่นที่ขาดหายไป” ในระหว่างการดำเนินการคำสั่ง “make” ตัวอย่างเช่น เราเพิ่มช่องว่างที่จุดเริ่มต้นของกฎที่บรรทัด 13 และลบแท็บออก

$ ( เป้า ) : $ ( โอบีเจ )
$ ( ซีเอ็กซ์เอ็กซ์ ) $ ( CXXFLAGS ) -โอ $ ( เป้า ) $ ( โอบีเจ )

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

ทำ

เพื่อหลีกเลี่ยงปัญหานี้ ตรวจสอบให้แน่ใจว่าใช้ 'แท็บ' แทนการเว้นวรรคดังที่ปรากฎในภาพต่อไปนี้:

$ ( เป้า ) : $ ( โอบีเจ )
$ ( ซีเอ็กซ์เอ็กซ์ ) $ ( CXXFLAGS ) -โอ $ ( เป้า ) $ ( โอบีเจ )

3: ปัญหา “ไม่พบจุดเข้าใช้งาน”

ข้อผิดพลาดนี้ส่วนใหญ่เกิดขึ้นเนื่องจากไฟล์ต้นฉบับ ไม่ใช่เพราะ makefile เช่นเมื่อคุณพลาดการใช้ฟังก์ชัน 'main()' ในไฟล์ซอร์สโค้ด ตัวอย่างเช่น เราแทนที่นิยามฟังก์ชัน main() ด้วยการประกาศฟังก์ชันที่ผู้ใช้กำหนดอย่างง่าย

#รวม
อินท์โชว์ ( ) {
ถ่านวี;
มาตรฐาน::cout << 'ป้อนค่า:' ;
มาตรฐาน::cin >> ใน;
มาตรฐาน::cout << ใน << มาตรฐาน::endl;
กลับ 0 ;
}

เมื่อดำเนินการคำสั่ง 'make' บนพรอมต์คำสั่งของ Windows เราพบ 'การอ้างอิงที่ไม่ได้กำหนดไปยัง 'WinMain'' เนื่องจากคอมไพเลอร์ไม่พบจุดเริ่มต้นใด ๆ เพื่อเริ่มเรียกใช้งานไฟล์ C++ หากต้องการแก้ไขปัญหานี้ ให้แทนที่ 'show' ด้วย 'main'

4: การใช้ส่วนขยายที่ไม่ถูกต้อง

บางครั้งผู้ใช้อาจใช้นามสกุลที่ไม่ถูกต้องสำหรับไฟล์ต้นฉบับที่จะใช้ใน makefile โดยไม่ได้ตั้งใจ การใช้ส่วนขยายที่ไม่ถูกต้องจะทำให้เกิดข้อผิดพลาดรันไทม์ กล่าวคือ ไม่มีกฎในการสร้างเป้าหมาย เราสร้าง makefile เพื่อสร้างไฟล์ปฏิบัติการและไฟล์อ็อบเจ็กต์สำหรับไฟล์ C++ ในบรรทัดที่ 7 เราจัดเตรียมไฟล์ต้นฉบับที่มีนามสกุล “c”

CXX := ก++
CXXFLAGS := -มาตรฐาน =ค++ สิบเอ็ด -กำแพง
เป้าหมาย = ใหม่
SRCS = main.c
OBJS = $ ( SRCS:.cpp=.o )
ทั้งหมด: $ ( เป้า )
$ ( เป้า ) : $ ( โอบีเจ )

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

ทำ

5: ขาดการพึ่งพา

ขณะเขียน makefile คุณควรรวมการอ้างอิงทั้งหมดสำหรับไฟล์ต้นฉบับเพื่อรับเอาต์พุตที่ต้องการ ตัวอย่างเช่น ไฟล์โค้ด C++ ของเราใช้ไฟล์ 'myheader.h' เป็นตัวอ้างอิง ดังนั้นเราจึงกล่าวถึงมันในไฟล์โค้ด C++ ดังนี้:

#รวม
#รวม “myheader.h”
อินท์โชว์ ( ) {
ถ่านวี;
มาตรฐาน::cout << 'ป้อนค่า:' ;
มาตรฐาน::cin >> ใน;
มาตรฐาน::cout << ใน << มาตรฐาน::endl;
กลับ 0 ;
}

ภายใน makefile เราจงใจเพิกเฉยต่อการใช้ไฟล์ 'myheader.h' ภายในกฎการสร้างที่เขียนไว้ที่บรรทัดที่ 9

% .โอ: % .ซีพีพี
$ ( ซีเอ็กซ์เอ็กซ์ ) $ ( CXXFLAGS ) -ค $ < -โอ $ @

ขณะนี้ ขณะที่ใช้คำสั่ง 'make' เราพบข้อผิดพลาด 'ไม่มีอะไรที่ต้องทำสำหรับ 'ทั้งหมด'

ทำ

% .โอ: % .cpp myheader.h
$ ( ซีเอ็กซ์เอ็กซ์ ) $ ( CXXFLAGS ) -ค $ < -โอ $ @

เพื่อหลีกเลี่ยงปัญหาดังกล่าวและเรียกใช้ซอร์สโค้ดได้สำเร็จ ให้ระบุชื่อไฟล์ “myheader.h” ที่บรรทัดที่เก้าของ makefile ดังที่แสดงไว้ต่อไปนี้:

บทสรุป

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