Cách thêm chính xác bao gồm các thư mục với CMake


243

Khoảng một năm trước tôi đã hỏi về sự phụ thuộc tiêu đề trong CMake .

Gần đây tôi nhận ra rằng vấn đề dường như là CMake coi những tệp tiêu đề đó là bên ngoài dự án. Ít nhất, khi tạo dự án Code :: Blocks, các tệp tiêu đề không xuất hiện trong dự án (các tệp nguồn thực hiện). Do đó, dường như CMake coi những tiêu đề đó là bên ngoài của dự án và không theo dõi chúng trong phần phụ thuộc.

Một tìm kiếm nhanh trong hướng dẫn CMake chỉ chỉ ra include_directoriesdường như không làm được điều tôi muốn ...

Cách thích hợp để báo hiệu cho CMake rằng một thư mục cụ thể có chứa các tiêu đề được bao gồm và những tiêu đề đó cần được theo dõi bởi Makefile được tạo?


Các chỉnh sửa được thực hiện cho câu hỏi này làm cho nó khó hiểu. Câu hỏi và câu trả lời ban đầu là cách theo dõi Tệp Tiêu đề trong IDE. Điều này khá khác biệt với một phụ thuộc tệp tiêu đề thiếu Makefile được tạo và cách giải quyết vấn đề đó.
fdk1342

@Fred: Tôi không biết bạn đang nói về cái gì. Khi sửa đổi chỉnh sửa cho thấy rõ ràng, câu cuối cùng đã luôn ở đó. Chỉ chỉnh sửa mỹ phẩm được thực hiện cho câu hỏi này, và không có từ nào được giới thiệu (hoặc loại bỏ).
Matthieu M.

Sau đó, đó là sự hiểu lầm của tôi. Nó trông giống như toàn bộ đoạn văn đã được thêm vào. stackoverflow.com/questions/13703647/ cảm nói cách hiểu phổ biến là làm thế nào để liệt kê tệp tiêu đề trong IDE. Điều này đã được đề cập đến các .cbptập tin dự án. Bây giờ nếu trình quét phụ thuộc cmake không xác định chính xác tệp tiêu đề là phụ thuộc cho Makefile, có một số cách để khắc phục điều đó nhưng trong một số trường hợp, nó sẽ bị lỗi vì nó không bao gồm bộ tiền xử lý đầy đủ.
fdk1342

Câu trả lời:


267

Hai điều phải được thực hiện.

Đầu tiên thêm thư mục để được bao gồm:

target_include_directories(test PRIVATE ${YOUR_DIRECTORY})

Trong trường hợp bạn bị mắc kẹt với phiên bản CMake rất cũ (2.8.10 trở lên) mà không có hỗ trợ target_include_directories, bạn cũng có thể sử dụng di sản include_directoriesthay thế:

include_directories(${YOUR_DIRECTORY})

Sau đó, bạn cũng phải thêm các tệp tiêu đề vào danh sách các tệp nguồn của mình cho mục tiêu hiện tại, ví dụ:

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

Bằng cách này, các tệp tiêu đề sẽ xuất hiện dưới dạng các phụ thuộc trong Makefile và ví dụ như trong dự án Visual Studio được tạo, nếu bạn tạo một tệp.

Cách sử dụng các tệp tiêu đề đó cho một số mục tiêu:

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})

Ah! Tôi biết nó phải là một cái gì đó ngu ngốc. Thật vậy, tôi đã không liệt kê các tiêu đề ... Tôi có cần liệt kê các tiêu đề của thư viện này không, hoặc tất cả các tiêu đề mà nó có thể phụ thuộc (trên đầu khai báo sự phụ thuộc vào thư viện)? Đó là một dự án đang phát triển và tôi khá sợ ý tưởng thêm một tiêu đề vào tất cả các phụ thuộc khi tôi thêm một tiêu đề trong thư viện gốc.
Matthieu M.

Để cho phép theo dõi phụ thuộc tốt hơn (ví dụ: để đảm bảo sửa đổi tệp tiêu đề kích hoạt biên dịch cho tất cả các mục tiêu bị ảnh hưởng), có. Tuy nhiên, bạn có thể sử dụng các biến cmake để liệt kê các tệp tiêu đề chỉ một lần và sử dụng chúng ở một số nơi, xem phần chỉnh sửa của tôi.
SirDarius

1
Câu hỏi của tôi nhiều hơn theo nghĩa là tôi có một số thư viện phụ thuộc lẫn nhau: libroot, liba phụ thuộc vào libroot, libb phụ thuộc vào libroot. Tôi có thể sử dụng LIBROOT_HEADER_FILESbiến trong liba/CMakefilelibb/CMakefilesau đó?
Matthieu M.

