ความแตกต่างระหว่างการใช้ Makefile และ CMake เพื่อคอมไพล์โค้ด


288

ฉันใช้รหัสใน C / C ++ และใช้ Makefile (GNU) เพื่อรวบรวมรหัส ฉันสามารถทำเช่นเดียวกันกับ CMake และรับ MakeFile อย่างไรก็ตามความแตกต่างระหว่างการใช้ Makefile และ CMake เพื่อรวบรวมรหัสคืออะไร?


2
cmake ยังสามารถสร้างไฟล์เพื่อใช้นินจาได้ด้วย
B --овић

คำตอบ:


403

Make (หรือค่อนข้าง Makefile) เป็น buildsystem - มันเป็นตัวขับเคลื่อนคอมไพเลอร์และเครื่องมือสร้างอื่น ๆ เพื่อสร้างรหัสของคุณ

CMake เป็นตัวกำเนิดของ buildsystems มันสามารถผลิต Makefiles, มันสามารถสร้างนินจาสร้างไฟล์, มันสามารถผลิตโครงการ KDEvelop หรือ Xcode, มันสามารถผลิตโซลูชั่น Visual Studio จากจุดเริ่มต้นเดียวกันไฟล์ CMakeLists.txt เดียวกัน ดังนั้นถ้าคุณมีโปรเจ็กต์ที่ไม่ขึ้นกับแพลตฟอร์ม CMake เป็นวิธีที่จะทำให้บิวด์เป็นอิสระจากระบบเช่นกัน

หากคุณมีนักพัฒนา Windows ที่คุ้นเคยกับนักพัฒนา Visual Studio และ Unix ที่สาบานด้วย GNU Make CMake คือหนึ่งในวิธีที่จะไป

ฉันมักจะแนะนำให้ใช้ CMake (หรือตัวสร้าง buildsystem อื่น แต่ CMake เป็นความชอบส่วนตัวของฉัน) หากคุณต้องการให้โครงการของคุณเป็นแบบหลายแพลตฟอร์มหรือใช้งานได้อย่างกว้างขวาง CMake เองยังมีคุณสมบัติที่ดีเช่นการตรวจจับการพึ่งพาการจัดการส่วนต่อประสานห้องสมุดหรือการรวมเข้ากับ CTest, CDash และ CPack

การใช้ตัวสร้างระบบสร้างทำให้โครงการของคุณพิสูจน์ได้ในอนาคต แม้ว่าคุณจะเป็น GNU-Make-only ในตอนนี้ถ้าคุณตัดสินใจที่จะขยายไปยังแพลตฟอร์มอื่น ๆ ในภายหลัง (ไม่ว่าจะเป็น Windows หรือบางอย่างที่ฝังอยู่) หรือเพียงแค่ต้องการใช้ IDE


5
@ ใช่ใช่นั่นคือส่วนสำคัญ อย่างไรก็ตามโปรดทราบว่ามีวิธีการเขียนโปรแกรมบน Linux มากกว่า Makefiles - ดูเช่น QtCreator, KDEvelop, Ninja สำหรับแต่ละรายการ "สร้างโครงการและซิงค์กับ Makefile" หรือ "เรียกใช้ CMake อีกครั้ง" และตามคำตอบที่กล่าวมา CMake ก็มีฟังก์ชั่นอื่น ๆ เช่นการค้นพบการพึ่งพา (เช่นfind_package()) หรือการสนับสนุนการทดสอบ / บรรจุภัณฑ์
Angew ไม่ภูมิใจใน SO

3
ฉันอ่านว่า CMake ไม่สามารถสร้างไฟล์ที่ไม่เรียกซ้ำ นั่นเป็นเรื่องจริงหรือไม่
Maxim Egorushkin

1
@Angew Non-recursiveคือเมื่อ make ถูกเรียกใช้หนึ่งครั้งด้วยแผนผังการพึ่งพาโปรเจ็กต์ที่สมบูรณ์ ตรงข้ามกับการเรียกซ้ำเมื่อ makefile ระดับบนสุดเรียกใช้ makefiles โครงการย่อยตามลำดับที่แน่นอน
Maxim Egorushkin

3
นี่เป็นจุดอ่อนที่สำคัญของ CMake - GNU make มีรอยย่น แต่ถ้าคุณใช้เวลาในการเรียนรู้มันมีพลังและใช้งานได้หลากหลายและทำงานบนแพลตฟอร์มจำนวนมหาศาล การไม่มีแผนภูมิการพึ่งพาที่สมบูรณ์ในการวิเคราะห์เป็นข้อบกพร่องที่สำคัญเพียงแค่ Google สำหรับ 'การเรียกซ้ำให้ถือว่าเป็นอันตราย'
Erik Alapää

