2013-03-07 8 views
8

Sono nuovo di CMake e ho un problema a cui non riesco a capire una soluzione. Sto usando CMake per compilare un progetto con un gruppo di sotto-dir opzionali e crea file di libreria condivisi come previsto. Questa parte sembra funzionare bene. Ciascuna di queste sub-dir contiene un file sql. Devo concat tutto tutti i file sql selezionati in un file di intestazione sql e installare il risultato. Così un file come:Utilizzando CMake, come posso concatare i file e installarli

sql_header.sql 
sub_dir_A.sql 
sub_dir_C.sql 
sub_dir_D.sql 

Se ho fatto questo direttamente in un file make potrei fare qualcosa di simile a quanto segue solo più intelligente per affrontare solo i sub-directory selezionati:

cat sql_header.sql > "${INSTALL_PATH}/somefile.sql" 
cat sub_dir_A.sql >> "${INSTALL_PATH}/somefile.sql" 
cat sub_dir_C.sql >> "${INSTALL_PATH}/somefile.sql" 
cat sub_dir_D.sql >> "${INSTALL_PATH}/somefile.sql" 

ho sorta della capito pezzi di questo, come posso usare:

LIST(APPEND PACKAGE_SQL_FILES "some_file.sql") 

che presumo che posso mettere in ognuno dei file sub-dirs CMakeLists.txt per raccogliere i nomi dei file. E posso creare una macro simile:

CAT(IN "${PACKAGE_SQL_FILES}" OUT "${INSTALL_PATH}/somefile.sql") 

Ma mi sono perso tra quando il CMake corre inizialmente e quando viene eseguito dal make install. Forse c'è un modo migliore per farlo. Ho bisogno che funzioni su Windows e Linux.

Sarei felice con alcuni suggerimenti per indicarmi la giusta direzione.

risposta

10

È possibile creare il file concatenato utilizzando principalmente i comandi file e function di CMake.

In primo luogo, creare una funzione cat:

function(cat IN_FILE OUT_FILE) 
    file(READ ${IN_FILE} CONTENTS) 
    file(APPEND ${OUT_FILE} "${CONTENTS}") 
endfunction() 

Supponendo di avere l'elenco dei file di input nella variabile PACKAGE_SQL_FILES, è possibile utilizzare la funzione in questo modo:

# Prepare a temporary file to "cat" to: 
file(WRITE somefile.sql.in "") 

# Call the "cat" function for each input file 
foreach(PACKAGE_SQL_FILE ${PACKAGE_SQL_FILES}) 
    cat(${PACKAGE_SQL_FILE} somefile.sql.in) 
endforeach() 

# Copy the temporary file to the final location 
configure_file(somefile.sql.in somefile.sql COPYONLY) 

La ragione per la scrittura a un temporaneo è così il vero file di destinazione viene aggiornato solo se il suo contenuto è cambiato. Vedi this answer per il motivo per cui questa è una buona cosa.

Si noti che se si includono le sottodirectory tramite il comando add_subdirectory, le sottodirectory hanno tutte il proprio ambito fino alle variabili CMake. Nelle sottodirectory, utilizzando list verranno applicate solo le variabili nell'ambito di tale sottodirectory.

Se si desidera creare un elenco disponibile nell'ambito genitore, è necessario utilizzare set(... PARENT_SCOPE), ad es.

set(PACKAGE_SQL_FILES 
    ${PACKAGE_SQL_FILES} 
    ${CMAKE_CURRENT_SOURCE_DIR}/some_file.sql 
    PARENT_SCOPE) 

Tutto questo finora ha semplicemente creato il file concatenato nella radice dell'albero di generazione. Per installarlo, probabilmente si desidera utilizzare il comando install(FILES ...):

install(FILES ${CMAKE_BINARY_DIR}/somefile.sql 
     DESTINATION ${INSTALL_PATH}) 

Così, ogni volta CMake corre (o perché si richiama manualmente o perché rileva le modifiche quando non "fare"), si aggiornerà il concatenati file nell'albero di compilazione. Solo una volta eseguito "make install" il file verrà finalmente copiato dalla root di compilazione al percorso di installazione.

+0

Bel uso di configure_file ... ;-) – DLRdave

+0

Grazie, è stato molto utile.È difficile ottenere risultati in bolla se si hanno più directory a più profondità, ma ho avuto modo di lavorare usando i suggerimenti molto utili. Grazie! –

+0

Ho provato questo, e ha funzionato ... a meno che il file non abbia il punto e virgola, a quel punto fallisce perché il punto e virgola viene rimosso in modo silenzioso. Questa è una normale conseguenza del fatto che il punto e virgola è il separatore di lista in cmake. Il caso di test più semplice che mostra il problema è 'set (CONTENTS" a; b; c \ n ") file (WRITE out.txt $ {CONTENTS})' La correzione è di citare il contenuto quando si scrive, ad es. '" $ {CONTENTS} "' –

Problemi correlati