Hinzufügen mehrerer ausführbarer Dateien in CMake


70

Mein Code in einem C ++ - Projekt ist wie folgt organisiert

  • Ich habe mehrere .cppund .hDateien, die meine Klassen enthalten
  • Ich habe mehrere .cxxDateien, die gegen die .cppDateien und einige externe Bibliotheken kompiliert werden müssen .

Jetzt hat jede der .cxxDateien eine main()Methode, daher muss ich für jede dieser Dateien eine andere ausführbare Datei hinzufügen, die denselben Namen wie die Datei hat.

Außerdem werden diese .cxxDateien möglicherweise nicht mit denselben externen Bibliotheken verknüpft.

Ich möchte diesen Build in CMake schreiben, in dem ich eine Art Neuling bin. Wie gehe ich vor?

Antworten:


107

Mein Vorschlag ist, dies in zwei Phasen anzugehen:

  1. Erstellen Sie eine Bibliothek aus den .cppund .hDateien, mitadd_library
  2. Durchlaufen Sie alle Ihre .cxxDateien und erstellen Sie aus jeder eine ausführbare Datei mit add_executableundforeach

Erstellen Sie die Bibliothek

Dies könnte so einfach sein wie

file( GLOB LIB_SOURCES lib/*.cpp )
file( GLOB LIB_HEADERS lib/*.h )
add_library( YourLib ${LIB_SOURCES} ${LIB_HEADERS} )

Erstellen Sie alle ausführbaren Dateien

Durchlaufen Sie einfach alle CPP-Dateien und erstellen Sie separate ausführbare Dateien.

# If necessary, use the RELATIVE flag, otherwise each source file may be listed 
# with full pathname. RELATIVE may makes it easier to extract an executable name
# automatically.
# file( GLOB APP_SOURCES RELATIVE app/*.cxx )
file( GLOB APP_SOURCES app/*.cxx )
foreach( testsourcefile ${APP_SOURCES} )
    # I used a simple string replace, to cut off .cpp.
    string( REPLACE ".cpp" "" testname ${testsourcefile} )
    add_executable( ${testname} ${testsourcefile} )
    # Make sure YourLib is linked to each app
    target_link_libraries( ${testname} YourLib )
endforeach( testsourcefile ${APP_SOURCES} )

Einige Warnungen:

  • file( GLOB )wird normalerweise nicht empfohlen, da CMake nicht automatisch neu erstellt wird, wenn eine neue Datei hinzugefügt wird. Ich habe es hier verwendet, weil ich Ihre Quelldateien nicht kenne.
  • In einigen Situationen können Quelldateien mit einem vollständigen Pfadnamen gefunden werden. Verwenden Sie gegebenenfalls das Flag RELATIVE fürfind( GLOB ... ) .
  • Das manuelle Festlegen der Quelldateien erfordert eine Änderung an CMakeLists.txt, die eine Neuerstellung auslöst. In dieser Frage finden Sie die (Nachteile) des Globbing.
  • Ich habe den Testnamen mit a generiert string( REPLACE ... ). Ich hätte get_filename_component mit dem NAME_WEFlag verwenden können.

In Bezug auf "allgemeine" CMake-Informationen empfehle ich Ihnen, einige der allgemeinen "CMake-Übersicht" -Fragen zu lesen, die hier bereits zum Stackoverflow gestellt wurden. Z.B:


+1 nette Antwort. Werden die ausführbaren Dateien alle in dasselbe build/Verzeichnis der obersten Ebene integriert , oder wird dies die Verzeichnisstruktur des zugrunde liegenden Quellbaums berücksichtigen? siehe auch diese Frage
TemplateRex

Ich habe es nicht getestet, gehe aber davon aus, dass es ausführbare Dateien in einer Verzeichnisstruktur ähnlich dem Quellverzeichnis erzeugt. Schamloser Stecker: Schauen Sie unter stackoverflow.com/questions/13556885 nach, wie Sie die Ausgabepfade ändern können ...
André

3
Wenn Sie einen neueren cmake verwenden (3.0.2 ist der früheste, den ich gefunden habe), können Sie den Dateinamen mithilfe von get_filename_component(testname ${testsourcefile} NAME_WE)anstelle von verwenden string(REPLACE.... Der Vorteil ist, dass dadurch auch der Rest des Pfads entfernt wird. Dies ist praktisch, wenn Sie EXECUTABLE_OUTPUT_PATHfestlegen möchten, wohin Binärdateien verschoben werden sollen.
Alex

@ André was ist die Alternative, um diefile( GLOB APP_SOURCES app/*.cxx )
ywiyogo

1
Ich musste einiges ändern, bevor ich es benutzte. Meine Konfiguration ist wie folgt:file( GLOB APP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) foreach( sourcefile ${APP_SOURCES} ) file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${sourcefile}) string( REPLACE ".cpp" "" file ${filename} ) add_executable( ${file} ${sourcefile} ) target_link_libraries( ${file} ndn-cxx boost_system ) endforeach( sourcefile ${APP_SOURCES} )
Rafee

0

Dies CMakeLists.txtfunktioniert für mein OpenCV-Projekt,
vorausgesetzt, die *.cppDateien befinden sich im selben Verzeichnis wieCMakeLists.txt

cmake_minimum_required(VERSION 3.5)

project(opencv LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(OpenCV REQUIRED)
include_directories( ${OpenCV_INCLUDE_DIRS} )

file( GLOB APP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp )
foreach( sourcefile ${APP_SOURCES} )
    file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${sourcefile})
    string( REPLACE ".cpp" "" file ${filename} )
    add_executable( ${file} ${sourcefile} )
    target_link_libraries( ${file} ${OpenCV_LIBS} )
endforeach( sourcefile ${APP_SOURCES} )

0

Ich befinde mich in einer ähnlichen Situation, wenn ich ein OpenGL-Projekt mit mehreren Beispieldateien organisiere, wobei jede dieser Dateien eine Hauptmethode enthält.

Die folgenden Einstellungen generieren eine separate ausführbare Datei pro c / cpp-Datei und kopieren die erforderlichen Abhängigkeiten in den Ziel-Bin-Ordner.

Ordnerstruktur

my-project
│── ch01_01.c
│── ch02_01.cpp
│── CMakeLists.txt
│── Resources
│   │── Libraries
│   │   │── glew
│   │   │   │── bin
│   │   │   │── include
│   │   │   │── lib
│   │   │── glfw    
│   │   │   │── include 
│   │   │   │── lib 

CMakeLists.txt

cmake_minimum_required (VERSION 3.9)

project ("my-project")

include_directories(Resources/Libraries/glew/include
                    Resources/Libraries/glfw/include)

link_directories(Resources/Libraries/glew/lib
                 Resources/Libraries/glfw/lib)

link_libraries(opengl32.lib
               glew32.lib
               glfw3.lib)

set(CMAKE_EXE_LINKER_FLAGS "/NODEFAULTLIB:MSVCRT")

file(GLOB SOURCE_FILES *.c *.cpp)

foreach(SOURCE_PATH ${SOURCE_FILES})

    get_filename_component(EXECUTABLE_NAME ${SOURCE_PATH} NAME_WE)

    add_executable(${EXECUTABLE_NAME} ${SOURCE_PATH})

    # Copy required DLLs to the target folder
    add_custom_command(TARGET ${EXECUTABLE_NAME} POST_BUILD
                       COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/Resources/Libraries/glew/bin/glew32.dll" 
                                                                     "${CMAKE_BINARY_DIR}/glew32.dll")

endforeach(SOURCE_PATH ${SOURCE_FILES})

Optionale Schritte

In Visual Studio

  • Öffnen Sie das Projekt mit der Option "Lokalen Ordner öffnen" im Startfenster

  • Wenn Sie eine neue Datei hinzufügen, können Sie entweder:

    • Brechen Sie den Dialog ab, in dem Sie automatisch gefragt werden add_executable zu CMakeLists.txt zu wechseln
    • Deaktivieren Sie dieses Verhalten, indem Sie das Kontrollkästchen "Automatische CMake-Skriptänderung für Dateivorgänge in der Ordneransicht aktivieren" in deaktivieren Tools > Options > CMake

Da neu hinzugefügte Dateien nicht automatisch erfasst werden, da CMakeLists.txt niemals geändert wird, generieren Sie den Cache einfach wie folgt neu:

  • Project > CMake Cache (x64-Debug) > Delete Cache
  • Project > Generate Cache for my-project

Jetzt können Sie einfach mit der rechten Maustaste auf eine bestimmte c / cpp-Datei klicken und Set as Startup Itemsie mit debuggen F5.

Umgebung

  • cmake Version 3.18.20081302-MSVC_2
  • Microsoft Visual Studio Community 2019 Version 16.8.3
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.