Come aggiungere correttamente le directory include con CMake


243

Circa un anno fa ho chiesto informazioni sulle dipendenze delle intestazioni in CMake .

Di recente mi sono reso conto che il problema sembrava essere che CMake considerasse quei file di intestazione esterni al progetto. Almeno, quando si genera un progetto Code :: Blocks i file di intestazione non vengono visualizzati all'interno del progetto (i file di origine lo fanno). Pertanto, mi sembra che CMake consideri tali intestazioni esterne al progetto e non le tiene traccia delle dipendenze.

Una rapida ricerca nel tutorial di CMake ha indicato solo include_directoriesche non sembra fare quello che desidero ...

Qual è il modo corretto di segnalare a CMake che una determinata directory contiene intestazioni da includere e che tali intestazioni devono essere tracciate dal Makefile generato?


Le modifiche apportate a questa domanda la rendono confusa. La domanda e le risposte originali erano come tenere traccia dei file di intestazione in un IDE. Questo è abbastanza diverso dalle dipendenze del file di intestazione mancante di un Makefile generato e da come risolvere quel problema.
fdk1342,

@Fred: non ho idea di cosa tu stia parlando. Come mostra chiaramente la revisione della modifica, l'ultima frase è sempre stata lì. Su questa domanda sono state apportate solo modifiche cosmetiche e nessuna parola è stata introdotta (o rimossa).
Matthieu M.

Quindi questo è il mio fraintendimento. Mi è sembrato che fosse aggiunto un intero paragrafo. stackoverflow.com/questions/13703647/… afferma che l'intesa comune era come elencare il file di intestazione nell'IDE. Ciò si sarebbe riferito al .cbpfile di progetto. Ora se lo scanner di dipendenza cmake non riesce a identificare correttamente un file di intestazione come dipendenza per un Makefile, ci sono modi per risolverlo, ma in alcuni casi lo sbaglierà perché non include un preprocessore completo.
fdk1342,

Risposte:


267

Due cose devono essere fatte.

Per prima cosa aggiungi la directory da includere:

target_include_directories(test PRIVATE ${YOUR_DIRECTORY})

Nel caso in cui tu sia bloccato con una versione CMake molto vecchia (2.8.10 o precedente) senza supporto target_include_directories, puoi include_directoriesinvece usare l'eredità :

include_directories(${YOUR_DIRECTORY})

Quindi è anche necessario aggiungere i file di intestazione all'elenco dei file di origine per la destinazione corrente, ad esempio:

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

In questo modo, i file di intestazione verranno visualizzati come dipendenze nel Makefile e, ad esempio, nel progetto Visual Studio generato, se ne viene generato uno.

Come utilizzare quei file di intestazione per diversi 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})

Ah! Sapevo che doveva essere qualcosa di stupido. In effetti, non ho elencato le intestazioni ... Devo elencare le intestazioni solo di questa libreria o anche tutte le intestazioni da cui potrebbe dipendere (oltre a dichiarare la dipendenza dalla libreria)? È un progetto in crescita e temo piuttosto di aggiungere un'intestazione a tutte le dipendenze quando ne aggiungo una nella libreria di root.
Matthieu M.

Per consentire un migliore rilevamento delle dipendenze (ad esempio per assicurarsi che la modifica di un file di intestazione inneschi la compilazione per tutte le destinazioni interessate), sì. Tuttavia è possibile utilizzare le variabili cmake per elencare i file di intestazione una sola volta e utilizzarli in diversi punti, vedere la mia modifica.
SirDarius,

1
La mia domanda era più nel senso che ho diverse librerie che dipendono l'una dall'altra: libroot, liba dipende da libroot, libb dipende da libroot. Posso usare la LIBROOT_HEADER_FILESvariabile in liba/CMakefilee libb/CMakefilepoi?
Matthieu M.

