Bagaimana cara menambahkan direktori dengan CMake dengan benar

243

Sekitar setahun yang lalu saya bertanya tentang dependensi header di CMake .

Saya menyadari baru-baru ini bahwa masalah tampaknya CMake menganggap file-file header itu eksternal untuk proyek. Setidaknya, ketika membuat proyek Code :: Blocks file header tidak muncul dalam proyek (file sumber lakukan). Oleh karena itu bagi saya CMake menganggap header-header itu sebagai eksternal dari proyek, dan tidak melacak mereka dalam ketergantungan.

Pencarian cepat di tutorial CMake hanya menunjukkan include_directoriesyang sepertinya tidak melakukan apa yang saya inginkan ...

Apa cara yang tepat untuk memberi sinyal ke CMake bahwa direktori tertentu berisi header untuk dimasukkan, dan bahwa header tersebut harus dilacak oleh Makefile yang dihasilkan?

Matthieu M.
sumber
Suntingan yang dibuat untuk pertanyaan ini membuatnya membingungkan. Pertanyaan dan jawaban asli adalah bagaimana melacak File Header dalam IDE. Ini sangat berbeda dari ketergantungan file header Makefile yang hilang dan cara mengatasi masalah itu.
fdk1342
@ Fred: Saya tidak tahu apa yang Anda bicarakan. Seperti yang terlihat jelas dari revisi edit, kalimat terakhir selalu ada. Hanya suntingan kosmetik yang dibuat pada pertanyaan ini, dan tidak ada kata yang diperkenalkan (atau dihapus).
Matthieu M.
Maka itu adalah kesalahpahaman saya. Bagi saya itu tampak seperti satu paragraf ditambahkan. stackoverflow.com/questions/13703647/… mengatakan bahwa pemahaman umum adalah bagaimana membuat daftar file header di IDE. Ini merujuk ke .cbpfile proyek. Sekarang jika pemindai dependensi cmake gagal mengidentifikasi file header dengan benar sebagai dependensi untuk Makefile ada cara untuk memperbaikinya tetapi dalam beberapa kasus hal itu akan salah karena tidak menyertakan preprosesor penuh.
fdk1342

Jawaban:

267

Dua hal harus dilakukan.

Pertama, tambahkan direktori yang akan disertakan:

target_include_directories(test PRIVATE ${YOUR_DIRECTORY})

Jika Anda terjebak dengan versi CMake yang sangat lama (2.8.10 atau lebih tua) tanpa dukungan target_include_directories, Anda juga dapat menggunakan warisan include_directoriessebagai gantinya:

include_directories(${YOUR_DIRECTORY})

Kemudian Anda juga harus menambahkan file header ke daftar file sumber Anda untuk target saat ini, misalnya:

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

Dengan cara ini, file header akan muncul sebagai dependensi di Makefile, dan juga misalnya dalam proyek Visual Studio yang dihasilkan, jika Anda menghasilkannya.

Cara menggunakan file header itu untuk beberapa target:

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})
SirDarius
sumber
Ah! Saya tahu itu pasti sesuatu yang bodoh. Memang, saya tidak mencantumkan header ... Apakah saya perlu mendaftar header hanya perpustakaan ini, atau juga semua header yang mungkin tergantung (di atas menyatakan ketergantungan pada perpustakaan)? Ini adalah proyek yang sedang berkembang dan saya cukup takut untuk menambahkan header ke semua dependensi ketika saya menambahkan satu di pustaka root.
Matthieu M.
Untuk memungkinkan pelacakan ketergantungan yang lebih baik (misalnya untuk memastikan memodifikasi file header memicu kompilasi untuk semua target yang terkena dampak), ya. Namun Anda dapat menggunakan variabel cmake untuk mendaftar file header hanya sekali dan menggunakannya di beberapa tempat, lihat edit saya.
SirDarius
1
Pertanyaan saya lebih dalam arti bahwa saya memiliki beberapa perpustakaan yang saling tergantung: libroot, liba tergantung pada libroot, libb tergantung pada libroot. Dapatkah saya menggunakan LIBROOT_HEADER_FILESvariabel dalam liba/CMakefiledan libb/CMakefilekemudian?
Matthieu M.
2
Ini salah, Anda harus tidak pernah menggunakan include_directorieslebih target_include_directories. Yang pertama menetapkannya secara rekursif untuk semua target dalam direktori itu; sedangkan yang terakhir menetapkannya untuk target. Melakukan yang pertama mematahkan gagasan grafik target di CMake, dan sebagai gantinya bergantung pada efek samping ke hierarki file Anda.
Andy
1
Saya mengedit jawaban untuk mencerminkan gagasan saat ini lebih memilih target_include_directoriesuntuk kode CMake modern. Jangan ragu untuk mengundang saya ke obrolan jika Anda tidak setuju dengan perubahan tersebut.
ComicSansMS
74

