CMake ใช้อย่างไร? [ปิด]


100

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

การเรียก CMake บน CMakeLists หมายความว่าอย่างไร มันควรจะเรียกว่าหนึ่งครั้งต่อการสร้างต้นไม้หรืออะไร? ฉันจะใช้การตั้งค่าที่แตกต่างกันสำหรับแต่ละบิลด์ได้อย่างไรหากพวกเขาทั้งหมดใช้ไฟล์ CMakeLists.txt เดียวกันจากแหล่งเดียวกัน เหตุใดแต่ละไดเรกทอรีย่อยจึงต้องการไฟล์ CMakeLists ของตัวเอง ควรใช้ CMake บน CMakeLists.txt อื่นที่ไม่ใช่ที่รากของโปรเจ็กต์หรือไม่ ถ้าเป็นเช่นนั้นในกรณีใด อะไรคือความแตกต่างระหว่างการระบุวิธีสร้างไฟล์ปฏิบัติการหรือไลบรารีจากไฟล์ CMakeLists ในไดเร็กทอรีย่อยของตัวเองกับการทำในไฟล์ CMakeLists ที่รากของแหล่งที่มาทั้งหมด ฉันสามารถสร้างโปรเจ็กต์สำหรับ Eclipse และอีกโปรเจ็กต์สำหรับ Visual Studio ได้หรือไม่เพียงแค่เปลี่ยนตัว-Gเลือกเมื่อเรียกใช้ CMake แม้จะใช้อย่างไร?

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

มีคำถามมากมายที่ถามโดย CMake มือใหม่เช่นฉันซึ่งไม่ได้ถามอย่างชัดเจน แต่นั่นทำให้เห็นได้ชัดว่าในฐานะมือใหม่เราไม่มีความคิดที่จะจัดการกับ CMake หรือจะทำอย่างไร


8
บางทีคุณควรเขียนบล็อกโพสต์แทน
steveire

2
ฉันอยากจะปิดโหวตแบบ "กว้างเกินไป" ... นี่ให้ความรู้สึกเหมือนเรียงความส่วนตัวใน CMake มากกว่าแบบที่ดีสำหรับ stackoverflow ทำไมคุณไม่ใส่คำถามเหล่านี้ทั้งหมดเป็นคำถามแยกกัน? และคำถาม + คำตอบของคุณแตกต่างจากคนอื่น ๆ อย่างไรเช่นstackoverflow.com/q/20884380/417197 , stackoverflow.com/q/4745996/417197 , stackoverflow.com/q/4506193/417197 ?
André

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

2
ไม่ได้คำตอบ แต่ผมขอเชิญคุณมีลักษณะที่jaws.rootdirectory.de ในขณะที่ CMake dokumentation (และคำตอบที่ยอมรับ ... ) แสดงให้คุณเห็นตัวอย่างขนาดพอดีคำจำนวนมากเกี่ยวกับสิ่งที่คุณสามารถทำได้ฉันได้เขียนการตั้งค่าพื้นฐาน (โดยไม่ได้หมายความว่า "เสร็จสมบูรณ์" หรือ "สมบูรณ์แบบ") รวมถึงความคิดเห็นตลอดว่า IMHO นำเสนอสิ่งที่ CMake (และ CTest และ CPack และ CDash ... ) สามารถทำเพื่อคุณได้ สร้างขึ้นจากกรอบและคุณสามารถปรับเปลี่ยน / ขยายให้เข้ากับความต้องการของโครงการได้อย่างง่ายดาย
DevSolar

10
น่าเสียดายที่คำถามดังกล่าวถูกปิดลงในปัจจุบัน ฉันคิดว่าคำถามกว้าง ๆ ที่ต้องการการสอนเช่นคำตอบ แต่เกี่ยวกับหัวข้อที่มีเอกสารไม่ดี / คลุมเครือ (อีกตัวอย่างหนึ่งคือ Torch7 C api) และคำถามระดับการวิจัยควรยังคงเปิดอยู่ นี่เป็นวิธีที่น่าสนใจกว่าที่คำว่า "เฮ้ฉันมีความผิดพลาดเมื่อทำโครงการของเล่น" ที่ทำให้ไซต์เสียหาย
เถ้า