1
@ ErikAlapääฉันจะอ่านรายละเอียดบทความ แต่จากการดูครั้งแรก - พวกเขากำลังพูดถึง recursive make โดยที่ความลึกของการเรียกซ้ำเป็นตัวขับเคลื่อนข้อมูล (เช่นขึ้นอยู่กับความลึกของไดเรกทอรีต้นทางเป็นต้น) นั่นไม่ใช่กรณีของ CMake: ความลึกรวมของการเรียกใช้เป็น 3 เสมอโดยไม่คำนึงถึงโครงสร้างโครงการ เป็นเพียงการที่บิตบางส่วนถูกมอบหมายให้กับ submakefile แทนที่จะเป็นหนึ่งเดียว แต่มันไม่ได้สะท้อนโครงสร้างโครงการในทางใดทางหนึ่ง ยิ่งไปกว่านั้น submakefiles ไม่ใช่ "อยู่ในตัวเอง" จริงๆดังนั้นพวกเขาจึงไม่ประสบปัญหาการพึ่งพาสูง / ต่ำ
Angew ไม่ภูมิใจใน SO

39

คำสั่งเกี่ยวกับ CMake การเป็น "สร้างเครื่องกำเนิด" เป็นความเข้าใจผิดที่พบบ่อย

มันไม่ผิดทางเทคนิค มันแค่อธิบายว่ามันทำงานอย่างไร แต่ไม่ใช่สิ่งที่มันทำ

ในบริบทของคำถามพวกเขาทำสิ่งเดียวกัน: นำไฟล์ C / C ++ มารวมกันและแปลงให้เป็นไบนารี

ดังนั้นความแตกต่างที่แท้จริงคืออะไร?

  • CMake เป็นระดับสูงมากขึ้น มันเหมาะกับการคอมไพล์ C ++ ซึ่งคุณเขียนโค้ดบิลด์น้อยกว่ามาก แต่สามารถใช้สำหรับบิลด์เอนกประสงค์ได้เช่นกัน makeมีกฎ C / C ++ ในตัวเช่นกัน แต่ส่วนใหญ่จะไร้ประโยชน์

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

  • ไวยากรณ์ของCMakeง่ายมากที่จะได้รับการสนับสนุนเครื่องมือภายนอกกว่ายี่ห้อของ

  • เมื่อmakeสร้างสิ่งประดิษฐ์มันจะลืมวิธีการสร้าง แหล่งข้อมูลใดที่ถูกสร้างขึ้นจากคอมไพเลอร์ธงอะไร CMakeติดตามมันmakeทิ้งมันไว้กับคุณ หากหนึ่งในแหล่งที่มาของห้องสมุดจะถูกลบออกตั้งแต่รุ่นก่อนหน้าของMakefile, makeจะไม่สร้างมัน

  • โมเดิร์นCMake(เริ่มต้นด้วยรุ่น 3. บางอย่าง) ทำงานในแง่ของการพึ่งพาระหว่าง "เป้าหมาย" เป้าหมายยังคงเป็นไฟล์ otput ไฟล์เดียว (น่าเศร้า) แต่สามารถมีการถ่ายทอด ("สาธารณะ" / "ส่วนต่อประสาน" ในเงื่อนไข CMake) สกรรมกริยาอ้างอิงเหล่านี้สามารถสัมผัสหรือซ่อนตัวจากแพ็คเกจพึ่งพา CMakeจะจัดการไดเรกทอรีให้คุณด้วย ด้วยmakeคุณติดอยู่ในระดับไฟล์ต่อไฟล์และจัดการไดเรกทอรีโดยมือ

คุณสามารถเขียนโค้ดบางอย่างในการmakeใช้ไฟล์ตั้งค่าสถานะเพื่อให้ครอบคลุมช่องว่างสองช่องที่ผ่านมา makeมีภาษาที่สมบูรณ์ของทัวริง (แม้แต่สองครั้งบางครั้งก็นับสามคนโกง ) และพวกเขาทั้งหมดน่ากลัว

จะซื่อสัตย์นี้เป็นสิ่งที่CMakeและmakeมีเหมือนกัน - ภาษาของพวกเขาจะน่ากลัวสวย:

  • พวกเขาไม่มีประเภท;
  • ไม่มีอาร์เรย์มีเพียงสตริงที่คั่นด้วยช่องว่างเท่านั้น
  • คุณมักจะส่งผ่านข้อโต้แย้งไปยังฟังก์ชั่นโดยการตั้งค่าตัวแปรทั่วโลก; (สิ่งนี้กำลังถูกจัดการใน CMake สมัยใหม่ - ตัวแปรสามารถมีเนมสเปซได้ในขณะนี้เป้าหมายคือเนมสเปซสำหรับคุณสมบัติของมัน)
  • การอ้างถึงตัวแปรที่ไม่ได้กำหนดจะถูกละเว้นโดยปริยาย

จะเริ่มต้นด้วย.

แต่ในCMakeคุณเขียนโค้ดน้อยกว่ามาก


1
ข้อมูลที่ดีบางอย่างที่นี่ แต่มีหนึ่งคำพูดที่ผิดอย่างสมบูรณ์: cmake มีรายการ LIST เนื่องจากมีฟังก์ชั่น LIST ที่เหมาะสมซึ่งเป็นสิ่งสำคัญสำหรับงานสร้างระบบจำนวนมากแตกต่างกันเล็กน้อย: cmake.org/cmake/help/git-master/command /list.html
แก้ปัญหา J

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