Pertama, Anda gunakan include_directories()untuk memberi tahu CMake untuk menambahkan direktori -Ike baris perintah kompilasi. Kedua, Anda daftar header di Anda add_executable()atau add_library()panggilan.

Sebagai contoh, jika sumber proyek Anda ada src, dan Anda memerlukan tajuk dari include, Anda dapat melakukannya seperti ini:

include_directories(include)

add_executable(MyExec
  src/main.c
  src/other_source.c
  include/header1.h
  include/header2.h
)
Angew tidak lagi bangga dengan SO
sumber
19
Apakah Anda benar-benar perlu menambahkan header add_executable? Saya pikir CMake tahu menyertakan dependensi file secara otomatis.
Colin D Bennett
57
@ColinDBennett Anda tidak perlu mendaftar mereka untuk alasan ketergantungan - CMake angka membangun dependensi baik-baik saja jika Anda tidak. Tetapi jika Anda mencantumkannya, mereka dianggap sebagai bagian dari proyek, dan akan dicantumkan dalam IDE (yang merupakan topik pertanyaan).
Angew tidak lagi bangga pada
Setidaknya untuk QtCreator tidak perlu menambahkan class.h jika ada class.cpp. Hanya lonely.h yang perlu ditambahkan ke sumber. Lihat tutorial di www.th-thielemann.de/cmake
Th. Thielemann
19

CMake lebih seperti bahasa skrip jika membandingkannya dengan cara lain untuk membuat Makefile (mis. Make atau qmake). Ini tidak terlalu keren seperti Python, tapi tetap saja.

Tidak ada hal seperti " cara yang tepat " jika mencari di berbagai proyek open source bagaimana orang memasukkan direktori. Tetapi ada dua cara untuk melakukannya.

  1. Mentah include_directories akan menambahkan direktori ke proyek saat ini dan semua proyek turunan lainnya yang akan Anda tambahkan melalui serangkaian perintah add_subdirectory . Kadang-kadang orang mengatakan bahwa pendekatan semacam itu adalah warisan.

  2. Cara yang lebih elegan adalah dengan target_include_directories . Hal ini memungkinkan untuk menambahkan direktori untuk proyek / target tertentu tanpa (mungkin) warisan atau bentrok yang tidak perlu dari berbagai direktori yang disertakan. Juga memungkinkan untuk melakukan bahkan konfigurasi yang halus dan menambahkan salah satu dari penanda berikut untuk perintah ini.

PRIVATE - hanya digunakan untuk target bangunan yang ditentukan ini

PUBLIC - gunakan untuk target yang ditentukan dan untuk target yang menghubungkan dengan proyek ini

INTERFACE - gunakan hanya untuk target yang terhubung dengan proyek saat ini

PS:

  1. Kedua perintah memungkinkan untuk menandai direktori sebagai SISTEM untuk memberikan petunjuk bahwa itu bukan bisnis Anda yang direktori tertentu akan berisi peringatan.

  2. Jawaban yang serupa adalah dengan pasangan perintah lain target_compile_definitions / add_definitions , target_compile_options / CMAKE_C_FLAGS

bruziuz
sumber
13

Tambah include_directories("/your/path/here").

Ini akan mirip gccdengan -I/your/path/here/opsi menelepon dengan .

Pastikan Anda menempatkan tanda kutip ganda di sekitar jalan. Orang lain tidak menyebutkan itu dan itu membuat saya macet selama 2 hari. Jadi jawaban ini adalah untuk orang yang sangat baru di CMake dan sangat bingung.

off99555
sumber
7

Saya memiliki masalah yang sama.

Direktori proyek saya seperti ini:

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

Dan apa yang saya gunakan untuk memasukkan file di semua folder itu:

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

    add_executable(Server ${source_files})

Dan itu benar-benar berhasil.

Seyed Hussein Mirzaki
sumber
Mengingat bahwa cmake adalah 'generator sistem bangun' dan bukan 'sistem bangun' menggunakan file glob bukanlah ide yang baik dalam cmake modern (CMake dengan versi 3.0 ke atas) karena gumpalan file dievaluasi pada waktu 'build' dan bukan 'build' waktu pembuatan sistem. Lihat tautan: gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1
ggulgulia