2011-12-21 15 views
9

Ho una base di codice di grandi dimensioni che costruisce diverse dozzine di libarini e diversi eseguibili.qual è l'uso corretto della direttiva "progetto" di CMake

Il codebase è suddiviso gerarchicamente e le librerie sono costruite praticamente a ogni livello.

Ho passato e ho inserito un file CMakeLists.txt in ogni directory per creare ciascuna libreria.

In ogni CMakeLists.txt ho utilizzato la direttiva "progetto (xxx)". Questo ha definito per me le variabili PROJECT_NAME, PROJECT_SOURCE_DIR e PROJECT_BINARY_DIR di cui faccio un uso giudizioso.

Tuttavia, uno dei membri della squadra non è soddisfatto di questo approccio in quanto non riesce a trovare esempi reali di chiunque altro abbia fatto questo. Spesso cita gli esempi di KitWare come non usando questo approccio e quindi nemmeno noi dovremmo.

L'approccio alternativo che sta sostenendo è impostare queste variabili in ciascun makefile che sembra molto simile a ciò che "progetto" ti offre.

Non riesco davvero a vedere il suo punto e sto facendo pochi passi avanti nel convincerlo del contrario. Qualcuno può fare luce sugli aspetti negativi dell'utilizzo della direttiva di progetto in questo modo.

Mi lancio sulla saggezza collettiva?

+0

Come si usano le variabili 'PROJECT_NAME',' PROJECT_SOURCE_DIR' e 'PROJECT_BINARY_DIR'? E queste librerie sono indipendenti o sono solo parti di una libreria/applicazione principale? –

+0

Uso queste variabili all'interno di macro che generano codice sorgente. Creo un obiettivo di livello superiore chiamato $ {PROJECT_NAME} _SPDEF da cui altri progetti possono dipendere per forzarne la generazione. Io uso anche le variabili _DIR per posizionare il codice generato nella posizione appropriata. – ScaryAardvark

risposta

12

In primo luogo, consente di utilizzare <projectName>_BINARY_DIR e <projectName>_SOURCE_DIR, ma questo non è il vantaggio principale. Se si assegna a CMake il nome di un progetto, questo genererà i target di costruzione per ciascuno dei sottoprogetti nelle proprie directory. Ciò significa che, sia che si utilizzi GNU Make, Eclipse CDT, XCode o qualsiasi altro generatore supportato, è possibile creare singoli progetti secondari. Ad esempio con GNU Make ogni sottoprogetto ha il proprio sistema di compilazione completo dalla propria directory.

È possibile accedere al nome del progetto corrente tramite PROJECT_NAME e il nome del progetto root per CMAKE_PROJECT_NAME.

Modifica: ho appena realizzato che il seguente comportamento standard di CMake per i suoi obiettivi di compilazione, indipendentemente dal fatto che siano progetti o meno. Lo terrò qui per informazioni generali, ma non è pertinente alla risposta:

Supponiamo che disponga di una libreria C++ e che possa generare tre eseguibili binari; Main e tests/test1 e examples/ex1. Posso eseguire make nella directory che ho chiamato CMake con il target ALL, eseguire make ex1 oppure posso cambiare la directory in examples/ e creare gli esempi con make da quella directory. In questo modo verranno creati tutti i progetti e le librerie dipendenti anche se si trovano da qualche altra parte nella struttura delle directory, ma non verranno creati Main o tests/test1 o qualsiasi libreria da cui dipendono, a differenza di examples/ex1. Se eseguo make dalla directory principale, non ricostruirà nessuna delle librerie da cui dipende examples/ex1 a meno che la loro origine non sia stata modificata.

+1

La possibilità di essere in grado di "cd" a qualsiasi livello della gerarchia di build e fare "make all" e avere tutti gli artefatti costruiti da questo livello verso il basso è una grande vittoria per me. Grazie. – ScaryAardvark

+0

