2017-03-23 22 views
5

Mamy wiele repozytoriów Git, niektóre zawierają nasz własny kod, a niektóre zawierają nieco zmodyfikowany kod biblioteki strony trzeciej. Uproszczony wykres zależność wygląda następująco:Jak radzić sobie z przejściowym konfliktem zależności za pomocą modułów podrzędnych Git i CMake?

executable_A 
    |  | 
    |  v 
    | library_B 
    |  | 
    v  v 
    library_C 

Więc wykonywalny ma dwie współzależności na library_C jeden bezpośredni i jeden przechodni. Mam nadzieję związać to wszystko razem za pomocą submodules Git i CMake, więc uproszczona struktura katalogów wygląda następująco:

executable_A/ 
    CMakeListst.txt 
    library_B/ 
    CMakeLists.txt 
    library_C/ 
     CMakeLists.txt 
    library_C/ 
    CMakeLists.txt 

Jak widać, repozytorium library_C jest włączone jako modułem dwukrotnie. Załóżmy, że oba submoduły wskazują na ten sam commit (wszelkie pomysły na egzekwowanie, które byłyby mile widziane, ale nie są tematem tego pytania).

Używamy add_subdirectory, target_link_libraries i target_include_directories do zarządzania tymi współzależnościami. Całkiem standardowe.

Problemem jest to, że CUpewnij nie lubi go, jeśli utworzyć cel o tej samej nazwie dwa razy, tak narzeka:

CUpewnij Błąd w library_C/CMakeLists.txt: 13 (add_library):
add_library nie można utworzyć obiektu docelowego "library_C", ponieważ inny obiekt docelowy o tej samej nazwie już istnieje. Istniejącym celem jest statyczna biblioteka utworzona w katalogu źródłowym ".../library_B/library_C".
Zobacz dokumentację zasad CMP0002, aby uzyskać więcej informacji.

Wolałbym nie usunąć bezpośrednią zależność executable_A na library_C, ponieważ fakt, że jest wciągany przez library_B jest szczegółowo realizacja library_B że nie powinno się powoływać. Co więcej, takie podejście zostanie przerwane, gdy tylko dodamy kolejną zależność, taką jak executable_A --> library_D --> library_C.

(This question jest najbliżej udało mi się znaleźć, ale jest nieco bardziej ogólny i pozostaje bez odpowiedzi i tak.)

+0

Dzięki. Mój mózg zrobił tam zły ruch. Edytowane. – Thomas

+1

Powszechnym podejściem jest sprawdzenie, czy istnieje jakiś cel specyficzny dla projektu ('if (TARGET library_C)') przed wkroczeniem do projektu za pomocą 'add_subdirectory()'. – Tsyvarev

+0

@Tsyvarev 'if (NOT TARGET library_c)', oczywiście.Brzmi jak realistyczne podejście. Chcesz umieścić go jako odpowiedź? – Thomas

Odpowiedz

2

Najprostszy wzór dla pojedynczego włączenia podprojektu jest sprawdzanie istnienia cel jakiegoś podprojektem za:

if(NOT TARGET library_C) 
    add_subdirectory(library_C) 
endif() 

(Tutaj cel i podprojekt mają tę samą nazwę, ale ogólnie nazwy docelowe i podprojektu mogą się różnić.)

Po takim warunkowym włączeniu wszystkie cele i funkcje podprojektu będą następujące: natychmiast dostępny dla osoby dzwoniącej z gwarancją.

Lepiej używać tego wzoru we wszystkich miejscach (w executable_A i library_B). Taki sposób zmiany kolejności library_B i library_C w executable_A nie łamie poprawności.