2013-10-13 19 views
9

Mam projekt cmake, w którym mam kilka modułów i używam Find - * .cmake do włączania współdzielonych modułów w aplikacji. Dla nie biorąc w uwagę każdy moduł, który dodam, jakie określono rodzaj globalnych LIB zmiennych tor linkera:cmake, zagubiony w koncepcji zmiennych globalnych (i PARENT_SCOPE lub add_subdirectory alternatives)

# inside a Find-*.cmake or in the CMakeLists.txt of the modules: 
set(LIB ${LIB} ...) 

więc w jednym z końcowych wniosków, które wykorzystuje niektóre moduły można po prostu zrobić:

target_link_libraries(${APP_NAME} ${LIB}) 

Następnie chciałbym mieć skompilowane moduły w /project_path/modules/foo/build, więc jeśli moduł jest naprawdę duży do kompilacji, może być skompilowany raz dla wszystkich aplikacji, które go używają. Droga ja osiągnięcia tego celu jest załadować CMakeLists.txt modułu od znalezienia - * cmake w ten sposób.

# Inside FindFoo.cmake, for loading /project_path/modules/foo/CMakeLists.txt 
# and compile it in /project_path/modules/foo/build 
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../modules/${PACKAGE_NAME} 
       ${CMAKE_CURRENT_LIST_DIR}/../modules/${PACKAGE_NAME}/build 
) 
include_directories(${CMAKE_CURRENT_LIST_DIR}/../modules/${PACKAGE_NAME}/include) 

Ale zdarzało się, że jakiś moduł wymaga kolejnych modułów, tak że tworzy add_subdirectory nowe zakresy i może poprawnie załadować LIB, ale nie może go zapisać (gdy używam set, jest w głębszym zasięgu i nie zmienia górnego zakresu). Na obwodnicy tego muszę dodać PARENT_SCOPE w set) .. Więc starałem się dodać go w jakiś moduł, który myślę, że może być zagnieżdżone i ukryte w pewnych zależnościach ale kompilacji wszystkich aplikacji nagle do czynienia z:

CMake Warning (dev) at /path_to_repo/cmake/FindFooX.cmake:6 (set): 
    Cannot set "LIB": current scope has no parent. 
Call Stack (most recent call first): 
    CMakeLists.txt:14 (find_package) 
This warning is for project developers. Use -Wno-dev to suppress it. 

Obawiam się, że może się to zmienić z aplikacji na aplikację w odniesieniu do potrzebnego modułu lub w odniesieniu do drzewa zależności w samych modułach, więc szukam czystszego rozwiązania.

Odpowiedz

20

Wszystkie zmienne w CMake są domyślnie lokalne. Chociaż można użyć parametru PARENT_SCOPE w celu zwiększenia zakresu zmiennej lokalnej o jedną warstwę, ma to najczęściej sens w przypadku zwracanych wartości functions.

Do znajdowania skryptów z drugiej strony zwykle potrzebne jest zachowanie zmiennej globalnej: Po wywołaniu skryptu wyszukiwania przez dowolne osoby, wyniki mają być dostępne wszędzie. W szczególności drugie wywołanie tego samego skryptu znajdowania powinno ponownie wykorzystywać wyniki pierwszego połączenia. W CMake osiąga się to przez przechowywanie zmiennych w pamięci podręcznej. Różne wywołania find_* już to robią automatycznie, więc powinieneś preferować używanie tych, o ile ma to zastosowanie. W przypadku jakichkolwiek dodatkowych zmiennych niestandardowych, set oferuje możliwość przechowywania w pamięci podręcznej, a także:

set(MY_GLOBAL_VARIABLE "Some value" CACHE STRING "Description") 

Zauważ, że zmienne lokalne mogą ukryć buforowane zmienne o tej samej nazwie w ich zakresie.

+0

przykro, ale ja nie rozumiem dokładnie, jak używać tych buforowanych zmiennych globalnych. Próbowałem zastąpić wszystkie wystąpienia 'set (LIB $ {LIB} $ {PACKAGE_NAME})' z pakietem 'set (LIB $ {LIB} $ {PACKAGE_NAME} CACHE STRING" "), ale na końcu, jeśli i' message ("- $ {LIB}") tylko pierwszy pakiet, który wywołałem, jest zawarty w $ {LIB} .. – nkint

+0

@nkint Sprawdź dokumentację dla 'set' I połączone powyżej. CMake zakłada, że ​​buforowane wartości zazwyczaj nie będą aktualizowane po ich utworzeniu, więc potrzebujesz później dodatkowego parametru 'FORCE'. – ComicSansMS

+1

więc zamieniłem wszędzie na 'set (LIB $ {LIB} $ {PACKAGE_NAME} CACHE STRING" Description "FORCE)', również wypróbowałem z 'INTERNAL' ale nie działa tak: brak błędów ale dodana biblioteka dodana do podpakietu z 'add_subdirectories' nie są już obecne w górnym zakresie – nkint

25

można 'symulować' zmienna globalna zachowanie, za pomocą właściwości w zakresie globalnym:

SET_PROPERTY(GLOBAL PROPERTY MyGlobalProperty "MyGlobalPropertyValue") 

Następnie można wyodrębnić własność globalnego za pomocą

GET_PROPERTY(MyLocalVariable GLOBAL PROPERTY MyGlobalProperty) 

Następnie MyLocalVariable zawiera " MyGlobalPropertyValue ".

Ponieważ PARENT_SCOPE rozszerza definicje zmiennych do jedynego katalogu nadrzędnego (a nie do jego rodziców), istnieją przypadki, to nie wystarczy, na przykład, jeśli masz głębokie drzewa źródłowego ...