2015-04-27 6 views
5

consideri il seguente esempio minimo:Le variabili impostate con PARENT_SCOPE sono vuote nello scope secondario corrispondente. Perché?

. 
├── bar 
│   └── CMakeLists.txt 
└── CMakeLists.txt 

dove ./CMakeLists.txt è

project(foo) 
cmake_minimum_required(VERSION 2.8) 

set(FOO "Exists in both, parent AND in child scope.") 

add_subdirectory(bar) 
message(STATUS "Variable BAR in ./  = ${BAR}") 
message(STATUS "Variable FOO in ./  = ${FOO}") 

e ./bar/CMakeLists.txt è

set(BAR "Exists in parent scope only." PARENT_SCOPE) 
message(STATUS "Variable BAR in ./bar/ = ${BAR}") 

La parte rilevante della produzione di cmake è questo:

... 
-- Variable BAR in ./bar/ = 
-- Variable FOO in ./bar/ = Exists in both, parent AND in child scope. 
-- Variable BAR in ./  = Exists in parent scope only. 
-- Variable FOO in ./  = Exists in both, parent AND in child scope. 
... 

Poiché la variabile BAR è inserita nello scope padre, mi aspetto che sia disponibile anche nell'attuale ambito figlio (e in quelli successivi), proprio come la variabile FOO, che è definita l'ambito genitore su iniziare con. Ma come si può vedere nelle righe sopra la variabile BAR è vuoto in ./bar/CMakeLists.txt, che mi portano a alle seguenti domande:

Perché l'ambito genitore modificato non immediatamente accessibili nel bambino campo di applicazione, ./bar/? Questo può essere mitigato? Se sì, come? E se no, che cos'è un work-around ? O mi manca completamente qualcosa di ovvio?

Contesto: il mio progetto è composto da diversi eseguibili e librerie. Per una libreria , ad es. bar, Vorrei impostare una variabile bar_INCLUDE_DIR che sia aggiunta ai percorsi di inclusione di qualsiasi eseguibile dipendente, ad esempio target_include_directories(my_target PUBLIC bar_INCLUDE_DIR).

risposta

2

Contesto: il mio progetto è composto da diversi eseguibili e librerie. Per una biblioteca, ad es. bar, vorrei impostare una variabile bar_INCLUDE_DIR che viene aggiunta ai percorsi di inclusione di qualsiasi eseguibile dipendente.

Esiste un modo molto migliore per farlo rispetto all'impostazione delle variabili nell'ambito genitore. CMake consente a un target di specificare directory incluse, simboli del preprocessore, ecc. Che possono essere utilizzati dagli obiettivi dipendenti.Nel tuo caso, puoi utilizzare target_include_directories.

Ad esempio:

target_include_directories(my_target PUBLIC my_inc_dir) 
+0

In realtà, questo è quello che uso. Ma poiché 'my_target' si trova in un * fratello * rispetto a una' bar' di libreria richiesta, io uso la deviazione tramite l'ambito genitore per inoltrare il percorso della directory include. – nils

+0

Non hai bisogno di variabili per trasmettere tali informazioni. Tutto quello che devi fare è applicare 'target_include_directories' nella libreria e tutti gli altri target che lo utilizzano otterranno automaticamente le directory rilevanti nel loro percorso di inclusione. – Lindydancer

+2

Aaah, ora capisco cosa intendi. È molto meglio, davvero. Grazie per la tua persistenza! – nils

5

non vedo nulla che non sia coerente con la SET command documentation

Se PARENT_SCOPE è presente, la variabile sarà impostata nel campo di applicazione sopra l'ambito corrente. Ogni nuova directory o funzione crea un nuovo ambito. Questo comando imposterà il valore di una variabile nella directory principale o nella funzione di chiamata (qualunque sia applicabile al caso in questione).

./bar/CMakeLists.txt

set(BAR "This is bar." PARENT_SCOPE) #<-- Variable is set only in the PARENT scope 
message(STATUS "Variable BAR in ./bar/ = ${BAR}") #<--- Still undefined/empty 

Si può sempre fare:

set(BAR "This is bar.") #<-- set in this scope 
set(BAR ${BAR} PARENT_SCOPE) #<-- set in the parent scope too 

Grep per PARENT_SCOPE nei moduli consegnati nella vostra installazione, per esempio FindGTK2

if(GTK2_${_var}_FOUND) 
    set(GTK2_LIBRARIES ${GTK2_LIBRARIES} ${GTK2_${_var}_LIBRARY}) 
    set(GTK2_LIBRARIES ${GTK2_LIBRARIES} PARENT_SCOPE) 
endif() 
+2

Bene, si consideri una variabile 'FOO' che è definita nello scope genitore per cominciare, quindi questa variabile è disponibile anche nell'oscilloscopio secondario (vedere l'esempio aggiornato). Quindi, perché "BAR" non dovrebbe essere disponibile nello scope figlio se entrambi vivono nello stesso ambito (genitore)? Mi aspetto che la documentazione menzioni un simile comportamento. – nils

+0

Questo potrebbe essere visto come [effetto collaterale] (http://en.wikipedia.org/wiki/Side_effect_%28computer_science%29) – Peter

5

Peter spiegato bene il motivo di questo comportamento.

Una soluzione Io di solito uso in questo caso è quello di impostare una variabile nella cache, che sarà visibile in tutto il mondo :

set(BAR "Visible everywhere" 
     CACHE INTERNAL "" FORCE 
) 

INTERNAL è quello di rendere non visibili da cmake-gui. FORCE è quello di assicurarsi che venga aggiornato se si modifica qualcosa, ad esempio nella struttura delle cartelle. La stringa vuota è una stringa descrittiva, che potresti voler compilare se ritieni che sia necessario.

+0

Grazie per aver indicato l'opzione 'CACHE'. Tuttavia, avendo capito cosa volesse dire @Lindydancer, tendo a preferire questo metodo. – nils

Problemi correlati