คำตอบ:


145

CMake มีไว้ทำอะไร?

อ้างอิงจาก Wikipedia:

CMake เป็นซอฟต์แวร์ [... ] สำหรับจัดการกระบวนการสร้างซอฟต์แวร์โดยใช้วิธีการที่ไม่ขึ้นกับคอมไพเลอร์ ได้รับการออกแบบมาเพื่อรองรับลำดับชั้นของไดเร็กทอรีและแอพพลิเคชั่นที่ขึ้นอยู่กับหลายไลบรารี ใช้ร่วมกับสภาพแวดล้อมการสร้างแบบเนทีฟเช่น make, Xcode ของ Apple และ Microsoft Visual Studio

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

CMake สามารถสร้างโซลูชัน Microsoft Visual Studio โครงการ Eclipse หรือเขาวงกต Makefile จากไฟล์เดียวกันโดยไม่ต้องเปลี่ยนแปลงอะไรเลย

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

หากตั้งค่าอย่างถูกต้องคุณจะใช้ CMake เพื่อสร้างไฟล์ทั้งหมดที่ "สภาพแวดล้อมการสร้างแบบเนทีฟ" ที่คุณเลือกต้องใช้ในการทำงาน โดยค่าเริ่มต้นใน Linux หมายถึง Makefiles ดังนั้นเมื่อคุณเรียกใช้ CMake มันจะสร้างไฟล์จำนวนมากสำหรับการใช้งานของมันเองบวกกับไฟล์บางMakefileไฟล์ สิ่งที่คุณต้องทำหลังจากนั้นคือพิมพ์ "make" ในคอนโซลจากโฟลเดอร์รูททุกครั้งที่คุณแก้ไขโค้ดของคุณเสร็จและ bam จะทำการคอมไพล์และเชื่อมโยงปฏิบัติการ

CMake ทำงานอย่างไร? มันทำอะไร?

นี่คือตัวอย่างการตั้งค่าโครงการที่ฉันจะใช้ตลอด:

simple/
  CMakeLists.txt
  src/
    tutorial.cxx
    CMakeLists.txt
  lib/
    TestLib.cxx
    TestLib.h
    CMakeLists.txt
  build/

เนื้อหาของแต่ละไฟล์จะถูกแสดงและกล่าวถึงในภายหลัง

CMake ตั้งค่าโปรเจ็กต์ของคุณตามรูท CMakeLists.txtของโปรเจ็กต์ของคุณและทำในไดเร็กทอรีใดก็ได้ที่คุณเรียกใช้cmakeจากคอนโซล การทำเช่นนี้จากโฟลเดอร์ที่ไม่ใช่รูทของโปรเจ็กต์ของคุณจะสร้างสิ่งที่เรียกว่าบิลด์นอกแหล่งซึ่งหมายถึงไฟล์ที่สร้างระหว่างการคอมไพล์ (ไฟล์ obj, ไฟล์ lib, ไฟล์ปฏิบัติการที่คุณรู้) จะถูกวางไว้ในโฟลเดอร์ดังกล่าว แยกต่างหากจากรหัสจริง ช่วยลดความยุ่งเหยิงและเป็นที่ต้องการสำหรับเหตุผลอื่น ๆ ด้วยซึ่งฉันจะไม่พูดถึง

ฉันไม่รู้ว่าจะเกิดอะไรขึ้นถ้าคุณดำเนินการcmakeกับสิ่งอื่นที่ไม่ใช่รูCMakeLists.txt

ในตัวอย่างนี้เนื่องจากฉันต้องการให้ทุกอย่างอยู่ในbuild/โฟลเดอร์ก่อนอื่นฉันต้องไปที่นั่นจากนั้นส่ง CMake ไดเรกทอรีที่มีรูทCMakeLists.txtอยู่