@ScaryAardvark la possibilità di eseguire diversi comandi per diversi compilatori e di includere codice diverso con diversi sistemi operativi automaticamente è davvero piacevole, inoltre è molto facile eseguire operazioni abbastanza avanzate con un paio di linee di codice. Comprimo le risorse con 'zip' con CMake, che funziona bene su qualsiasi piattaforma/IDE/toolchain. Rende anche molto facile la compilazione incrociata per ARM, ecc. Dovresti anche controllare il sistema di test integrato di CMake, [CTest] (http://www.vtk.org/Wiki/CMake_Testing_With_CTest). Esistono anche plugin CMake per sistemi CI come Jenkins. –

+0

Sì, sono familiare con questo. Una delle domande che ho fatto è stato il modo in cui cmake gestisce una versione diversa dello stesso compilatore ... cioè abbiamo una sezione del nostro albero del progetto che può essere compilata solo con sunstudio11 e la maggior parte di essa ha bisogno di sunstudio12. Penso che solleverò un'altra domanda a riguardo, ma grazie :) – ScaryAardvark

0

Se le librerie sono progetti veramente indipendenti, è quindi opportuno utilizzare il comando project. Tuttavia, se non lo sono, vorrei invece aggiungerli come sottodirectory nella tua radice CmakeLists.txt. È possibile utilizzare le variabili CMAKE_CURRENT_SOURCE_DIR e CMAKE_CURRENT_BINARY_DIR se è necessario conoscere le directory attualmente in fase di elaborazione.

+0

Esiste un CMAKE_CURRENT_PROJECT. Se c'è allora posso vedere il tuo punto, tuttavia se devo usare set() per creare questa variabile (o qualcosa di simile), allora perché non usare "project" e avere tutte le variabili create per me. – ScaryAardvark

0

Ho trovato un buon esempio di utilizzo proprio di questo oggi: aggiungere la documentazione di Doxygen.

Uso CMake (e Ninja) per creare i miei progetti C++ personali. Ho deciso per un capriccio di aggiungere una documentazione di Doxygen ad uno dei miei sforzi più completi ma non documentati. Ho anche pensato che sarebbe stato utile aggiungerlo anche agli altri progetti appena ho capito come renderlo il più generico possibile.

Per iniziare, ho generato un modello Doxygen standard e lo ho rinominato.

cd my_projects/projectx 
doxygen -g Doxyfile 
mv Doxyfile Doxyfile.in 

Nota l'estensione .in. Probabilmente non necessario ma convenzionale, se ho capito bene.

Successivamente, ho aggiunto il seguente blocco di codice nel mio file CMakeLists.txt, appena prima di definire i miei obiettivi (non sono sicuro se ciò è importante ma CMake a volte è esigente riguardo alla sequenza di determinati comandi).

FIND_PACKAGE(Doxygen) 
IF("${DOXYGEN_FOUND}" MATCHES "^YES$") 
    CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in 
        ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 
        @ONLY) 
    ADD_CUSTOM_TARGET( doc ALL 
         COMMAND ${DOXYGEN_EXECUTABLE} 
         ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 
         WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 
         COMMENT "Doxygenating..." 
         VERBATIM) 
ENDIF() 

Questo crea un nuovo obiettivo chiamato doc. Specificando ALL lo si aggiunge al target "tutto" predefinito, ma questo è facoltativo. Specificando @ONLY, le variabili di tipo "$ {variable}" non verranno espanse da CONFIGURE_FILE, solo i tipi "@ variable @". Un po 'di confusione (almeno per me), CMAKE_CURRENT_SOURCE_DIR sembra riferirsi alla directory del progetto e CMAKE_CURRENT_BINARY_DIR alla directory di build.

Infine, ed è qui che entra PROJECT_NAME, ho modificato Doxyfile.in.

Questo è l'inizio della mia nuova Doxyfile.in:

DOXYFILE_ENCODING  = UTF-8 
PROJECT_NAME   = "@[email protected]" 
PROJECT_NUMBER   = @[email protected] 
PROJECT_BRIEF   = 
PROJECT_LOGO   = @[email protected]/res/doc_logo-200x55.png 
OUTPUT_DIRECTORY  = @[email protected]/doc 

Si ottiene l'idea, credo. Una volta che questo è completamente generico (è una parola?) Posso copiarlo nei miei altri progetti e, finché codifico il mio codice, avrò una buona documentazione ovunque.

Avviso PROJECT_BRIEF non specificato. Non ho finito con questo e ci sono ancora alcuni spazi vuoti su cui riflettere. Ad esempio PROJECT_VERSION_TWEAK in realtà non contiene ancora nulla. Dovrò trovare un modo per ottenere il mio numero di build lì.

Problemi correlati