วิธีเพิ่มไดเรกทอรีรวมอย่างถูกต้องด้วย CMake


243

เกี่ยวกับปีที่ผ่านมาผมถามเกี่ยวกับการอ้างอิงในส่วนหัว CMake

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

การค้นหาอย่างรวดเร็วในบทแนะนำ CMake ชี้ไปinclude_directoriesที่ดูเหมือนจะไม่ทำสิ่งที่ฉันต้องการ ...

เป็นวิธีที่เหมาะสมในการส่งสัญญาณถึง CMake ว่าไดเรกทอรีใดมีส่วนหัวที่จะรวมและส่วนหัวเหล่านั้นควรถูกติดตามโดย Makefile ที่สร้างขึ้น?


การแก้ไขที่ทำกับคำถามนี้ทำให้เกิดความสับสน คำถามและคำตอบเดิมคือวิธีติดตามไฟล์ส่วนหัวใน IDE สิ่งนี้ค่อนข้างแตกต่างจากการขึ้นต่อกันของไฟล์ส่วนหัว Makefile ที่หายไปและวิธีแก้ไขปัญหานั้น
fdk1342

@ เฟรด: ฉันไม่รู้ว่าคุณกำลังพูดถึงอะไร เมื่อการแก้ไขแก้ไขแสดงขึ้นอย่างชัดเจนประโยคสุดท้ายจะอยู่ที่นั่นเสมอ มีเพียงการแก้ไขเครื่องสำอางที่ทำกับคำถามนี้และไม่มีการแนะนำคำใด ๆ (หรือลบออก)
Matthieu M.

นั่นคือความเข้าใจผิดของฉัน ดูเหมือนว่าฉันจะเพิ่มย่อหน้าทั้งหมด stackoverflow.com/questions/13703647/…กล่าวว่าความเข้าใจทั่วไปคือวิธีการแสดงรายการไฟล์ส่วนหัวใน IDE สิ่งนี้จะเป็นการอ้างถึง.cbpไฟล์โครงการ ในตอนนี้หากตัวตรวจจับการพึ่งพา cmake ไม่สามารถระบุไฟล์ส่วนหัวได้อย่างถูกต้องว่าเป็นส่วนที่พึ่งพาสำหรับ Makefile จะมีวิธีแก้ไข แต่ในบางกรณีมันจะผิดเนื่องจากไม่มีตัวประมวลผลเต็มก่อน
fdk1342

คำตอบ:


267

ต้องทำสองสิ่ง

ก่อนอื่นให้เพิ่มไดเรกทอรีที่จะรวม:

target_include_directories(test PRIVATE ${YOUR_DIRECTORY})

ในกรณีที่คุณติดอยู่กับ CMake เวอร์ชันเก่ามาก (2.8.10 หรือเก่ากว่า) โดยไม่สนับสนุนtarget_include_directoriesคุณสามารถใช้มรดกinclude_directoriesแทน:

include_directories(${YOUR_DIRECTORY})

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

set(SOURCES file.cpp file2.cpp ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)
add_executable(test ${SOURCES})

วิธีนี้ไฟล์ส่วนหัวจะปรากฏเป็นการอ้างอิงใน Makefile และตัวอย่างเช่นในโครงการ Visual Studio ที่สร้างขึ้นหากคุณสร้างขึ้นมา

วิธีใช้ไฟล์ส่วนหัวเหล่านั้นสำหรับเป้าหมายหลายรายการ:

set(HEADER_FILES ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)

add_library(mylib libsrc.cpp ${HEADER_FILES})
target_include_directories(mylib PRIVATE ${YOUR_DIRECTORY})
add_executable(myexec execfile.cpp ${HEADER_FILES})
target_include_directories(myexec PRIVATE ${YOUR_DIRECTORY})

อา! ฉันรู้ว่ามันต้องเป็นสิ่งที่โง่ อันที่จริงฉันไม่ได้ระบุส่วนหัว ... ฉันจำเป็นต้องแสดงรายการส่วนหัวของห้องสมุดนี้หรือส่วนหัวทั้งหมดที่อาจขึ้นอยู่กับ (ด้านบนของการประกาศการพึ่งพาห้องสมุด) มันเป็นโครงการที่กำลังเติบโตและฉันค่อนข้างกลัวว่าจะเพิ่มส่วนหัวในการพึ่งพาทั้งหมดเมื่อฉันเพิ่มในไลบรารีรูท
Matthieu M.

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

1
คำถามของฉันในแง่ที่ว่าฉันมีห้องสมุดหลายแห่งซึ่งพึ่งพากันและกัน: libroot, liba ขึ้นอยู่กับ libroot, libb ขึ้นอยู่กับ libroot ฉันสามารถใช้LIBROOT_HEADER_FILESตัวแปรในliba/CMakefileและlibb/CMakefileแล้ว?
Matthieu M.