cd build
cmake ..

โดยค่าเริ่มต้นจะตั้งค่าทุกอย่างโดยใช้ Makefiles ตามที่ฉันได้กล่าวไป นี่คือลักษณะของโฟลเดอร์ build ในตอนนี้:

simple/build/
  CMakeCache.txt
  cmake_install.cmake
  Makefile
  CMakeFiles/
    (...)
  src/
    CMakeFiles/
      (...)
    cmake_install.cmake
    Makefile
  lib/
    CMakeFiles/
      (...)
    cmake_install.cmake
    Makefile

ไฟล์เหล่านี้คืออะไร? สิ่งเดียวที่คุณต้องกังวลเกี่ยวกับเป็น Makefile และโฟลเดอร์โครงการ

สังเกตsrc/และlib/โฟลเดอร์ เหล่านี้ได้รับการสร้างขึ้นเพราะจุดที่จะให้พวกเขาใช้คำสั่งsimple/CMakeLists.txt add_subdirectory(<folder>)คำสั่งนี้จะบอก CMake ที่จะมองในโฟลเดอร์กล่าวอีกCMakeLists.txtไฟล์และดำเนินการที่สคริปต์เพื่อเพิ่มไดเรกทอรีย่อยด้วยวิธีนี้ทุกต้องมีCMakeLists.txtไฟล์ภายใน ในโครงการนี้simple/src/CMakeLists.txtอธิบายถึงวิธีการสร้างไฟล์ปฏิบัติการจริงและsimple/lib/CMakeLists.txtอธิบายวิธีการสร้างไลบรารี ทุกเป้าหมายที่CMakeLists.txtอธิบายจะถูกวางโดยค่าเริ่มต้นในไดเรกทอรีย่อยภายในโครงสร้างโครงสร้าง ดังนั้นหลังจากนั้นอย่างรวดเร็ว

make

ในคอนโซลเสร็จสิ้นbuild/มีการเพิ่มไฟล์บางไฟล์:

simple/build/
  (...)
  lib/
    libTestLib.a
    (...)
  src/
    Tutorial
    (...)

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

ฉันจะบอก CMake ว่าจะสร้างโครงการของฉันได้อย่างไร

นี่คือเนื้อหาอธิบายของแต่ละไฟล์ในไดเร็กทอรีต้นทาง:

simple/CMakeLists.txt:

cmake_minimum_required(VERSION 2.6)

project(Tutorial)

# Add all subdirectories in this project
add_subdirectory(lib)
add_subdirectory(src)

ควรตั้งค่าเวอร์ชันขั้นต่ำที่จำเป็นเสมอตามคำเตือนที่ CMake จะพ่นเมื่อคุณไม่ทำ ใช้ CMake เวอร์ชันใดก็ได้

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

ดังที่ได้กล่าวไว้ก่อนหน้านี้ให้add_subdirectory()เพิ่มโฟลเดอร์ในโครงการซึ่งหมายความว่า CMake คาดว่าจะมีCMakeLists.txtภายในซึ่งจะเรียกใช้ก่อนดำเนินการต่อ อย่างไรก็ตามหากคุณมีฟังก์ชัน CMake ที่กำหนดไว้คุณสามารถใช้งานได้จากCMakeLists.txts อื่น ๆในไดเรกทอรีย่อย แต่คุณต้องกำหนดก่อนที่จะใช้add_subdirectory()ไม่เช่นนั้นจะไม่พบ CMake ฉลาดกว่าเกี่ยวกับไลบรารีดังนั้นนี่เป็นครั้งเดียวที่คุณจะพบปัญหาประเภทนี้

simple/lib/CMakeLists.txt:

add_library(TestLib TestLib.cxx)

