Jak poprawnie dodać dołączone katalogi za pomocą CMake

243

Około rok temu zapytałem o zależności nagłówka w CMake .

Ostatnio zdałem sobie sprawę, że wydaje się, że problem polega na tym, że CMake uznał te pliki nagłówkowe za zewnętrzne dla projektu. Przynajmniej podczas generowania projektu Code :: Blocks pliki nagłówkowe nie pojawiają się w projekcie (tak jak pliki źródłowe). Dlatego wydaje mi się, że CMake uważa te nagłówki za zewnętrzne dla projektu i nie śledzi ich w zależności.

Szybkie wyszukiwanie w samouczku CMake wskazało tylko, include_directoriesktóre nie wydają się robić tego, co chciałbym ...

Jaki jest właściwy sposób zasygnalizowania CMake, że określony katalog zawiera nagłówki, które należy uwzględnić, i że nagłówki te powinny być śledzone przez wygenerowany plik Makefile?

Matthieu M.
źródło
Zmiany wprowadzone w tym pytaniu powodują zamieszanie. Pierwotne pytanie i odpowiedzi dotyczyły sposobu śledzenia plików nagłówkowych w środowisku IDE. Różni się to znacznie od wygenerowanych zależności brakujących plików nagłówkowych Makefile i sposobu rozwiązania tego problemu.
fdk1342
@Fred: Nie mam pojęcia o czym mówisz. Jak wyraźnie pokazuje wersja edycji, zawsze było tam ostatnie zdanie . W tym pytaniu wprowadzono tylko zmiany kosmetyczne i żadne słowo nie zostało wprowadzone (ani usunięte).
Matthieu M.
To jest moje nieporozumienie. Wydawało mi się, że został dodany cały akapit. stackoverflow.com/questions/13703647/... mówi, że powszechnie rozumie się, jak wyświetlić plik nagłówkowy w IDE. Odnosi się to do .cbppliku projektu. Teraz, jeśli skaner zależności cmake nie rozpozna poprawnie pliku nagłówka jako zależności dla pliku Makefile, istnieją sposoby, aby to naprawić, ale w niektórych przypadkach może to być błędne, ponieważ nie zawiera pełnego preprocesora.
fdk1342,

Odpowiedzi:

267

Dwie rzeczy muszą być zrobione.

Najpierw dodaj katalog, który chcesz dołączyć:

target_include_directories(test PRIVATE ${YOUR_DIRECTORY})

Jeśli utkniesz z bardzo starą wersją CMake (2.8.10 lub starszą) bez wsparcia target_include_directories, możesz również użyć starszej wersji include_directories:

include_directories(${YOUR_DIRECTORY})

Następnie musisz również dodać pliki nagłówkowe do listy plików źródłowych dla bieżącego celu, na przykład:

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

W ten sposób pliki nagłówkowe pojawią się jako zależności w pliku Makefile, a także na przykład w wygenerowanym projekcie Visual Studio, jeśli go wygenerujesz.

Jak korzystać z tych plików nagłówkowych dla kilku celów:

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
źródło
Ach! Wiedziałem, że to musi być coś głupiego. Rzeczywiście, nie wymieniłem nagłówków ... Czy muszę wymienić nagłówki tylko tej biblioteki, czy też wszystkich nagłówków, od których może ona zależeć (oprócz deklarowania zależności od biblioteki)? To rozwijający się projekt i bardzo boję się pomysłu dodania nagłówka do wszystkich zależności, gdy dodam go do biblioteki głównej.
Matthieu M.
Aby umożliwić lepsze śledzenie zależności (na przykład aby upewnić się, że modyfikacja pliku nagłówkowego wyzwala kompilację dla wszystkich docelowych obiektów), tak. Jednak można użyć zmiennych cmake, aby wyświetlić listę plików nagłówków tylko raz i użyć ich w kilku miejscach, zobacz moją edycję.
SirDarius,
1
Moje pytanie było bardziej w tym sensie, że mam kilka bibliotek, które są od siebie zależne: libroot, liba zależy od libroota, libb zależy od libroota. Czy mogę użyć LIBROOT_HEADER_FILESzmiennej w, liba/CMakefilea libb/CMakefilenastępnie?
Matthieu M.,
2
To jest złe, nie należy nigdy używać include_directoriesover target_include_directories. Ten pierwszy ustawia go rekurencyjnie dla wszystkich celów w tym katalogu; podczas gdy ten drugi wyznacza cel. Wykonanie pierwszego z nich łamie pojęcie grafu docelowego w CMake i zamiast tego opiera się na skutkach ubocznych w hierarchii plików.
Andy,
1
Zredagowałem odpowiedź, aby odzwierciedlić obecne pojęcie preferowania target_include_directoriesnowoczesnego kodu CMake. Jeśli nie zgadzasz się ze zmianami, zaproś mnie na czat.
ComicSansMS
74