2
นี้เป็นธรรมคุณควรไม่เคยใช้มากกว่าinclude_directories target_include_directoriesชุดก่อนหน้านี้จะตั้งค่าซ้ำสำหรับเป้าหมายทั้งหมดในไดเรกทอรีนั้น ในขณะที่หลังตั้งไว้สำหรับเป้าหมาย การดำเนินการก่อนหน้านี้เป็นการทำลายความคิดของกราฟเป้าหมายใน CMake และอาศัยผลข้างเคียงกับลำดับชั้นไฟล์ของคุณแทน
แอนดี้

1
ฉันแก้ไขคำตอบเพื่อให้สอดคล้องกับแนวคิดปัจจุบันของการเลือกtarget_include_directoriesใช้รหัส CMake ที่ทันสมัย เชิญชวนฉันเข้าร่วมแชทถ้าคุณไม่เห็นด้วยกับการเปลี่ยนแปลง
ComicSansMS

74

ก่อนอื่นคุณinclude_directories()จะใช้เพื่อบอก CMake ให้เพิ่มไดเรกทอรี-Iลงในบรรทัดคำสั่งการคอมไพล์ ประการที่สองคุณแสดงรายการส่วนหัวในadd_executable()หรือการadd_library()โทรของคุณ

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

include_directories(include)

add_executable(MyExec
  src/main.c
  src/other_source.c
  include/header1.h
  include/header2.h
)

19
คุณต้องการเพิ่มส่วนหัวลงไปadd_executableจริงๆหรือ? ฉันคิดว่า CMake หาการรวมไฟล์ที่ต้องพึ่งพาโดยอัตโนมัติ
โคลินดีเบนเน็ตต์

57
@ColoftBennett คุณไม่จำเป็นต้องระบุรายการเหล่านี้ด้วยเหตุผลในการพึ่งพา - CMake ให้ตัวเลขการสร้างการอ้างอิงได้ดีหากคุณไม่ต้องการ แต่ถ้าคุณแสดงรายการพวกเขาจะถือว่าเป็นส่วนหนึ่งของโครงการและจะแสดงรายการดังกล่าวใน IDEs (ซึ่งเป็นหัวข้อของคำถาม)
Angew ไม่ภูมิใจใน SO SO

อย่างน้อยสำหรับ QtCreator ไม่จำเป็นต้องเพิ่ม class.h ในกรณีที่มี class.cpp อยู่ lonely.h เท่านั้นที่ต้องเพิ่มแหล่งที่มา ดูการสอนที่www.th-thielemann.de/cmake
Th Thielemann

19

CMake เป็นเหมือนภาษาสคริปต์หากเปรียบเทียบกับวิธีอื่น ๆ ในการสร้าง Makefile (เช่น make หรือ qmake) มันไม่เจ๋งเหมือน Python แต่ก็ยังดี

ไม่มีสิ่งเช่น " วิธีที่เหมาะสม " หากมองในโครงการโอเพนซอร์สต่าง ๆ ที่ผู้คนมีไดเรกทอรี แต่มีสองวิธีที่จะทำ

  1. Crude include_directoriesจะผนวกไดเรกทอรีไปยังโครงการปัจจุบันและโครงการที่สืบทอดอื่น ๆ ทั้งหมดที่คุณจะผนวกผ่านชุดคำสั่งadd_subdirectory บางคนบอกว่าวิธีการดังกล่าวเป็นมรดก

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

ความเป็นส่วนตัว - ใช้สำหรับเป้าหมายการสร้างที่ระบุนี้เท่านั้น

สาธารณะ - ใช้เพื่อเป้าหมายที่ระบุและสำหรับเป้าหมายที่เชื่อมโยงกับโครงการนี้

INTERFACE - ใช้เพื่อเป้าหมายที่เชื่อมโยงกับโครงการปัจจุบันเท่านั้น

PS:

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

  2. คำตอบที่คล้ายกันคือกับคำสั่งคู่อื่น ๆtarget_compile_definitions / add_definitions , target_compile_options / CMAKE_C_FLAGS


13

include_directories("/your/path/here")เพิ่ม

นี้จะคล้ายกับการโทรgccด้วย-I/your/path/here/ตัวเลือก

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


7

ผมมีปัญหาเหมือนกัน.

ไดเรกทอรีโครงการของฉันเป็นแบบนี้:

    --project
    ---Classes
    ----Application
    -----.h and .c files
    ----OtherFolders
    --main.cpp

และสิ่งที่ฉันใช้ในการรวมไฟล์ในโฟลเดอร์เหล่านั้นทั้งหมด:

    file(GLOB source_files
            "*.h"
            "*.cpp"
            "Classes/*/*.cpp"
            "Classes/*/*.h"
    )

    add_executable(Server ${source_files})

และมันทำงานได้อย่างสมบูรณ์


การจำ cmake นั้นเป็น 'เครื่องกำเนิดระบบสร้าง' และไม่ใช่ 'ระบบสร้าง' โดยใช้ไฟล์ glob ไม่ใช่ความคิดที่ดีใน cmake ที่ทันสมัย ​​(CMake กับรุ่น 3.0 ขึ้นไป) เนื่องจากไฟล์ globs ถูกประเมินในเวลา 'สร้าง' และไม่สร้าง เวลาในการสร้างระบบ ' ดูลิงค์: gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1
ggulgulia
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.