ในการสร้างไลบรารีของคุณเองคุณต้องตั้งชื่อแล้วแสดงรายการไฟล์ทั้งหมดที่สร้างขึ้นจาก ตรงไปตรงมา. ถ้ามันจำเป็นไฟล์อื่นจะได้รับการรวบรวมคุณจะเขียนแทนfoo.cxx add_library(TestLib TestLib.cxx foo.cxx)นี้ยังสามารถใช้ได้กับไฟล์ในไดเรกทอรีอื่น ๆ add_library(TestLib TestLib.cxx ${CMAKE_SOURCE_DIR}/foo.cxx)เช่น เพิ่มเติมเกี่ยวกับตัวแปร CMAKE_SOURCE_DIR ในภายหลัง

สิ่งที่คุณสามารถทำได้อีกอย่างคือระบุว่าคุณต้องการไลบรารีที่ใช้ร่วมกัน ตัวอย่าง: add_library(TestLib SHARED TestLib.cxx). ไม่ต้องกลัวนี่คือจุดที่ CMake เริ่มทำให้ชีวิตของคุณง่ายขึ้น ไม่ว่าจะแชร์หรือไม่ก็ตามตอนนี้สิ่งที่คุณต้องจัดการเพื่อใช้ไลบรารีที่สร้างด้วยวิธีนี้คือชื่อที่คุณตั้งไว้ที่นี่ ตอนนี้ชื่อของไลบรารีนี้คือ TestLib และคุณสามารถอ้างอิงได้จากทุกที่ในโครงการ CMake จะพบมัน

มีวิธีที่ดีกว่าในการแสดงรายการการอ้างอิงหรือไม่? ใช่แน่นอน ตรวจสอบด้านล่างสำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้

simple/lib/TestLib.cxx:

#include <stdio.h>

void test() {
  printf("testing...\n");
}

simple/lib/TestLib.h:

#ifndef TestLib
#define TestLib

void test();

#endif

simple/src/CMakeLists.txt:

# Name the executable and all resources it depends on directly
add_executable(Tutorial tutorial.cxx)

# Link to needed libraries
target_link_libraries(Tutorial TestLib)

# Tell CMake where to look for the .h files
target_include_directories(Tutorial PUBLIC ${CMAKE_SOURCE_DIR}/lib)

คำสั่งadd_executable()ทำงานเหมือนกับadd_library()ยกเว้นแน่นอนว่ามันจะสร้างไฟล์ปฏิบัติการแทน ตอนนี้ไฟล์ปฏิบัติการนี้สามารถอ้างอิงเป็นเป้าหมายสำหรับสิ่งต่างๆเช่นtarget_link_libraries(). เนื่องจาก tutorial.cxx ใช้รหัสที่พบในไลบรารี TestLib คุณจึงชี้ให้ CMake ดังที่แสดง

ในทำนองเดียวกันไฟล์. h ใด ๆ # รวมโดยแหล่งที่มาใด ๆadd_executable()ที่ไม่ได้อยู่ในไดเร็กทอรีเดียวกันกับแหล่งที่มาจะต้องถูกเพิ่มเข้าไป หากไม่ใช่target_include_directories()คำสั่งlib/TestLib.hจะไม่พบเมื่อคอมไพล์บทช่วยสอนดังนั้นทั้งlib/โฟลเดอร์จึงถูกเพิ่มไปยังไดเร็กทอรี include เพื่อค้นหา #includes นอกจากนี้คุณอาจเห็นคำสั่งinclude_directories()ที่ทำงานในลักษณะคล้ายกันยกเว้นว่าคุณไม่ต้องการให้คุณระบุเป้าหมายเนื่องจากจะตั้งค่าทันทีทั่วโลกสำหรับไฟล์ปฏิบัติการทั้งหมด อีกครั้งฉันจะอธิบาย CMAKE_SOURCE_DIR ในภายหลัง

simple/src/tutorial.cxx:

#include <stdio.h>
#include "TestLib.h"
int main (int argc, char *argv[])
{
  test();
  fprintf(stdout, "Main\n");
  return 0;
}

สังเกตว่าไฟล์ "TestLib.h" รวมอยู่อย่างไร ไม่จำเป็นต้องรวมเส้นทางแบบเต็ม: CMake target_include_directories()ดูแลทุกสิ่งที่อยู่เบื้องหลังต้องขอบคุณ