2
Questo è sbagliato, si dovrebbe mai usare include_directoriessopra target_include_directories. Il primo lo imposta in modo ricorsivo per tutti i target in quella directory; mentre quest'ultimo lo pone come obiettivo. Fare il primo rompe l'idea di un grafico di destinazione in CMake e si basa invece sugli effetti collaterali della gerarchia dei file.
Andy,

1
Ho modificato la risposta per riflettere l'attuale nozione di preferire target_include_directoriesil codice CMake moderna. Sentiti libero di invitarmi in una chat se non sei d'accordo con le modifiche.
ComicSansMS

74

Per prima cosa, usi include_directories()per dire a CMake di aggiungere la directory -Ialla riga di comando della compilazione. In secondo luogo, elenchi le intestazioni nel tuo add_executable()o add_library()chiama.

Ad esempio, se le fonti del tuo progetto sono presenti srce hai bisogno di intestazioni include, puoi farlo in questo modo:

include_directories(include)

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

19
Hai davvero bisogno di aggiungere intestazioni a add_executable? Ho pensato che CMake abbia capito automaticamente le dipendenze del file include.
Colin D Bennett,

57
@ColinDBennett Non è necessario elencarli per motivi di dipendenza. In caso contrario, CMake riesce a capire come creare le dipendenze. Ma se li elenchi, sono considerati parte del progetto e saranno elencati come tali negli IDE (che era l'argomento della domanda).
Angew non è più orgoglioso di SO

Almeno per QtCreator non è necessario aggiungere class.h nel caso esista un class.cpp. Solo lonely.h deve essere aggiunto alla fonte. Vedi tutorial su www.th-thielemann.de/cmake
Th. Thielemann il

19

CMake è più simile a un linguaggio di script se lo confronta con altri modi per creare Makefile (ad esempio make o qmake). Non è molto bello come Python, ma comunque.

Non esiste un " modo corretto " se si guarda in vari progetti open source come le persone includono le directory. Ma ci sono due modi per farlo.

  1. La grezza include_directory aggiunge una directory al progetto corrente e a tutti gli altri progetti discendenti che verranno aggiunti tramite una serie di comandi add_subdirectory . A volte le persone dicono che tale approccio è eredità.

  2. Un modo più elegante è con target_include_directories . Permette di aggiungere una directory per uno specifico progetto / target senza (forse) eredità o scontro inutili di varie directory include. Consenti anche di eseguire anche una configurazione sottile e aggiungi uno dei seguenti marcatori per questo comando.

PRIVATO : utilizzare solo per questo target di build specificato

PUBBLICO : utilizzalo per target specificato e per target che si collegano a questo progetto

INTERFACCIA : utilizzalo solo per obiettivi che si collegano al progetto corrente

PS:

  1. Entrambi i comandi consentono di contrassegnare una directory come SISTEMA per suggerire che non sono gli affari che le directory specificate conterranno avvisi.

  2. Una risposta simile è con altre coppie di comandi target_compile_definitions / add_definitions , target_compile_options / CMAKE_C_FLAGS


13

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

Questo sarà simile alla chiamata gcccon -I/your/path/here/opzione.

Assicurati di inserire doppie virgolette attorno al percorso. Altre persone non lo hanno menzionato e mi ha fatto rimanere bloccato per 2 giorni. Quindi questa risposta è per le persone che sono molto nuove in CMake e molto confuse.


7

Ho avuto lo stesso problema.

La mia directory di progetto era così:

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

E cosa ho usato per includere i file in tutte quelle cartelle:

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

    add_executable(Server ${source_files})

E ha funzionato totalmente.


Ricordare che cmake è un "generatore di sistema di build" e non un "sistema di build" che utilizza file glob non è una buona idea in cmake moderno (CMake con versioni 3.0 e successive) perché i globi di file vengono valutati al momento del "build" e non "build" tempo di generazione del sistema. Vedi link: gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1
ggulgulia
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.