Po pierwsze, include_directories()mówisz CMake, aby dodała katalog -Ido wiersza poleceń kompilacji. Po drugie, wypisujesz nagłówki w swoim add_executable()lub add_library()wywołaniu.

Na przykład, jeśli źródła twojego projektu są włączone srci potrzebujesz nagłówków z include, możesz to zrobić w następujący sposób:

include_directories(include)

add_executable(MyExec
  src/main.c
  src/other_source.c
  include/header1.h
  include/header2.h
)
Angew nie jest już dumny z SO
źródło
19
Czy naprawdę musisz dodać nagłówki add_executable? Myślałem, że CMake automatycznie zorientował się, jakie są zależności plików dołączanych.
Colin D Bennett
57
@ColinDBennett Nie musisz ich wymieniać ze względów zależności - CMake dobrze wymyśli zależności kompilacji, jeśli nie. Ale jeśli je wymienisz, będą one uważane za część projektu i jako takie zostaną wymienione w IDE (co było tematem pytania).
Angew nie jest już dumny z SO
Przynajmniej dla QtCreator nie jest konieczne dodawanie class.h w przypadku, gdy istnieje class.cpp. Tylko lonely.h należy dodać do źródła. Zobacz samouczek na www.th-thielemann.de/cmake
Th. Thielemann
19

CMake jest bardziej jak język skryptowy, jeśli porównuje się go z innymi sposobami tworzenia Makefile (np. Make lub qmake). Nie jest tak fajny jak Python, ale nadal.

Nie ma czegoś takiego jak „ właściwy sposób ”, jeśli w różnych projektach typu open source ludzie uwzględniają katalogi. Ale są na to dwa sposoby.

  1. Surowe katalog_włączenia doda katalog do bieżącego projektu i wszystkich innych projektów potomnych, które dodasz za pomocą szeregu poleceń add_subdirectory . Czasami ludzie mówią, że takie podejście jest dziedzictwem.

  2. Bardziej elegancki jest sposób z target_include_directories . Pozwala dołączyć katalog do konkretnego projektu / celu bez (być może) niepotrzebnego dziedziczenia lub kolizji różnych katalogów dołączanych. Pozwól także na wykonanie nawet subtelnej konfiguracji i dodaj jeden z następujących znaczników do tego polecenia.

PRYWATNE - użyj tylko dla tego określonego celu kompilacji

PUBLICZNY - użyj go dla określonego celu i celów, które łączą się z tym projektem

BERŁO - używaj go tylko do celów, które łączą się z bieżącym projektem

PS:

  1. Obie komendy pozwalają oznaczyć katalog jako SYSTEM, dając do zrozumienia, że ​​to nie twoja firma zawiera określone ostrzeżenia.

  2. Podobna odpowiedź jest z innymi parami poleceń target_compile_definitions / add_definitions , target_compile_options / CMAKE_C_FLAGS

bruziuz
źródło
13

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

Będzie to podobne do dzwonienia gccz -I/your/path/here/opcją.

Upewnij się, że umieściłeś podwójne cudzysłowy wokół ścieżki. Inni o tym nie wspominali i utknąłem na 2 dni. Ta odpowiedź jest więc dla osób, które są nowe w CMake i bardzo zdezorientowane.

off99555
źródło
7

Miałem ten sam problem.

Mój katalog projektów wyglądał tak:

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

I to, co zwykłem umieszczać pliki we wszystkich tych folderach:

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

    add_executable(Server ${source_files})

I to całkowicie zadziałało.

Seyed Hussein Mirzaki
źródło
Zapamiętywanie, że cmake jest „generatorem systemu kompilacji”, a nie „systemem budowania” za pomocą globu plików, nie jest dobrym pomysłem we współczesnym cmake (CMake z wersjami 3.0 i nowszymi), ponieważ globusy plików są oceniane w czasie „kompilacji”, a nie „kompilacji” czas generowania systemu. Zobacz link: gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1
ggulgulia