เทคนิคการพูดในแหล่งต้นไม้ง่ายๆเช่นนี้คุณสามารถทำได้โดยไม่ต้องCMakeLists.txtภายใต้lib/และsrc/และเพียงแค่เพิ่มสิ่งที่ต้องการที่จะadd_executable(Tutorial src/tutorial.cxx) simple/CMakeLists.txtขึ้นอยู่กับคุณและความต้องการของโครงการของคุณ

ฉันควรรู้อะไรอีกบ้างเพื่อใช้ CMake อย่างถูกต้อง

(หัวข้อ AKA ที่เกี่ยวข้องกับความเข้าใจของคุณ)

การค้นหาและใช้แพ็คเกจ : คำตอบสำหรับคำถามนี้อธิบายได้ดีกว่าที่ฉันเคยทำได้

การประกาศตัวแปรและฟังก์ชั่นการใช้โฟลว์การควบคุม ฯลฯ : ดูบทช่วยสอนนี้ซึ่งอธิบายถึงพื้นฐานของสิ่งที่ CMake นำเสนอตลอดจนเป็นการแนะนำที่ดีโดยทั่วไป

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

คุณอาจต้องการแก้ไขตัวแปรบางตัวโดยไม่ต้องสร้างโครงสร้างสร้างใหม่ ใช้ ccmake สำหรับสิ่งนี้ (มันแก้ไขCMakeCache.txtไฟล์) อย่าลืมcกำหนดค่าเมื่อเสร็จสิ้นกับการเปลี่ยนแปลงแล้วจึงgจัดทำ makefiles ด้วยการกำหนดค่าที่อัปเดต

อ่านบทแนะนำที่อ้างถึงก่อนหน้านี้เพื่อเรียนรู้เกี่ยวกับการใช้ตัวแปร แต่เรื่องยาวสั้น: set(<variable name> value)เพื่อเปลี่ยนหรือสร้างตัวแปร ${<variable name>}ที่จะใช้มัน

  • CMAKE_SOURCE_DIR: ไดเร็กทอรีรากของซอร์ส ในตัวอย่างก่อนหน้านี้จะเท่ากับ/simple
  • CMAKE_BINARY_DIR: ไดเร็กทอรีรากของบิลด์ ในตัวอย่างก่อนหน้านี้จะเท่ากับsimple/build/แต่ถ้าคุณวิ่งcmake simple/จากโฟลเดอร์เช่นfoo/bar/etc/นั้นการอ้างอิงถึงในการที่สร้างต้นไม้ก็จะกลายเป็นCMAKE_BINARY_DIR/foo/bar/etc
  • CMAKE_CURRENT_SOURCE_DIR: ไดเรกทอรีที่ปัจจุบันCMakeLists.txtอยู่ในวิธีการนี้มันเปลี่ยนแปลงตลอด:. พิมพ์นี้จากsimple/CMakeLists.txtอัตราผลตอบแทน/simpleและการพิมพ์ได้จากอัตราผลตอบแทนsimple/src/CMakeLists.txt/simple/src
  • CMAKE_CURRENT_BINARY_DIR: คุณเข้าใจแล้ว เส้นทางนี้ไม่เพียงขึ้นอยู่กับโฟลเดอร์ที่สร้างอยู่ แต่ยังขึ้นอยู่กับตำแหน่งCMakeLists.txtของสคริปต์ปัจจุบันด้วย

