2013-10-13 21 views
11

Sto utilizzando il modulo FindProtobuf in un progetto in cui i file del buffer del protocollo si trovano in una sottodirectory. Voglio che il file CMakeLists.txt in quella sottodirectory invochi protoc per generare i file CPP. Il mio progetto struttura di cartelle è come questo:CMake e FindProtobuf

cammy/CMakeLists.txt # Root CMakeLists.txt 
cammy/protofiles/test.proto # protofile 
cammy/protofiles/CMakeLists.txt 

ho la comprendono (FindProtobuf), l'invocazione find_package e la chiamata alla PROTOBUF_GENERATE_CPP nel file CMakeLists.txt nella cartella protobuf.

Il passaggio di generazione eseguibile è nel file Root CMakeLists.txt e aggiungere i file generati al file eseguibile di destinazione in questo file es.

add_executable(${EXEC} ${SRCS} ${PROTO_SRC} ${PROTO_HEADER}) 
target_link_libraries(${EXEC} ${PROTOBUF_LIBRARIES}) 

sono entrambe definite nella radice CMakeLists.txt

Quando corro cmake, non viene eseguito ProtoC generare file sorgente anche se expilicitly legare fonti generati all'eseguibile creando così una dipendenza.

Quando si spostano tutti i contenuti di CMakeLists.txt nella cartella protofiles nella radice CMakeLists.txt, i file di proto vengono compilati.

Qualcuno può aiutarmi con questo? Voglio che tutto il protocollo di costruzione del buffer vada nel file CMakeLists.txt creato nella cartella protofiles.

Ho anche notato che le variabili generate nel CMakeLists.txt interno (come PROTO_SRC) sono definite nel file interno quando stampate (cioè ottengo il nome file CPP generato correttamente) ma quando stampo la stessa variabile nel file radice. . è vuoto. È quasi come se avessi bisogno di "esportare" (se ci fosse un modo in cmake) le variabili nella cartella radice.

Qualsiasi aiuto sarebbe molto apprezzato.

Grazie Kartik

risposta

19

penso FindProtobuf non si intende veramente per essere utilizzato in questo modo. Dai suoi documenti:

NOTA: Le macro PROTOBUF_GENERATE_CPP & add_executable() o add_library() le chiamate di lavoro correttamente solo all'interno della stessa directory.

si sta cercando di utilizzare la macro PROTOBUF_GENERATE_CPP in una sottodirectory, e anche se la documentazione CMake in realtà non mettere in chiaro, una sottodirectory introduce un nuovo ambito per le variabili. Ciò significa che tutte le variabili impostate o modificate nell'ambito del sottodir non influiscono sulle variabili con nome simile nell'ambito genitore. Da qui il motivo per PROTO_SRC disponibile nella tua directory dei file protofili, ma non nel genitore.

Il modo per passare le variabili un ambito è quello di utilizzare set(... PARENT_SCOPE), quindi in protofiles/CMakeLists.txt si potrebbe fare:

PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HEADER test.proto) 

set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIRS} PARENT_SCOPE) 
set(PROTOBUF_LIBRARIES ${PROTOBUF_LIBRARIES} PARENT_SCOPE) 
set(PROTO_SRC ${PROTO_SRC} PARENT_SCOPE) 
set(PROTO_HEADER ${PROTO_HEADER} PARENT_SCOPE) 

Tuttavia, questo ancora non ci porti fino in fondo!

CMake in realtà non invocare il compilatore ProtoC per generare il .pb.h ei file .pb.cc - usa add_custom_command per fare questo. Il comando personalizzato specifica .pb.h e .pb.cc file come output, e il comando custom viene invocato (cioè protoc eseguito) se viene creato un target successivo che dipende da questi file.

Quindi, al momento della configurazione (quando CMake esegue) questi file non esistono. Questo è un problema se si tenta di aggiungerli come sorgenti a un comando add_library o add_executable - CMake deve essere informato che questi file non esistono quando viene eseguito, ma che essi sono esistenti al momento della compilazione.

Il modo per farlo è impostare la proprietà GENERATED su TRUE per questi file. La macro PROTOBUF_GENERATE_CPP viene eseguita automaticamente, ma come per le variabili, la proprietà non viene popolata nell'ambito principale. Quindi nel tuo CMakeLists.txt di livello superiore, è inoltre necessario aggiungere:

set_source_files_properties(${PROTO_SRC} ${PROTO_HEADER} PROPERTIES 
          GENERATED TRUE) 

Come si può vedere, utilizzando PROTOBUF_GENERATE_CPP in una directory diversa ai corrispondenti add_library/add_executable comandi è un po 'fragile. Se tu puoi evitare di farlo, probabilmente dovresti.

+0

Grazie per chiarire le cose. Per riassumere, ho ragione nel dire che il motivo per cui la proto compilazione nidificata non funziona è perché le variabili generate non sono nello scope della torre? Inoltre, è possibile contrassegnare il flag GENERATO quando impostiamo le variabili dell'ambito genitore da quelle locali invece di doverlo fare nel file root? Infine, un approccio alternativo potrebbe essere quello di costruire il materiale di protobuf come libreria e collegarlo semplicemente all'eseguibile di root? –

+0

@KartikAiyer Non si sa cosa significhi "non nell'ambito della torre", ma se "non è nell'ambito di CMakeLists.txt di livello superiore", allora sì. Per Q2, no - per quanto ne so non c'è modo di impostare le proprietà sui file che sono definiti nell'ambito genitore. Per il terzo trimestre, sì, credo che sarebbe un buon approccio. – Fraser

+0

@Fraser ti ringrazio per la risposta, ho una domanda simile, aggiusto il progetto e ancora non funziona, è possibile che mi dia più suggerimenti? ref: http://stackoverflow.com/questions/29720410/no-member-found-when-use-cmake-construct-proto, progetto di esempio: https://github.com/yuikns/cmake-proto –