2015-04-27 4 views
5

Rozważmy następujący minimalny przykład:Zestaw zmiennych z PARENT_SCOPE są puste w odpowiednim zasięgu podrzędnym. Czemu?

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

gdzie ./CMakeLists.txt jest

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}") 

i ./bar/CMakeLists.txt jest

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

Istotna część wyjściu cmake to:

... 
-- 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. 
... 

Ponieważ zmienna BAR jest umieszczana w zasięgu nadrzędnym, oczekiwałbym, że będzie ona dostępna również w bieżącym zasięgu podrzędnym (i w kolejnych) - tak jak zmienna FOO, która definiuje zakres rodzica do zaczynać się. Ale jak widać w powyższych wierszach zmienna BAR jest pusta ./bar/CMakeLists.txt, które prowadzą mnie do następujące pytania:

Dlaczego jest zakres rodzic zmodyfikowany nie od razu dostępne w zakresie, ./bar/ dziecko ? Czy można to złagodzić? Jeśli tak, w jaki sposób? A jeśli nie, co to jest obejście ? Czy też zupełnie brakuje mi czegoś oczywistego?

Kontekst: mój projekt składa się z kilku plików wykonywalnych i bibliotek. Dla biblioteki , np. bar, Chciałbym ustawić zmienną bar_INCLUDE_DIR, która jest dodawana do ścieżek dołączania każdego zależnego pliku wykonywalnego, tj. target_include_directories(my_target PUBLIC bar_INCLUDE_DIR).

Odpowiedz

2

Kontekst: mój projekt składa się z kilku plików wykonywalnych i bibliotek. W przypadku biblioteki, np. bar, chciałbym ustawić zmienną bar_INCLUDE_DIR, która jest dodawana do ścieżek dołączania dowolnego zależnego pliku wykonywalnego.

Jest o wiele lepszy sposób na zrobienie tego niż ustawienie zmiennych w zakresie rodzica. CMake pozwala celowi na określenie katalogów, symboli preprocesora itp., Które mogą być używane w zależności od celów.W twoim przypadku możesz użyć target_include_directories.

Na przykład:

target_include_directories(my_target PUBLIC my_inc_dir) 
+0

W rzeczywistości to właśnie używam. Ale ponieważ 'my_target' ma zasięg * rodzeństwa * w stosunku do wymaganej biblioteki' bar', używam objazdu za pośrednictwem zakresu nadrzędnego, aby przekazać lokalizację katalogu zawierającego. – nils

+0

Nie potrzebujesz zmiennych do przekazania tych informacji. Wszystko, co musisz zrobić, to zastosować 'target_include_directories' w bibliotece, a wszystkie inne obiekty docelowe, które będą z niego korzystać, automagicznie uzyskają odpowiednie katalogi w swojej ścieżce dołączania. – Lindydancer

+2

Aaah, teraz rozumiem, co masz na myśli. W rzeczy samej jest znacznie lepiej. Dzięki za wytrwałość! – nils

5

nie widzę niczego, co nie jest zgodne z SET command documentation

Jeśli PARENT_SCOPE występuje zmienna zostanie ustawiony w zakresie powyżej bieżącego zakresu. Każdy nowy katalog lub funkcja tworzy nowy zakres. To polecenie ustawi wartość zmiennej w katalogu nadrzędnym lub funkcji wywołującej (w zależności od przypadku).

./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 

Zawsze można zrobić:

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

Grep dla PARENT_SCOPE w dostarczonych modułów w instalacji, na przykład FindGTK2

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

Cóż, weź pod uwagę zmienną "FOO", która jest zdefiniowana w zakresie rodzica na początek, wtedy ta zmienna jest również dostępna w zasięgu podrzędnym (patrz zaktualizowany przykład). Dlaczego więc "BAR" nie byłby dostępny w zakresie podrzędnym, jeśli oba żyją w tym samym (macierzystym) zakresie? Oczekuję, że dokumentacja wspomnie o takim zachowaniu. – nils

+0

To może być postrzegane jako [efekt uboczny] (http://en.wikipedia.org/wiki/Side_effect_%28computer_science%29) – Peter

5

Piotr wyjaśnił również powody takiego zachowania.

Rozwiązaniem Zwykle używam w tym przypadku jest, aby ustawić pamięci podręcznej zmienną, która będzie widoczna wszędzie:

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

INTERNAL jest, aby to nie jest widoczna z cmake-gui. FORCE to upewnić się, że zostanie zaktualizowany, jeśli zmienisz coś na przykład w strukturze folderów. Pusty łańcuch jest łańcuchem opisu, który możesz wypełnić, jeśli uważasz, że jest to konieczne.

+0

Dzięki za wskazanie opcji 'CACHE'. Jednakże, rozumiejąc, co oznaczało @Lindydancer, preferuję tę metodę. – nils

Powiązane problemy