Installation nur eines Ziels (und seiner Abhängigkeiten) aus einem komplexen Projekt mit cmake (offen für bessere Lösungen)

Angenommen, ich habe ein Projekt aus mehreren Teilprojekten A, B, C, D ...Alle Teilprojekte hängen von A ab, was sich ziemlich häufig ändert. Außerdem kann es einige weitere Abhängigkeiten geben: In diesem BeispielD hängt von B ab.

Jetzt arbeiten viele Leute an diesen Projekten. Die Hauptdatei CMakeLists.txt sollte alle Verzeichnisse enthalten, damit der Build all alles erstellt. Aber die Leute möchten auch nur an einem dieser Projekte arbeiten können und nicht jedes Mal alles bauen / installieren müssen.

Wenn ich an D arbeite, kann ich einfach "nur" D erstellen, indem ich aufrufe

cmake --build . --target D -- -j7

oder

ninja -j7 D

Dies wird auch A und B bauen, wenn sich etwas für sie geändert hat. Perfekt.

Aber wie kann ich install nur für D aufrufen, ohne build all auszulösen? Das würde mir gefallen, wenn ich anrufe:

ninja -j7 D install

Es wurde nur D (und Abhängigkeiten) erstellt und dann nur D installiertund seine Abhängigkeiten (A und B). Stattdessen wird das Ziel all erstellt und all installiert.

Ich möchte behalten, dass das Ziel alle alles weiter aufbaut. EXCLUDE_FROM_ALL wäre also keine Option. Aber in diese Richtung konnte ich keine Lösung finden.

Ich überlege mir also folgende Strategie:

Mit Ausnahme von Teilprojekt A werden alle anderen Ziele bei der Installation auf EXCLUDE_FROM_ALL und OPTIONAL gesetzt.Ich füge ein zusätzliches Unterprojekt hinzu, das einfach von allen anderen Unterprojekten abhängt (vielleicht lasse ich jedes Ziel seinen Namen veröffentlichen, indem ich eine unter PARENT_SCOPE festgelegte Variable verwende), und die Leute müssen das aufrufen, wenn sie alles erstellen und installieren wollen.

Wird es funktionieren? Gibt es eine bessere Lösung?

Wir möchten vermeiden, dass jeder die Hauptdatei CMakeLists.txt bearbeiten muss, um Projekte auszuschließen, die ihn nicht interessieren. Die Lösung sollte auf verschiedene Betriebssysteme portierbar sein.

Bearbeiten:

Ich habe die von mir vorgeschlagene Strategie ausprobiert, aber sie hat nicht funktioniert: In meinem Fall wird EXCLUDE_FROM_ALL unwirksam, wenn eine install-Anweisung für ein Ziel angegeben wird (auch wenn sie als OPTIONAL angegeben ist). Besser lesen in derDokumentation Ich habe herausgefunden, dass:

Installing a target with EXCLUDE_FROM_ALL set to true has undefined behavior.

Ich bekomme auch diese Warnung:

Target <targetname> has EXCLUDE_FROM_ALL set and will not be built by default but an install rule has been provided for it.  CMake does not define behavior for this case.

Bearbeiten 2:

Ich habe versucht, EXCLUDE_FROM_ALL als Option für das Unterverzeichnis add_subdirectory (anstelle von add_library / add_executable) anzugeben, aber dann scheinen alle Installationsanweisungen in diesen Unterverzeichnissen ignoriert zu werden: Es werden nur Installationsanweisungen in Unterverzeichnissen installiert, die nicht von allen ausgeschlossen sind.

Edit 3:

Auch wenn ich aktiviereCMAKE_SKIP_INSTALL_ALL_DEPENDENCY:

set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true)

Setzen Sie in der Hauptdatei CMakeLists.txt, und lassen Sie EXCLUDE_FROM_ALL weg, die Installation beliebig vieler Ziele (in meinem Fall alle bis auf A) und, falls die Erstellung bestimmter Ziele der Installation vorausgeht, den Befehl:

ninja -j7 D && ninja install

Aus irgendeinem Grund schlägt die Angabe fehl, dass C (dessen Installation auf OPTIONAL gesetzt wurde) nicht vorhanden ist (es wurde nicht erstellt, weil D nur von A und B abhing) ...

file INSTALL cannot find "<name of dll file for C>"

Bearbeiten 4:

Es sieht für mich aus wie ein Wanze. (Ich benutze 2.8.11 unter Windows, habe auch 2.8.10 getestet) Dieser INSTALL Befehl

install(TARGETS ${targetname} RUNTIME DESTINATION . LIBRARY DESTINATION . OPTIONAL)

wird in der cmake_install.cmake konvertiert als:

IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified")   

DATEI (INSTALLIEREN SIE ZIEL "$ {CMAKE_INSTALL_PREFIX} /." TYP SHARED_LIBRARY DATEIEN * path_to_dll *)

IF (EXISTS "$ ENV {DESTDIR} $ {CMAKE_INSTALL_PREFIX} /./" UND NICHT IS_SYMLINK "$ ENV {DESTDIR} $ {CMAKE_INSTALL_PREFIX} /./* dll_name *")

IF(CMAKE_INSTALL_DO_STRIP)

  EXECUTE_PROCESS(COMMAND "C:/Programs/MinGW/bin/strip.exe" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/./*dll_name*")

ENDIF(CMAKE_INSTALL_DO_STRIP)   ENDIF() ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified")

mit dem Befehl DATEI fehlt OPTIONAL! Wenn ich OPTIONAL manuell hinzufüge, funktioniert es! (Anmerkung: Ich habe hier bearbeitet, um * dll_name * und * path_to_dll * Platzhalter zu setzen)

Edit 5:

Ich bestätige, dass es ein Fehler von cmake oder zumindest eine falsche Dokumentation ist. Ich werde das melden. Die Situation löste sich entweder einfacher

install(TARGETS ${targetname} DESTINATION . OPTIONAL)

(In meinem Fall werden jedoch auch .lib.a-Dateien installiert, die ich nicht möchte.)

oder vor die OPTIONAL-Flagge bewegen:

install(TARGETS ${targetname} OPTIONAL RUNTIME DESTINATION . LIBRARY DESTINATION .)

Was versteht man von derDokumentation erstellen ist, dass OPTIONAL als letzte Option gesetzt werden sollte.

Antworten auf die Frage(4)

Ihre Antwort auf die Frage