เหตุใดสิ่งเหล่านี้จึงสำคัญ ไฟล์ต้นฉบับจะไม่อยู่ในโครงสร้างการสร้าง ถ้าคุณพยายามบางอย่างเช่นtarget_include_directories(Tutorial PUBLIC ../lib)ในตัวอย่างก่อนหน้านี้เส้นทางที่จะเป็นเมื่อเทียบกับการสร้างต้นไม้ที่จะบอกว่ามันจะเป็นเหมือนการเขียนซึ่งจะดูภายใน${CMAKE_BINARY_DIR}/lib simple/build/lib/ไม่มีไฟล์. h อยู่ในนั้น libTestLib.aที่มากที่สุดที่คุณจะได้พบกับ คุณต้องการ${CMAKE_SOURCE_DIR}/libแทน

  • CMAKE_CXX_FLAGS: แฟล็กเพื่อส่งต่อไปยังคอมไพเลอร์ในกรณีนี้คือคอมไพเลอร์ C ++ นอกจากนี้ที่น่าสังเกตคือCMAKE_CXX_FLAGS_DEBUGจะใช้แทนหากCMAKE_BUILD_TYPEตั้งค่าเป็นดีบัก มีมากกว่านี้; ตรวจสอบวิกิ CMake
  • CMAKE_RUNTIME_OUTPUT_DIRECTORY: บอก CMake ว่าจะวางไฟล์ปฏิบัติการทั้งหมดเมื่อสร้าง นี่เป็นการตั้งค่าส่วนกลาง ตัวอย่างเช่นคุณสามารถตั้งค่าbin/และวางทุกอย่างไว้ที่นั่นอย่างเรียบร้อย EXECUTABLE_OUTPUT_PATHคล้ายกัน แต่เลิกใช้แล้วในกรณีที่คุณสะดุด
  • CMAKE_LIBRARY_OUTPUT_DIRECTORY: ในทำนองเดียวกันการตั้งค่าส่วนกลางเพื่อบอก CMake ว่าจะวางไฟล์ไลบรารีทั้งหมดไว้ที่ใด

