Skip to content

beetroot-project/docs_compiled

Repository files navigation

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>&lt;no title&gt; &#8212; The Beetroot Project 0.9.0 documentation</title>
    <link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
    <script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
    <script type="text/javascript" src="_static/jquery.js"></script>
    <script type="text/javascript" src="_static/underscore.js"></script>
    <script type="text/javascript" src="_static/doctools.js"></script>
    <link rel="author" title="About these documents" href="about.html" />
    <link rel="index" title="Index" href="genindex.html" />
    <link rel="search" title="Search" href="search.html" />
   
  <link rel="stylesheet" href="_static/custom.css" type="text/css" />
  
  
  <meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />

  </head><body>
  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          

          <div class="body" role="main">
            
  <p>Design rationale
===</p>
<p>O tym, że CMake utrudnia definiowanie kompilacji projektu używając funkcji: wymusza globalne zmienne i zupełnie nie ułatwia przekazywanie i weryfikowanie argumentów funkcji.</p>
<p>Wykorzystywane są następujące cechy CMake:</p>
<ol class="arabic simple">
<li>Targety są definiowane zawsze w jednej globalnej przestrzeni (scope), co oznacza że targety mogą z powodzeniem być definiowane wewnątrz funkcji. Zróbmy z tego regułę.</li>
<li>Użytkownik definiuje zależności między  używając kodu CMake zamiast</li>
</ol>
<ol class="arabic simple">
<li>Tworzenie każdego targetu jako funkcja, która przyjmuje zadeklarowane parametry o określonych warunkach walidacji.
1a) Argumenty muszą być przekazywane na 3 sposoby: wartość domyślna podana podczas deklaracji argumentu (lub brak - argument obowiązkowy) -&gt; wartość podana z CACHE lub po prostu ze zmiennych dostępnych w CMake -&gt; wartość podana podczas wywoływania targetu, jako argument funkcji produjującej target.
1b) Niech użytkownik sam zajmuje się dependencies. W szczególności, niech sam przekazuje te parametry, które chce override, np. te, które mają być zafiksowane, lub jakieś własne.</li>
<li>Nazywanie targetu na podstawie jego argumentów po to, aby można było kompilować dwa targety różniące się tylko argumentami</li>
<li>Kompatybilność z CMakeLists.txt - systemem, który nie pozwala na dynamiczne definiowanie targetów i nie pozwala na deklaracje zmiennych</li>
<li>Wygoda dla użytkownika. Zero boilerplate.</li>
</ol>
<p>## Z tego wynikają następujące cechy:</p>
<p>1. System deklaracji parametrów, ich typów, reguł walidacyjnych i wartości domyślnych
1a) System łączący trzy źródła informacji o typach.
1b) Możliwość wywoływania funkcji tworzącej target rekurencyjnie. Dbanie o to, aby przerwać rekurencję - tj. musi być globalna właściwość, która zawiera listę aktualnie definiowanych targetów.
2. Po zebraniu wszystkich argumentów i posortowaniu ich - tworzenie z nich hasha, który tworzy nazwę instancji targetu (być może z prefiksem nazwy targetu). Rozróżnia się dwa pojęcia:</p>
<blockquote>
<div><ol class="arabic simple">
<li><cite>TARGET_INSTANCE</cite> - nazwa targetu, jaka jest wygenerowana przez <cite>add_executable</cite> lub <cite>add_library</cite> lub <cite>add_custom_target</cite>. Ta nazwa nie jest czytelna dla ludzi i jest hashem argumentów przekazanych do targetu i jego klasy (TARGET_TEMPLATE).</li>
<li><cite>TARGET_TEMPLATE</cite> - nazwa przepisu na generowanie targetów. Ta nazwa jest podana przez człowieka i musi być unikalna w całym projekcie. Np. LIB_LOG, GRIDTOOLS, ADVECTION_DRIVER.</li>
</ol>
</div></blockquote>
<ol class="arabic simple" start="3">
<li>Specjalna składnia dla deklarowania targetu jako targetu definiowanego przez CMakeLists.txt. Muszą tam się znaleźć nazwy definiowanych (i używanych przez nas) targetów, katalog źródłowy i nazwa katalogu (już z ew. prefiksami związanymi z wersjami zależności używanych podczas budowy, np. boost, gridtools). Podczas napotkania takiej definicji system sprawdzi, czy w oddzielnym pliku jest zawarta lista parametrów tego CMakeLists.txt. Jeśli jest, to będzie jej używać, a jeśli nie - to w oddzielnym procesie uruchomi CMake po to, aby ją dostać.</li>
</ol>
<p>4. Plik targets.cmake zawiera:
a)
<a href="#id1"><span class="problematic" id="id2">``</span></a>`
set(TARGET_PARAMETERS #DEFINE_MODIFIERS</p>
<blockquote>
<div>PATH    SCALAR  PATH ${CMAKE_costam}</div></blockquote>
<p>)
set(LINK_PARAMETERS #DEFINE_PARAMETERS</p>
<blockquote>
<div>PRECISION       SCALAR  INTEGER 4
ARCH    SCALAR  CHOICE(GPU;CPU) CPU</div></blockquote>
<p>)</p>
<dl class="docutils">
<dt>set(TARGET_FEATURES</dt>
<dd>USE_GPU OPTION  “” 0
COMPONENTS      VECTOR  STRING  “filesystem;log”</dd>
</dl>
<p>)</p>
<dl class="docutils">
<dt>set(TEMPLATE_OPTIONS</dt>
<dd>SINGLETON_TARGETS  #If set requires TARGET_TEMPLATE and generates error if ENUM_TEMPLATES is specified
NO_TARGETS #If set it declares that no targets will be generated. Generates error if <cite>generate_targets()</cite> is defined by the user.
LINK_TO_DEPENDEE #calls <cite>target_link_libraries()</cite>, even if the function <cite>apply_dependency_to_target()</cite> is defined
GENERATE_TARGETS_INCLUDE_LINKPARS # Make linkpars available in <cite>generate_targets()</cite>
LANGUAGES CUDA CXX
EXPORTED_VARIABLES USE_GPU
#This can be used to utilize LINK_PARAMETERS after the target is built to e.g. write a script.</dd>
</dl>
<p>)</p>
<p>set(ENUM_TEMPLATES &lt;UNIQUE NAME OF TARGET_TEMPLATE&gt;)
# Or optional, if for some reasons the target name must be fixed:
#set(ENUM_TARGETS &lt;UNIQUE NAME OF TARGET_TEMPLATE&gt;) #the set of actual target names we are capable of providing</p>
<p>#optional:
set(DEFINE_EXTERNAL_PROJECT</p>
<blockquote>
<div>SOURCE_PATH gridtools
ASSUME_INSTALLED
INSTALL_PATH /usr/lib/gridtools
WHAT_COMPONENTS_NAME_DEPENDS_ON boost compiler
COMPONENTS SerialboxC
BUILD_PARAMETERS USE_GPU ARCH</div></blockquote>
<p>)</p>
<p><a href="#id3"><span class="problematic" id="id4">``</span></a>`
Jeśli projekt nie jest external (tj. nie zdefiniowano DEFINE_EXTERNAL_PROJECT), definicję funkcji <cite>generate_targets()</cite> przyjmującej jako argument listę wartości zadeklarowanych w ENUM_TEMPLATES. Ta funkcja jest odpowiedzialna za tworzenie targetu o nazwie ${TEMPLATE_NAME}. Alternatywnie, jeśli dana część projektu nie jest w stanie generować targetu (np. starego typu dependency), to należy pominąć definicję <cite>generate_targets()</cite>, a zamiast napisać funkcję <cite>apply_dependency_to_target(DEPENDEE_TARGET_NAME OUR_TARGET_NAME)</cite> która aplikuje nasz projekt na istniejący target. Oczywiście nie można otrzymać dla takiego template targetu, więc wywołanie <cite>get_targets()</cite> z poziomu <cite>CMakeLists.txt</cite> dla template używającego <cite>apply_dependency_to_target()</cite> zakończy się niepowodzeniem. Za to można używać <cite>get_targets()</cite> z poziomu funkcji <cite>declare_dependencies()</cite>.</p>
<p>apply_dependency_to_target() nie jest wywoływana, jeśli target jest external</p>
<p>Definicję funkcji <cite>declare_dependencies()</cite> przyjmującej jako argument listę wartości zadeklarowanych w ENUM_TEMPLATES. Ta funkcja jest odpowiedzialna za tworzenie targetu o nazwie ${TEMPLATE_NAME}. Ta funkcja jest wywoływana podczas superbuild pass po to, aby wywołać ExternalProjects_Add dla zewnętrznych zależności. Wewnątrz niej można używać funkcji</p>
<p><code class="docutils literal notranslate"><span class="pre">`</span>
<span class="pre">get_target(&lt;TEMPLATE_NAME&gt;</span> <span class="pre">&lt;INSTANCE_NAME&gt;</span> <span class="pre">[PATH</span> <span class="pre">&lt;PATH_TO_TARGETS.CMAKE&gt;]</span> <span class="pre">&lt;ARGS...&gt;)</span>
<span class="pre">`</span></code></p>
<p>## Co wolno, a czego nie wolno w funkcji generate_targets?</p>
<p>Funkcja służy do generowania jednego lub więcej targetów, każdy z nich zadeklarowany w ENUM_TEMPLATES. Funkcja dostaje w argumentach nazwy template, które ma stworzyć (nikt nie zabrania tworzyć ich więcej). Każdy template uważa się za stworzony, jeśli istnieje target o nazwie “${TEMPLATE_NAME}_${ARG_HASH}”. Funkcja używa zmiennej INSTANCE_NAME albo ${TEMPLATE_NAME}_INSTANCE_NAME, jeśli jest więcej niż jeden TEMPLATE zdefiniowany w funkcji.</p>
<p>Aby dodać dependency, należy użyć funkcji get_target(&lt;TEMPLATE_NAME&gt; &lt;VAR_INSTANCE_NAME&gt; [PATH &lt;PATH_TO_TARGETS.CMAKE&gt;] &lt;ARGS…&gt;) w ciele funkcji.</p>
<p>Wolno dokonywać dowolnych manipulacji na argumentach, które są przekazane jako zmienne (nie argumenty funkcji).
Wolno wywoływać inne funkcje CMake, poza generate_targets() i declare_dependencies().
Każde wywołanie <cite>get_target()</cite> przerwie konfigurację z błędem.</p>
<p>## Co wolno, a czego nie wolno w declare_dependencies?</p>
<p>Wolno wywoływać get_target(&lt;TEMPLATE_NAME&gt; &lt;VAR_INSTANCE_NAME&gt; [PATH &lt;PATH_TO_TARGETS.CMAKE&gt;] &lt;ARGS…&gt;)
Wolno wywoływać inne funkcje CMake, poza generate_targets() i declare_dependencies().
Każde wywołanie
<cite>add_executable</cite>, <cite>add_library</cite>, <cite>add_custom_target</cite> przerwie konfigurację z błędem.</p>
<p>## O czym należy pamiętać pisząc targets.cmake?</p>
<p>Plik będzie wykonywany przez CMake wiele raz, co najmniej 2, i to zarówno podczas etapu SuperBuild, jak i podczas etapu naszego projektu</p>
<hr class="docutils" />
<p>CMakeLists.txt zawiera wywołania do funkcji <cite>get_target(&lt;TEMPLATE_NAME&gt; &lt;VAR_INSTANCE_NAME&gt; [PATH &lt;PATH_TO_TARGETS.CMAKE&gt;] &lt;OPTS&gt;)</cite>,
albo <cite>build_target(&lt;TEMPLATE_NAME&gt; [PATH &lt;PATH_TO_TARGETS.CMAKE&gt;] &lt;OPTS&gt;)</cite> która jest uproszczoną wersją, która po prostu nie pozwala na uzyskanie nazwy targetu.</p>
<p>## Algorytm w Superbuild:</p>
<p>Sprawdza, czy TEMPLATE_NAME jest zadeklarowany w ENUM_TEMPLATES.</p>
<p>Ta funkcja wykonuje: (funkcja: _get_variables)</p>
<ol class="arabic simple">
<li>parsuje plik definiujący target (zawierający DEFINE_PARAMETERS z wartościami domyślnymi),</li>
<li>nadpisuje wartości domyślne wartościami z pamięci</li>
<li>i na końcu wartościami &lt;OPTS&gt;.</li>
<li>Następnie robi hash ze wszystkich tych opcji.</li>
</ol>
<p>Powtarza kroki 1-4 tak długo, aż hash przestanie się zmieniać lub max 10 razy i zwraca błąd, jeśli doszło do 10 razy.</p>
<p>Pamiętając, jak się nazywa definiowany TEMPLATE_NAME, wywołuje funkcję użytkownika <cite>declare_dependencies(TEMPLATE_NAME)</cite>, gdzie każde wywołanie get_target jest zapamiętywane i zbierane jako definicja ExternalProject lub ignorowane, jeśli dotyczy głównego projektu. W szczególności:
1. Definicja zależy od ustawionej zmiennej __SUPERBUILD
2. Dodajemy hash dependency do listy lokalnie wyszukiwanych dependency, służącej do wyłapania cyklicznego zapętlenia.
3. Na podstawie nazwy dependency znajdywany jest plik <cite>targets.cmake</cite>, parsowany i uzyskujemy zbiór argumentów. Na ich podstawie generujemy hash i sprawdzamy, czy mamy target o takim hashu. (Jeśli mamy, to sprawdzamy, czy nie został on już dodany w liście lokalnie wyszukiwanych dependency, aby wykluczyć cykliczne zapętlenie) go zwracamy i dodajemy do globalnej listy dependency, którą dodamy, gdy tylko dostaniemy definicję naszego projektu.
4. Jeśli targetu jeszcze nie ma i jest on zewnętrzny, to go tworzymy w poniższy sposób. W przeciwnym razie - ignorujemy go (na razie), jeśli target jest wewnętrzny, lub dodajemy jego <cite>INSTANCE_NAME</cite> do listy dependencies naszego targetu, który próbujemy stworzyć. &lt;jak odróżnić target zewnętrzny od lokalnego - poprzez obecność DEFINE_EXTERNAL_PROJECT&gt;
5. <em>Tworzenie targetu zewnętrznego, etap superbuild:</em></p>
<blockquote>
<div><ol class="arabic simple">
<li>(Przypomnienie: Jesteśmy tu, bo kod użytkownika w <cite>targets.cmake:declare_dependencies()</cite> wywołał nasz target (i wiemy że on jest zewnętrzny i go jeszcze nie ma). )</li>
</ol>
<p>2. Instancjonizujemy wszystkie <cite>INSTANCE_NAME</cite> zależności, jakie ten target może mieć. Upewniamy się, że żadna z zależności nie jest wewnętrzna (i zwracamy błąd, jeśli jest)
2. Tworzymy hash wszystkich argumentów, w standardowy sposób.
3. Na podstawie hasha tworzymy nazwę <cite>INSTANCE_NAME</cite> dla naszej dependency (np. Serialbox)
4. Wywołujemy <cite>ExternalProject_Add(${INSTANCE_NAME} …)</cite> tak, aby stworzył się obiekt naszych zależności. Dodajemy do DEPENDENCY wszystkie instancje targetów ew. zależności
5. Dopisujemy nazwę <cite>$INSTANCE_NAME</cite> do globalnej przestrzeni nazw. (funkcja: _store_target_instance)</p>
</div></blockquote>
<ol class="arabic simple" start="6">
<li>Tworzymy wywołanie ExternalProject_Add odwołujące się do wywołanego, najwyższego <cite>CMakeLists.txt</cite> i ustawiamy tam zmienną <cite>__SUPERBUILD:BOOL=0</cite> i dodając do dependency całą naszą listę dependency. Nie dodaje zmiennych - zmienne znajdzie sobie jeszcze raz.</li>
<li>Koniec</li>
</ol>
<p>## Algorytm w naszym projekcie (nie - superbuild):</p>
<ol class="arabic simple">
<li>Tak samo, jak w wywołaniu superbuild, parsuje każde odwołanie do build_target/get_target, które, jak zawsze, zaczyna się od ustalenia zbioru zmiennych (funkcja: _get_variables)</li>
<li>Również wywołuje funkcję użytkownika <cite>declare_dependencies(TEMPLATE_NAMES)</cite>, ale tym razem zbiera dependencies inaczej. Zewnętrzne dependencies są zbierane przy pomocy <cite>find_packages</cite>, natomiast wewnętrzne poprzez rekurencyjne budowanie ich, identycznie jak zewnętrzne były zbierane podczas kroku superbuild.</li>
<li>Wywołuję <cite>_call_generate_targets()</cite>.</li>
<li>Do każdego z <cite>INSTANCE_NAMES</cite> dodaję zależności zebrane w kroku 2.</li>
</ol>
<p>Zbiór funkcji:</p>
<p>Podczas wczytania biblioteki:
ustawiana jest zmienna globalna <cite>__GET_TARGET_BEHAVIOUR</cite> na “<cite>GLOBAL_SCOPE</cite>”.</p>
<p><cite>get_target(&lt;TEMPLATE_NAME&gt; [PATH &lt;Ścieżka do targets.cmake&gt;] &lt;Args…&gt;)</cite></p>
<ol class="arabic simple">
<li>Jeśli wartość zmiennej globalnej <cite>__GET_TARGET_BEHAVIOUR</cite> jest równa <cite>“INSIDE_GENERATE_TARGETS”</cite>. Jeśli tak - to zwracamy błąd, bo nie można naszej funkcji wywoływać wewnątrz <cite>generate_targets()</cite>. (Do tego celu należy użyć funkcję <cite>declare_dependencies()</cite>).</li>
<li>Próbujemy znaleźć ścieżkę do <cite>targets.cmake</cite> używając <cite>__find_targets_cmake_by_template_name($TEMPLATE_NAME __OUT_TARGETS_PATH)</cite></li>
</ol>
<p>3. Jeśli ścieżka nie jest znaleziona - zwraca błąd.
3. Tworzy listę zmiennych używając <cite>_get_variables(&lt;znaleziona ścieżka do targets.cmake&gt; __VARIABLE_DIC __TEMPLATES __EXTERNAL_PROJECT_INFO ${ARGS})</cite>
4. Upewnia się, że <cite>TEMPLATE_NAME</cite> jest zadeklarowany w <cite>ENUM_TEMPLATES</cite>.
5. Wywołuje <cite>_get_dependencies($TEMPLATE_NAME var_dictionary __INSTANCE_NAME_LIST)</cite>
6. Jeśli <cite>IS_EXTERNAL</cite>, to wywołuje <cite>_get_target_external(${TEMPLATE_NAME} __VARIABLE_DIC __INSTANCE_NAME ${__EXTERNAL_PROJECT_INFO})</cite>
7. Jeśli nie jest external, to <cite>_get_target_internal(${TEMPLATE_NAME} &lt;katalog zawierający targets.cmake&gt; __VARIABLE_DIC __INSTANCE_NAME)</cite>
8. Jeśli wywołanie <cite>_get_target_xxx</cite> się powiodło, to zwraca <cite>${__INSTANCE_NAME}</cite>, lub błąd w przeciwnym razie.</p>
<p><cite>_find_targets_cmake_by_template_name(&lt;TEMPLATE_NAME&gt; &lt;OUT_SCIEZKA&gt;)</cite></p>
<p>Próbuje znaleźć ścieżkę do pliku targets.cmake na podstawie <cite>TEMPLATE_NAME</cite>. Mechanizmu jeszcze nie jestem pewny.
Prawdopodobnie, użyjemy zewnętrznego targetu, który użyje CMake to obwąchania wszystkich plików <cite>.cmake</cite> w katalogu definiującym zewnętrzne targety oraz
wszystkie pliki <cite>targets.cmake</cite> w naszym źródle, stwoży listę tych plików, i zdefiniuje target zależny od tych plików, który stwoży bazę danych targetów w formie pliku <cite>template_paths.cmake</cite> z zawartością samych linijek
<a href="#id5"><span class="problematic" id="id6">``</span></a>`
set(__TEMPLATE_PATHS_${TEMPLATE_NAME} “${PATH}”)n
…</p>
<p><a href="#id7"><span class="problematic" id="id8">``</span></a><a href="#id9"><span class="problematic" id="id10">`</span></a></p>
<p>Ten plik będzie includowany przy pierwszym wykonaniu <cite>_find_targets_cmake_by_template_name</cite> zaraz po stworzeniu, zarówno przez SUPERBUILD jak i build wewnętrzny. Ta funkcja będzie też odpowiedzialna za stworzenie tego pliku używając zewnętrzne wywołanie CMake przy każdym pierwszym wywołaniu. Funkcja wpisze słownik do globalnej zmiennej.</p>
<p><cite>_get_variables(&lt;ścieżka do pliku targets.cmake&gt;, &lt;out_variables_dic&gt;, &lt;out_template_names&gt;, &lt;out_is_external&gt; &lt;Args…&gt;)</cite></p>
<p>Parsuje plikt targets.cmake i na podstawie Args…, zmiennych tam zadeklarowanych i zmiennych już istniejących w przestrzeni nazw, tworzy słownik wszystkich konkretnych wartości argumentów.</p>
<ol class="arabic simple" start="0">
<li>Ustawia hash parametrów jako ARGUMENT_HASH=”&lt;nothing&gt;” oraz COUNT=0</li>
<li><cite>_read_targets_file(&lt;ścieżka do pliku targets.cmake&gt; __READ_PREFIX)</cite> - parsuje plik definiujący target (zawierający <cite>DEFINE_PARAMETERS</cite> z wartościami domyślnymi),</li>
<li><cite>COUNT&lt;-COUNT+1</cite></li>
<li>nadpisuje wartości domyślne wartościami z pamięci (<cite>__read_variables_from_cache(“__READ_PREFIX_${DEFINE_PARAMETERS}” “” “” __OUT_CACHED_VALUES )</cite>)</li>
<li>i na końcu wartościami &lt;Args…&gt; (<cite>__read_variables_from_arg(“__READ_PREFIX_${DEFINE_PARAMETERS}” “${__OUT_CACHED_VALUES}” __OUT_FINAL_VALUES)</cite>).</li>
<li>Następnie robi hash ze wszystkich tych opcji i zapisuje go jako <cite>NEW_ARGUMENT_HASH</cite> (<cite>__calculate_hash(“__READ_PREFIX_${DEFINE_PARAMETERS}” “${__OUT_FINAL_VALUES}” __OUT_VAR_DIC)</cite>)</li>
<li>Jeśli <cite>NEW_ARGUMENT_HASH</cite> != <cite>ARGUMENT_HASH</cite> &amp;&amp; <cite>COUNT &lt; 10</cite> THEN a) <cite>ARGUMENT_HASH &lt;- NEW_ARGUMENT_HASH</cite> i powtarza kroki 1-5. (czyli tak długo, aż hash przestanie się zmieniać lub max 10 razy i zwraca błąd, jeśli doszło do 10 razy.</li>
<li>Jeśli <cite>COUNT == 10</cite> THEN błąd.</li>
<li>Zapisuje aktualny słownik zmiennych do <cite>OUT_VARIABLES_DIC</cite>. Poza tym, wpisuje <cite>OUT_TEMPLATE_NAMES</cite> i <cite>OUT_IS_EXTERNAL</cite></li>
<li>Koniec.</li>
</ol>
<p><cite>_get_target_internal(&lt;TEMPLATE_NAME&gt; &lt;path&gt; &lt;var_dictionary&gt; &lt;out_instance_name&gt;)</cite></p>
<ol class="arabic simple" start="2">
<li>Jeśli etap SUPERBUILD: robi NIC (zwraca pusty string)</li>
<li><cite>_instantiate_variables(0 var_dictionary)</cite></li>
<li>Tworzy zmienne o nazwach <cite>${TEMPLATE_NAME}_TARGET_NAME</cite>, które przechowują oczekiwane nazwy targetów danego <cite>TEMPLATE_NAME</cite>.</li>
<li>Upewnia się, że flaga <cite>__GATHERING_DEPENDENCIES</cite> jest wyzerowana.</li>
</ol>
<p>6. Modyfikuje <cite>CMAKE_CURRENT_SOURCE_DIR</cite>, aby wskazywała na katalog, w którym jest wywoływany <cite>targets.cmake</cite> (tj. <cite>path</cite>).
6. Wywołuje funkcję użytkownika <cite>generate_targets(TEMPLATE_NAME)</cite>. Wewnątrz tej funkcji każde wywołanie <cite>get_target()</cite> zwraca błąd z uwagi na wyzerowanie <cite>__GATHERING_DEPENDENCIES</cite>.
7. Sprawdza, czy targety, które chcieliśmy uzyskać, faktycznie są stworzone (<cite>if(TARGET ${TEMPLATE_NAME}_TARGET_NAME)…</cite>). Jeśli nie - zwraca błąd.
8. Zwraca nazwę instance targetu, który chcieliśmy uzyskać.</p>
<p><cite>_get_target_external(&lt;TEMPLATE_NAME&gt; &lt;var_dictionary&gt; &lt;out_instance_name&gt; &lt;EXTERNAL_PROJECT_ARGS&gt;)</cite></p>
<ol class="arabic simple" start="2">
<li>Jeśli etap SUPERBUILD - Wywołuje <cite>ExternalProject_Add</cite> dla nazwy targetu policzonej na <cite>var_dictionary</cite> i zwraca tą nazwę targetu w <cite>out_instance_name</cite></li>
<li>Jeśli etap naszego projektu - wywołuje <cite>find_packages</cite>, tworzy alias dla importowanego targetu i zwraca nazwę <cite>INSTANCE_NAME</cite>.</li>
</ol>
<p><cite>_read_targets_file(&lt;ścieżka do pliku targets.cmake&gt; &lt;out_prefix&gt;)</cite></p>
<p>Wczytuje plik <cite>targets.cmake</cite> i zwraca <cite>DEFINE_PARAMETERS</cite>, <cite>DEFINE_EXTERNAL_PROJECT</cite> i <cite>ENUM_TEMPLATES</cite> poprzedzone prefiksem.</p>
<p><cite>_read_variables_from_cache(&lt;PARAMETERS_PREFIX&gt; &lt;ARGUMENTS_PREFIX&gt; &lt;VALUES_PREFIX&gt;|”” &lt;OUT_PREFIX&gt;)</cite></p>
<p>Korzysta ze zmiennych wczytanych z <cite>targets.cmake</cite> i podanych poprzez jeden argument <cite>DEFINED_PARAMETERS</cite>. Iteruje się po nich i dla każdej z nich:
1. Pobiera wartość i zapisuje w pamięci pod <cite>__RC_&lt;VARIABLE_NAME&gt;</cite> oraz dodaje jej nazwę do <cite>RC__LIST</cite>
2. Jeśli zmienna <cite>${PREFIX}${VARIABLE_NAME}</cite> jest w pamięci, to dla niej wywołuje <cite>_verify_parameter(${VARIABLE_NAME} ${VARIABLE_CONTAINER} ${VARIABLE_TYPE} )</cite> i wpisuje ją do pamięci. W przeciwnym razie:
3. …jeśli <cite>EXISTING_VALUES_PREFIX</cite> jest niezerowe, to sprawdza, czy zmienna czy zmienna jest tam, i jeśli jest, to wpisuje ją do pamięci.
4. Zapisuje wartość do <cite>PARENT_SCOPE</cite> używając prefiksu <cite>__OUT_CACHED_VALUES</cite>.
5. Na końcu, po zakończeniu pętli, wpisuje listę wszystkich zmiennych do <cite>${__OUT_CACHED_VALUES}__LIST</cite>.</p>
<p>Efektywnie format zmiennych to:</p>
<p><cite>PREFIX__LIST</cite> - lista zmiennych
<cite>PREFIX_&lt;var name&gt;</cite> - wartość zmiennej</p>
<p><cite>__read_variables_from_args(&lt;PARAMETERS_PREFIX&gt; &lt;ARGUMENTS_PREFIX&gt; &lt;OUT_PREFIX&gt; &lt;ARGS…&gt;)</cite></p>
<ol class="arabic simple">
<li>Parsuje ARGS korzystając z definicji wczytanej z <cite>DEFINED_PARAMETERS</cite> i zapisuje je prefiksowane <cite>__RV</cite>.</li>
<li>Uruchamia <cite>__read_variables_from_cache(“${DEFINED_PARAMETERS}” __RV ${CURRENT_VALUES_PREFIX} __RA )</cite></li>
<li><cite>_pass_variables_higher(__RA __RA)</cite></li>
</ol>
<p><cite>__calculate_hash(&lt;PREFIX&gt; &lt;__OUT_HASH&gt; &lt;EXTRA_STRING&gt;)</cite></p>
<ol class="arabic simple">
<li>Sortuje wszystkie zmienne w liście <cite>${PREFIX}__LIST</cite></li>
<li>Tworzy pustą zmienną stringową z zawartością <cite>${EXTRA_STRING}</cite></li>
<li>Iteruje się po kolejnych elementach tej listy i dodaje wartość do listy</li>
<li>Liczy hash tej zmiennej tekstowej</li>
<li>Zwraca hash z prefiksem <cite>__OUT_PREFIX</cite>.</li>
</ol>
<p><cite>_pass_variables_higher(&lt;IN_PREFIX&gt; &lt;OUT_PREFIX&gt;)</cite></p>
<p>Makro, które iteruje się po wszystkich zmiennych w <cite>${IN_PREFIX}__LIST</cite> i każdą z wartości zapisuje w <cite>PARENT_SCOPE</cite> z prefiksem <cite>OUT_PREFIX</cite>. Na koniec eksportuje <cite>${IN_PREFIX}__LIST</cite> jako <cite>${OUT_PREFIX}__LIST</cite> w <cite>PARENT_SCOPE</cite></p>
<p><cite>_store_target_instance(&lt;template_name&gt; &lt;hash&gt; &lt;instance_name&gt; &lt;path_to_targets&gt;?)</cite>
Zapisuje target &lt;instance_name&gt; do globalnej pamięci</p>
<p><cite>_exists_target_instance(&lt;template_name&gt; &lt;var_dictionary_prefix&gt; &lt;out_target_exists&gt;)</cite></p>
<p>Sprawdza, czy o takiej nazwie i zmiennych już istnieje</p>
<p><cite>_name_target_instance(&lt;template_name&gt; &lt;var_dictionary_prefix&gt; &lt;out_instance_name&gt;)</cite></p>
<p>Funkcja nazywa instance_name na podstawie zmiennych var_dictionary_prefix i zapisuje nazwę do zmiennej &lt;out_instance_name&gt;</p>
<p><cite>_instantiate_variables(FLAG_PARENT var_dictionary)</cite></p>
<p>Makro przejeżdża się po słowniku <cite>var_dictionary</cite> i każdą napotkaną tam zmienną wpisuje do bierzącego scope, albo - jeśli <cite>FLAG_PARENT</cite> - do <cite>PARENT_SCOPE</cite>.</p>
<p><cite>_get_dependencies(&lt;TEMPLATE_NAME&gt; &lt;var_dictionary&gt; &lt;out_dependencies_target_list&gt;)</cite></p>
<p>Funkcja zbiera wszystkie zależności danego targetu i zwraca listę <a href="#id11"><span class="problematic" id="id12">`</span></a>INSTANCE_NAME`s.</p>
<ol class="arabic simple">
<li>Zapisuje flagę <cite>__GET_TARGET_BEHAVIOUR</cite> na “<cite>GATHERING_DEPENDENCIES</cite>”, która jest odczytywana przez funkcję <cite>get_target()</cite> i modyfikuje zachownie tej funkcji.</li>
<li><cite>_instantiate_variables(0 var_dictionary)</cite></li>
</ol>
<p>3. Dodaje hash z TEMPLATE_NAME i var_dictionary
3. Wywołuje funkcję użytkownika <cite>declare_dependencies(TEMPLATE_NAME)</cite>, która tworzy zależności używając <cite>get_target()</cite>
4. Zbiera ze stosu listę znalezionych dependencies i dodaje je do listy <cite>out_dependencies_target_list</cite></p>
<p><cite>_verify_parameter(&lt;VARIABLE_NAME&gt; &lt;VARIABLE_CONTEXT&gt; &lt;VARIABLE_CONTAINER&gt; &lt;VARIABLE_TYPE&gt; &lt;VARIABLE_VALUE&gt;)</cite></p>
<p>Weryfikuje parametr o wartości <cite>VARIABLE_VALUE</cite> (przekazaną przez wartość, a nie typ). Sprawdza, czy zgadza się kontener, oraz czy każdy element w kontenerze (jeśli wektor) ma typ
kompatybilny z zadeklarowanym.
<cite>VARIABLE_NAME</cite> i <cite>VARIABLE_CONTEXT</cite> przekazywane jest tylko dla produkowania ładnych komunikatów błędu.</p>
<hr class="docutils" />
<ul class="simple">
<li>Podczas fazy SUPERBUILD zwraca nazwę targetu zewnętrznego projektu wskazywanego przez TEMPLATE_NAME i słownika zmiennych i ignoruje wewnętrzne targety.</li>
<li>Podczas fazy wewnętrznej, zwraca INSTANCE_NAME dla targetu zewnętrznego (używając find_packages i pojęcia imported targets) i wewnętrznego.</li>
</ul>
<p><em>UWAGA!!</em> Funkcja zakłada, że aktualne definicje funkcji <cite>generate_targets()</cite> oraz <cite>declare_dependencies()</cite> są zgodne z plikiem, z którego wczytano <cite>var_dictionary</cite>.</p>
<p>Pamiętając, jak się nazywa definiowany TEMPLATE_NAME, wywołuje funkcję użytkownika <cite>declare_dependencies(TEMPLATE_NAME)</cite>, gdzie każde wywołanie get_target jest zapamiętywane i zbierane jako definicja ExternalProject lub ignorowane, jeśli dotyczy głównego projektu. W szczególności:
1. Definicja zależy od ustawionej zmiennej __SUPERBUILD
2. Dodajemy hash dependency do listy lokalnie wyszukiwanych dependency, służącej do wyłapania cyklicznego zapętlenia.
3. Na podstawie nazwy dependency znajdywany jest plik <cite>targets.cmake</cite>, parsowany i uzyskujemy zbiór argumentów. Na ich podstawie generujemy hash i sprawdzamy, czy mamy target o takim hashu. (Jeśli mamy, to sprawdzamy, czy nie został on już dodany w liście lokalnie wyszukiwanych dependency, aby wykluczyć cykliczne zapętlenie) go zwracamy i dodajemy do globalnej listy dependency, którą dodamy, gdy tylko dostaniemy definicję naszego projektu.
4. Jeśli targetu jeszcze nie ma i jest on zewnętrzny, to go tworzymy w poniższy sposób. W przeciwnym razie - ignorujemy go (na razie), jeśli target jest wewnętrzny, lub dodajemy jego <cite>INSTANCE_NAME</cite> do listy dependencies naszego targetu, który próbujemy stworzyć. &lt;jak odróżnić target zewnętrzny od lokalnego - poprzez obecność DEFINE_EXTERNAL_PROJECT&gt;
5. <em>Tworzenie targetu zewnętrznego, etap superbuild:</em></p>
<blockquote>
<div><ol class="arabic simple">
<li>(Przypomnienie: Jesteśmy tu, bo kod użytkownika w <cite>targets.cmake:declare_dependencies()</cite> wywołał nasz target (i wiemy że on jest zewnętrzny i go jeszcze nie ma). )</li>
</ol>
<p>2. Instancjonizujemy wszystkie <cite>INSTANCE_NAME</cite> zależności, jakie ten target może mieć. Upewniamy się, że żadna z zależności nie jest wewnętrzna (i zwracamy błąd, jeśli jest)
2. Tworzymy hash wszystkich argumentów, w standardowy sposób.
3. Na podstawie hasha tworzymy nazwę <cite>INSTANCE_NAME</cite> dla naszej dependency (np. Serialbox)
4. Wywołujemy <cite>ExternalProject_Add(${INSTANCE_NAME} …)</cite> tak, aby stworzył się obiekt naszych zależności. Dodajemy do DEPENDENCY wszystkie instancje targetów ew. zależności
5. Dopisujemy nazwę <cite>$INSTANCE_NAME</cite> do globalnej przestrzeni nazw. (funkcja: _store_target_instance)</p>
</div></blockquote>
<ol class="arabic simple" start="6">
<li>Tworzymy wywołanie ExternalProject_Add odwołujące się do wywołanego, najwyższego <cite>CMakeLists.txt</cite> i ustawiamy tam zmienną <cite>__SUPERBUILD:BOOL=0</cite> i dodając do dependency całą naszą listę dependency. Nie dodaje zmiennych - zmienne znajdzie sobie jeszcze raz.</li>
<li>Koniec</li>
</ol>
<p><cite>_call_generate_targets(&lt;ścieżka do pliku targets.cmake&gt; &lt;TEMPLATE_NAMES&gt; &lt;var_dictionary&gt; &lt;out_instance_name&gt;)</cite></p>
<p>Wywołuje funkcję <cite>generate_targets()</cite> dostarczoną przez użytkownika dla zadanego słownika zmiennych i nazw targetów. Po wywołaniu sprawdza, czy rzeczywiście targety zostały zdefiniowane.</p>


          </div>
          
        </div>
      </div>
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
<h1 class="logo"><a href="index.html">The Beetroot Project</a></h1>








<h3>Navigation</h3>
<p class="caption"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="about.html">Steps to start using the Beetroot:</a></li>
<li class="toctree-l1"><a class="reference internal" href="about.html#how-does-the-beetroot-work">How does the Beetroot work?</a></li>
<li class="toctree-l1"><a class="reference internal" href="features.html">List of most important and complex Beetroot functionalities</a></li>
<li class="toctree-l1"><a class="reference internal" href="features.html#list-of-the-most-visible-features-of-the-beetroot">List of the most visible features of the Beetroot</a></li>
<li class="toctree-l1"><a class="reference internal" href="start.html">Getting started</a></li>
</ul>

<div class="relations">
<h3>Related Topics</h3>
<ul>
  <li><a href="index.html">Documentation overview</a><ul>
  </ul></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
  <h3>Quick search</h3>
    <div class="searchformwrapper">
    <form class="search" action="search.html" method="get">
      <input type="text" name="q" />
      <input type="submit" value="Go" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    </div>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>








        </div>
      </div>
      <div class="clearer"></div>
    </div>
    <div class="footer">
      &copy;2019, Adam Ryczkowski.
      
      |
      Powered by <a href="http://sphinx-doc.org/">Sphinx 1.7.6</a>
      &amp; <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
      
      |
      <a href="_sources/readme.rst.txt"
          rel="nofollow">Page source</a>
    </div>

    

    
  </body>
</html>

About

Compiled version of static html documentation

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published