2
Điều này là sai, bạn không bao giờ nên sử dụng include_directorieshơn target_include_directories. Cái trước đặt nó đệ quy cho tất cả các mục tiêu trong thư mục đó; trong khi cái sau đặt nó cho một mục tiêu. Việc thực hiện trước đây sẽ phá vỡ khái niệm về biểu đồ đích trong CMake và thay vào đó dựa vào các hiệu ứng phụ vào hệ thống phân cấp tệp của bạn.
Andy

1
Tôi đã chỉnh sửa câu trả lời để phản ánh khái niệm hiện tại về việc thích target_include_directoriesmã CMake hiện đại. Vui lòng mời tôi trò chuyện nếu bạn không đồng ý với các thay đổi.
ComicSansMS

74

Đầu tiên, bạn sử dụng include_directories()để nói với CMake để thêm thư -Imục vào dòng lệnh biên dịch. Thứ hai, bạn liệt kê các tiêu đề trong add_executable()hoặc add_library()cuộc gọi của bạn .

Ví dụ: nếu nguồn của dự án của bạn nằm trong srcvà bạn cần các tiêu đề từ đó include, bạn có thể làm như thế này:

include_directories(include)

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

19
Bạn có thực sự cần phải thêm tiêu đề add_executable? Tôi nghĩ CMake đã tự động tìm ra các phụ thuộc tệp bao gồm.
Colin D Bennett

57
@ColinDBennett Bạn không phải liệt kê chúng vì lý do phụ thuộc - CMake chỉ ra các phụ thuộc xây dựng chỉ tốt nếu bạn không. Nhưng nếu bạn liệt kê chúng, chúng được coi là một phần của dự án và sẽ được liệt kê như vậy trong IDE (đó là chủ đề của câu hỏi).
Angew không còn tự hào về SO

Ít nhất là đối với QtCreator, không cần thiết phải thêm class.h trong trường hợp class.cpp tồn tại. Chỉ cô đơn.h cần được thêm vào nguồn. Xem hướng dẫn tại www.th-thielemann.de/cmake
Th. Thielemann

19

CMake giống ngôn ngữ kịch bản hơn nếu so sánh nó với các cách khác để tạo Makefile (ví dụ: make hoặc qmake). Nó không tuyệt lắm như Python, nhưng vẫn vậy.

Không có thứ gọi là " cách thích hợp " nếu tìm kiếm trong các dự án mã nguồn mở khác nhau về cách mọi người bao gồm các thư mục. Nhưng có hai cách để làm điều đó.

  1. Crude include_directories sẽ nối thêm một thư mục vào dự án hiện tại và tất cả các dự án hậu duệ khác mà bạn sẽ nối thông qua một loạt các lệnh add_subdirectory . Đôi khi mọi người nói rằng cách tiếp cận như vậy là di sản.

  2. Một cách thanh lịch hơn là với target_include_directories . Nó cho phép nối thêm một thư mục cho một dự án / mục tiêu cụ thể mà không (có thể) kế thừa không cần thiết hoặc xung đột các thư mục bao gồm khác nhau. Cũng cho phép thực hiện ngay cả một cấu hình tinh tế và nối thêm một trong các dấu hiệu sau cho lệnh này.

RIÊNG TƯ - chỉ sử dụng cho mục tiêu xây dựng được chỉ định này

PUBLIC - sử dụng nó cho mục tiêu được chỉ định và cho các mục tiêu liên kết với dự án này

INTERFACE - chỉ sử dụng nó cho các mục tiêu liên kết với dự án hiện tại

Tái bút

  1. Cả hai lệnh đều cho phép đánh dấu một thư mục là HỆ THỐNG để đưa ra gợi ý rằng đó không phải là doanh nghiệp của bạn mà các thư mục được chỉ định sẽ chứa các cảnh báo.

  2. Một câu trả lời tương tự là với các cặp lệnh khác target_compile_def địnhs / add_def địnhs , target_compile_options / CMAKE_C_FLAGS


13

Thêm include_directories("/your/path/here").

Điều này sẽ tương tự như gọi gccvới -I/your/path/here/tùy chọn.

Hãy chắc chắn rằng bạn đặt dấu ngoặc kép xung quanh đường dẫn. Những người khác đã không đề cập đến điều đó và nó khiến tôi bế tắc trong 2 ngày. Vì vậy, câu trả lời này dành cho những người rất mới với CMake và rất bối rối.


7

Tôi đã từng gặp vấn đề tương tự.

Thư mục dự án của tôi là như thế này:

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

Và những gì tôi đã sử dụng để bao gồm các tệp trong tất cả các thư mục đó:

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

    add_executable(Server ${source_files})

Và nó hoàn toàn làm việc.


Hãy nhớ rằng cmake là 'trình tạo hệ thống xây dựng' chứ không phải 'hệ thống xây dựng' sử dụng tệp toàn cầu không phải là ý tưởng hay trong cmake hiện đại (CMake với các phiên bản 3.0 trở lên) vì các khối lượng tệp được đánh giá tại thời điểm 'xây dựng' chứ không phải 'xây dựng thời gian tạo hệ thống. Xem liên kết: gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1
ggulgulia
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.