คุณสมบัติเป้าหมาย : คุณสามารถตั้งค่าคุณสมบัติที่ส่งผลต่อเป้าหมายเดียวไม่ว่าจะเป็นไฟล์ปฏิบัติการหรือไลบรารี (หรือที่เก็บถาวร ... คุณจะได้รับแนวคิด) นี่คือตัวอย่างที่ดีในการใช้งาน (ด้วยset_target_properties().

มีวิธีง่ายๆในการเพิ่มแหล่งที่มาให้กับเป้าหมายโดยอัตโนมัติหรือไม่? ใช้ GLOBเพื่อแสดงรายการทุกอย่างในไดเร็กทอรีที่กำหนดภายใต้ตัวแปรเดียวกัน ตัวอย่างไวยากรณ์คือFILE(GLOB <variable name> <directory>/*.cxx).

คุณสามารถระบุประเภทการสร้างต่างๆได้หรือไม่? ใช่แม้ว่าฉันจะไม่แน่ใจเกี่ยวกับวิธีการทำงานหรือข้อ จำกัด ของสิ่งนี้ อาจต้องใช้ if / then'ning บ้าง แต่ CMake ให้การสนับสนุนขั้นพื้นฐานโดยไม่ต้องกำหนดค่าอะไรเช่นค่าเริ่มต้นCMAKE_CXX_FLAGS_DEBUGสำหรับตัวอย่างเช่น คุณสามารถตั้งค่าทั้งสร้างประเภทของคุณจากภายในCMakeLists.txtไฟล์ผ่านset(CMAKE_BUILD_TYPE <type>)หรือโทร CMake cmake -DCMAKE_BUILD_TYPE=Debugจากคอนโซลที่มีธงที่เหมาะสมตัวอย่างเช่น

ตัวอย่างที่ดีของโครงการที่ใช้ CMake? Wikipedia มีรายชื่อโครงการโอเพ่นซอร์สที่ใช้ CMake หากคุณต้องการตรวจสอบสิ่งนั้น แบบฝึกหัดออนไลน์ไม่ได้เป็นเพียงสิ่งที่ทำให้ฉันผิดหวังในเรื่องนี้อย่างไรก็ตามคำถาม Stack Overflowนี้มีการตั้งค่า CMake ที่ค่อนข้างเจ๋งและเข้าใจง่าย มันคุ้มค่าที่จะดู

การใช้ตัวแปรจาก CMake ในโค้ดของคุณ : นี่เป็นตัวอย่างที่รวดเร็วและสกปรก (ดัดแปลงจากบทช่วยสอนอื่น ๆ ):

simple/CMakeLists.txt:

project (Tutorial)

# Setting variables
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 1)

# Configure_file(<input> <output>)
# Copies a file <input> to file <output> and substitutes variable values referenced in the file content.
# So you can pass some CMake variables to the source code (in this case version numbers)
configure_file (
  "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
  "${PROJECT_SOURCE_DIR}/src/TutorialConfig.h"
)

simple/TutorialConfig.h.in:

// Configured options and settings
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

ไฟล์ผลลัพธ์ที่สร้างโดย CMake simple/src/TutorialConfig.h:

// Configured options and settings
#define Tutorial_VERSION_MAJOR 1
#define Tutorial_VERSION_MINOR 1

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

สำหรับสิ่งอื่น Stack Overflow เต็มไปด้วยคำถามเฉพาะและคำตอบที่กระชับซึ่งเหมาะสำหรับทุกคนยกเว้นผู้ที่ไม่ได้ฝึกหัด


2
ฉันยอมรับคำตอบนี้ แต่ถ้ามีคนอื่นเขียนคำตอบที่ดีกว่าและสั้นกว่าฉันจะเลือกอย่างนั้น ฉันจะทำด้วยตัวเอง แต่ฉันต้องทนทุกข์ทรมานกับ CMake มากพอแล้ว
leinaD_natipaC

7
ขอบคุณสำหรับผลงานที่น่าทึ่งนี้ หวังว่านี่จะได้รับคะแนนโหวตมากขึ้น! :)
58

4
ประเด็นที่ค่อนข้างเข้าใจง่าย: ด้วย CMake คุณไม่จำเป็นต้องรักษาการตั้งค่าแยกเฉพาะสำหรับสภาพแวดล้อมคอมไพเลอร์ / บิลด์ของคุณอีกต่อไป คุณมีการกำหนดค่าเดียวและใช้ได้กับ (เวอร์ชันต่างๆ) Visual Studio, Code Blocks, Unix Makefiles ธรรมดาและสภาพแวดล้อมอื่น ๆ อีกมากมาย นั่นคือเหตุผลที่ฉันมอง CMake ตั้งแต่แรก: มันกลายเป็นความเจ็บปวดครั้งใหญ่ที่ทำให้การกำหนดค่า Autoconf, MSVC 2005 / 32bit และ MSVC 2010/64 บิตซิงค์กัน และเมื่อฉันได้รับมันฉันได้เพิ่มสิ่งต่างๆอีกมากมายเช่นการสร้างเอกสารการทดสอบบรรจุภัณฑ์ ฯลฯ ทั้งหมดนี้ในรูปแบบข้ามแพลตฟอร์ม
DevSolar

1
@DevSolar ที่แท้ทรู. ฉันชอบบรรทัดนั้นมากกว่าของวิกิพีเดียดังนั้นฉันจะเพิ่มคำตอบให้ถ้าคุณไม่รังเกียจ ฉันจะไม่พอดีกับวิธีการใช้ CMake อย่างถูกต้องกับเอฟเฟกต์นั้น นี่เป็นข้อมูลเพิ่มเติมเกี่ยวกับความสามารถในการบอกสิ่งที่เกิดขึ้น
leinaD_natipaC

1
@RichieHH ตามตัวอย่างก่อนอื่นคุณกำหนดค่า CMake เพื่อใช้ Makefiles จากนั้นคุณใช้ CMake เพื่อสร้างไฟล์ที่โครงการของคุณต้องสร้างขึ้นและในที่สุดคุณก็เลิกกังวลเกี่ยวกับ CMake เพราะงานที่นี่เสร็จแล้ว ดังนั้นคุณจึง "กังวล" เกี่ยวกับ Makefile ในแง่ที่ว่าจากนี้ไปคุณต้องใช้makeในการทุบตีเพื่อสร้างโครงการของคุณ
leinaD_natipaC
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.