Ich bin neu in der Bash-Programmierung. Ich möchte mein C++-Programm in einer Bash-Datei aufrufen.
Mein Programm ist myProg.cpp
:
#include<iostream>
using namespace std;
int main()
{
cout<<"Salam! World"<<endl;
return 0;
}
Und meine Bash-Datei ist myBash.sh
. Wie kann ich mein obiges .cpp-Programm in der Datei aufrufen myBash.sh
?
Antwort1
Sie müssen es zuerst kompilieren: Ändern Sie zuerst das aktuelle Arbeitsverzeichnis des Terminals in den Pfad Ihrer Quelldatei:
cd <path_to_cpp_file>/
Kompilieren Sie dann die Quelldatei:
g++ myProg.cpp -o myProg
Anschließend können Sie die kompilierte ausführbare Datei aus Ihrem bash
Skript wie folgt aufrufen:
#!/bin/bash
# ...
<path_to_compiled_executable>/myProg
# ...
Antwort2
Da Ihrwahres ZielEs scheint darin zu bestehen, alles zu automatisieren, was zur Ausführung Ihres Programms getan werden muss. Ich schlage einen anderen Ansatz vor.Anstatt ein Shell-Skript zu schreiben, können Sie einMake-Datei.Wenn Sie möchten, können Sie in Ihr Makefile eine Regel für die Ausführung Ihrer ausführbaren Datei schreiben, sobald diese erstellt ist. Sie haben dann zwei Dateien – Ihre C++-Quellcodedatei und Ihr Makefile – und können einen einzigen Befehl effizient ausführen:
- Erstellt oder erstellt Ihr C++-Programm neu,genau dann, wenn es nötig ist.
- Führt Ihr Programm aus.
Die folgenden Abschnitte dieses Beitrags erklären, warum Sie eine .cpp
Datei nicht direkt aufrufen können (sondern zuerst eine ausführbare Datei daraus erstellen müssen); wie Sie sie installieren make
, wie Sie sie verwenden und was sie im Hintergrund tut; und wie Sie häufige Fehler vermeiden. Aber falls Sie erst einmal ein Gefühl dafür bekommen möchten, wie dieser Ansatz aussieht, bevor Sie sich damit befassen, werden Sie make run
nach dem Einfügen dieses0In Makefile
:
all: myProg
run: all
./myProg
Mir gefällt das für diesen Zweck besser als ein Shell-Skript und ich denke, Ihnen geht es vielleicht genauso.
Hintergrund
Anders als einigegedolmetschte SprachenWie Python und Bash ist C++ einkompilierte Sprache.1In C++ geschriebene Programme müssengebautbevor sie ausgeführt werden. (Building wird manchmal auchKompilieren, obwohlKompilierenbezieht sich genauer auf einen der Schritte des Erstellens.) Sie können kein C++QuellcodeDatei; es muss stattdessen kompiliert werden inObjektcode2, in diesem FallMaschinensprache. Die Objektdateien müssen dann miteinander verknüpft werden, und selbst wenn es nur eine gibt, muss sie dennoch mit allengemeinsam genutzte Bibliothekenes verwendet. Durch Verknüpfen entsteht einausführbardie ausgeführt werden können.
Kurz gesagt, Sie müssen Ihr Programm erstellen, bevor Sie es ausführen.das erste MalVor nachfolgenden Läufen muss es nichtReerstellt, es sei denn, Sie haben den Quellcode geändert. In diesem Fall müssen Sie es erneut erstellen, wenn Ihre Änderungen im ausgeführten Programm berücksichtigt werden sollen.Das make
Dienstprogrammist speziell für solche Situationen konzipiert, in denen man Aktionen ausführen möchtebedingtabhängig davon, ob und wann sie bereits erledigt wurden.
Bekommenmake
Möglicherweise ist der make
Befehl bereits installiert. Führen Sie ihn aus, um dies herauszufinden. Wenn er installiert ist, wird Folgendes angezeigt:
$ make
make: *** No targets specified and no makefile found. Stop.
Um make zu erhalten, können Sie diemachen Paket, aber ich schlage vor, zu installierenBuild-Essential das eine Reihe weiterer praktischer Tools bietet. (Vielleicht haben SieBuild-Essential um zu erhalten g++
. Dies ist eine Möglichkeit, wie Sie möglicherweise bereits haben make
.) Sie können es über das Software Center installieren oder den folgenden Befehl ausführen:
sudo apt-get update && sudo apt-get install build-essential
make
Ohne Makefile
Um zu sehen, wie make
es funktioniert, schlage ich vor, es zuerst ohne Makefile auszuführen und ihm den Basisnamen Ihrer Quellcodedatei zu übergeben:
$ make myProg
g++ myProg.cpp -o myProg
$ ./myProg
Salam! World
Vergleicht bei nachfolgenden Ausführungen make
die Änderungszeitstempel (mZeits) auf den Eingabe- und Ausgabedateien und erstellt Ihr Programm nicht unnötig neu:
$ make myProg
make: 'myProg' is up to date.
Wenn Sie ändern myProg.cpp
, wird der Änderungszeitstempel aktualisiert, sodass make
Sie wissen, dass die Datei neu erstellt werden muss. (Sie können den Zeitstempel einer Datei auch mit demtouch
Befehl, wenn Sie den Neuaufbau von davon abhängigen Ausgabedateien erzwingen müssen oder wollen. Und natürlich stellt das Löschen der Ausgabedateien auch sicher, dass sie beim Ausführen neu aufgebaut werden make
– löschen Sie nur nicht die falsche Datei!)
$ touch myProg.cpp
$ make myProg
g++ myProg.cpp -o myProg
Woher make
weiß ich, was zu tun ist, wenn ich laufe make myProg
?
- Das
myProg
Argument zumake
heißt aZiel. - Ziele sind oft, aber nicht immer, die Namen der zu erstellenden Dateien. Ziele können explizit in einem Makefile definiert werden.
- Wenn in der Make-Datei kein Ziel definiert ist oder (wie in diesem Fall) keine Make-Datei vorhanden ist,
make
wird nach Eingabedateien (d. h. Quellcodedateien) gesucht, deren Namen darauf schließen lassen, dass sie zum Erstellen des Ziels bestimmt sind. make
leitet aus der Endung einer Datei (in diesem Fall ) ab, welches Dienstprogramm und welche Syntax zum Erstellen einer Datei zu verwenden sind.cpp
.
All dies kann angepasst werden, aber in einfachen Fällen wie diesem ist das oft nicht nötig.
Erstellen eines Makefiles zum Automatisieren des Erstellens und Ausführens Ihres Programms
Um komplexere Aufgaben als das Erstellen eines Programms aus einer einzelnen Quellcodedatei zu automatisieren, z. B. wenn mehrere Eingabedateien vorhanden sind oder (was für Ihre unmittelbaren Anforderungen eher zutrifft) Aktionen, die Sie neben der Ausführung des Compilers ausführen möchten, können Sie ein Makefile erstellen, um Ziele zu definieren make
und anzugeben, wie diese von anderen Zielen abhängen.
Das erste in einem Makefile definierte Ziel ist das Standardziel: Es wird make
versucht, es zu erstellen, wenn es ohne Befehlszeilenargumente ausgeführt wird (d. h., wenn Sie nur make
und nicht etwas wie ausführen make myProg
).
Normalerweise verwendet man Makefiles, indem man ein Verzeichnis erstellt, das alle Quellcodedateien (und alle anderen Dateien) enthält, die zum Erstellen des Programms verwendet werden, sowie das Makefile, das normalerweise heißt Makefile
. Unter diesem Namen make
wird es automatisch gefunden.
Um ein Makefile zu erstellen, können Sie es ausführen myProg
und es wird bei Bedarf automatisch zuerst erstellt. Legen Sie es myProg.cpp
in ein neues, ansonsten leeres Verzeichnis. Erstellen Sie in diesem Verzeichnis eine weitere Textdatei mit dem Namen Makefile
.
Sie können hierfür jeden beliebigen Texteditor verwenden, aber das Rezept für eine Regel - die darunter aufgelisteten Befehle, die ausgeführt werden, um das Ziel zu erreichen - muss eingerückt werden mitRegisterkartenstattRäume.3Wenn Ihr Texteditor derzeit so konfiguriert ist, dass beim Drücken von die Einrückung mit Leerzeichen erfolgt Tab, sollten Sie dies ändern.
In Gedit oder Pluma würden Sie beispielsweise Folgendes eingeben:Bearbeiten > Voreinstellungen, drücke denEditorund stellen Sie sicher,Leerzeichen statt Tabulatoren einfügenist nicht aktiviert:
Viele Editoren verwenden standardmäßig Tabulatoren und keine Leerzeichen zum Einrücken. Wenn Sie diese Einstellung also vorher nicht geändert haben, ist sie für Makefiles möglicherweise bereits richtig eingestellt.
Wenn Sie in Ihrem Editor sind und ihn (falls nötig) für die Einrückung mit Tabulatoren konfiguriert haben, geben Sie Folgendes ein:
all: myProg
run: all
./myProg
Wenn Sie dies kopieren und einfügen, wird es falsch seinweil Leerzeichen eingefügt werden, obwohl Ihr Texteditor sie beim Drücken von nicht erstellt Tab. (Das hängt mit der Art und Weise zusammen, wie Ask Ubuntu Code anzeigt.) Sie können aber einfach die vier vorangehenden Leerzeichen entfernen ./myProg
und drücken, Tabum an ihrer Stelle einen Tabulator zu erstellen.
Einige Texteditoren zeigen einen Tabulator standardmäßig als 8 Leerzeichen oder eine andere Zahl an. Das ist in Ordnung.
Was dieses Makefile macht und wie man es benutzt
Verwenden Sie den Befehl:
make
, um das Programm zu erstellen, sofern es nicht bereits erstellt ist und die ausführbare Datei dem Quellcode entspricht.Oder,make run
, um das Programm auszuführen,Bauen Sie es ggf. zuerst(d. h. wenn keine aktuelle ausführbare Datei vorhanden ist).
Dieses Makefile definiert zwei Ziele: all
und run
.
Das
all
Ziel hat kein eigenes Rezept, sondern hängt vommyProg
Ziel ab. Dieses Ziel ist nicht explizit definiert, daher weist es implizit an,make
den BuildmyProg
aus den Quellcodedateien zu versuchen, die im aktuellen Verzeichnis dafür verfügbar sind. (Siehe diemake
Ohne MakefileWeitere Einzelheiten finden Sie im Abschnitt oben.)Da
all
das erste in explizit definierte Ziel istMakefile
, wird es erstellt, wennmake
aus dem Verzeichnis ausgeführt wird, in demMakefile
es sich befindet. Daher haben wir alles so eingerichtet, dass dasmake
alleinige Ausführen dem Ausführen von entsprichtmake all
.Das
run
Ziel führt das Programm aus. Das Rezept besteht aus dem Befehl, der dies tut./myProg
.run
deklariert dasall
Ziel als Abhängigkeit. Dadurch wird beim Ausführen neu erstelltmake run
,myProg
wenn die aktuellemyProg
ausführbare Datei nicht aktuell ist (oder noch nicht existiert).Wir hätten genauso gut
run
depend onmyProg
statt on machen könnenall
, aber wir hätten trotzdem das expliziteall
Ziel (oder ein gleichwertiges Ziel mit einem anderen Namen) benötigt, um zu verhindern,run
dass es das Standardziel ist. Wenn Sie möchten, dass Ihr Programm erstellt wird,und Rennselbst wenn Siemake
alleine laufen, könnten Sie dies tun.Ein weiterer Vorteil der Zielabhängigkeit
all
besteht darin, dass später weitere Aktionen ausgeführt werden müssen, bevor Ihr Programm ausgeführt werden soll. Sie können der Regel dann ein Rezept für hinzufügenall
.
Die Verwendung des Makefiles zum Ausführen des Programms sieht folgendermaßen aus, wenn es erstellt werden muss:
$ cd myProg/
$ make run
g++ myProg.cpp -o myProg
./myProg
Salam! World
Oder dies, wenn es nicht gebaut werden muss:
$ make run
./myProg
Salam! World
Und wenn Sie nur sicherstellen möchten, dass das Programm erstellt wurde (seit der letzten Änderung der Quellcodedatei)ohne das Programm auszuführen, führen Sie es einfach make
ohne Argumente aus:
$ make # Here, I run make and myProg isn't current.
g++ myProg.cpp -o myProg
$ make # Running "make" again after "make" or "make run" does nothing.
make: Nothing to be done for 'all'.
( make myProg
wird auch weiterhin funktionieren.)
Eine Verfeinerung: Benutzerdefinierte Compiler-Flags
make
ist ein extrem leistungsfähiges Werkzeug, das für einfache Zwecke wie diesen praktisch ist, sich aber auch für große, komplexe Projekte eignet. Der Versuch, alle Funktionen im Detail zu beschreiben, make
würde ein ganzes Buch füllen (insbesondereDieses hier).
Aber mir ist aufgefallen, dass Sie vielleicht Warnungen vom Compiler sehen möchten, wenn etwas den Abschluss des Builds nicht verhindert, aber dennoch ein potenzieller Fehler vorliegt. Diese werden zwar nicht alle Fehler in den von Ihnen geschriebenen Programmen aufdecken, aber sie könnten viele davon aufdecken.
Wenn Sie GCC verwenden (wie bei dem g++
Befehl), empfehle ich, zumindest -Wall
an den Compiler zu übergeben. Dies ermöglicht eigentlich nichtalleWarnungen, aber den Großteil der übrigen können Sie mit aktivieren -Wextra
. Manchmal möchten Sie vielleicht auch -pedantic
. (Sieheman gcc
Und3.8Optionen zum Anfordern oder Unterdrücken von WarnungenimGCC-Referenzhandbuch.)
Um diese Flags manuell aufzurufen g++
, führen Sie Folgendes aus:
g++ -Wall -Wextra -pedantic -o myProg myProg.cpp
Um make
den C++-Compiler ( g++
) mit den Flags -Wall
, -Wextra
, und aufzurufen -pedantic
, fügen Sie CXXFLAGS=
oben von eine Zeile mit ihnen hinzu Makefile
.
CXXFLAGS=-Wall -Wextra -pedantic
all: myProg
run: all
./myProg
Auch wenn myProg
noch vorhanden und neuer als ist myProg.cpp
, wird das Programm beim Ausführen make
oder make run
nach der Bearbeitung Makefile
trotzdem erneut erstellt, da Makefile
jetzt neuer als ist myProg
. Das ist gut, denn:
- In diesem Fall werden Ihnen beim Neuerstellen der ausführbaren Datei Warnungen angezeigt, sofern welche vorhanden sind (bei diesem bestimmten Programm sollte dies nicht der Fall sein).
- Allgemeiner gesagt: Manchmal bearbeiten Sie ein Makefile, weil Sie möchten, dass unterschiedliche Dateien erstellt werden oder dass diese unterschiedliche Inhalte haben. (Wenn Sie beispielsweise das
-O3
Flag für umfangreiche Optimierungen oder-g
zum Generieren von Debugsymbolen durch den Compiler hinzugefügt hätten,myProg
wäre die resultierende ausführbare Datei anders.)
Weitere Informationen
- Übung 2: Machen Sie jetzt Ihr PythonInLerne C auf die harte TourvonZed Shaw.
- DerGNU Make-Handbuch, besonders2.1Wie eine Regel aussieht.
- Ein einfaches Makefile-TutorialvonBruce A. Maxwell, für Informationen zu anderen Verwendungsmöglichkeiten
make
. - "Verwendung von Makefiles" (S. 15) und "Makefiles vs. Shell-Skripte" (S. 62) in21. Jahrhundert CvonBen Klemens. Die Seitenzahlen beziehen sich auf die Erstausgabe. (Die zweite Ausgabe ist wahrscheinlich besser, aber ich habe nur die Erstausgabe.)
Anmerkungen
0: Ich empfehle, weiterzulesen, um zu erfahren, wie das funktioniert. Aber falls Sie es zuerst selbst versuchen möchten: Sie müssen Zeilen mit Tabulatoren statt mit Leerzeichen einrücken.
1: Streng genommen könnte praktisch jede Programmiersprache entweder interpretiert oder kompiliert werden, je nachdem, wasImplementierungendafür wurden geschrieben. Für einige Sprachen gibt es sowohl Interpreter als auch Compiler. Interpretiertes C++ ist jedoch ungewöhnlich - obwohlnicht unbekannt.
2: Gebäude aufteilen inKompilierenUndVerlinkungund Aufruf der Übersetzung einer C++-Quellcodedatei (.cc/.cpp/.cxx/.C) in ObjektcodeKompilieren, ist nicht die ganze Geschichte. Programme in C und C++ (und einigen anderen Sprachen) sind zunächstvorverarbeitet. In Ihrem ProgrammC-Präprozessorersetzt #include<iostream>
durch den Inhalt der <iostream>
Header-Datei, bevor die eigentliche Kompilierung beginnt. Und im engsten Sinne wandelt die Kompilierung den Quellcode inAssemblersprachestatt Objektcode. Viele Compiler (wie GCC/ g++
) können Kompilierung und Assembly in einem einzigen Schritt kombinieren und erzeugen keinen Assemblercode, wenn sie nicht dazu aufgefordert werden.
Während die Vorverarbeitung ein separater Schritt ist, führen GCC und andere Compiler den Präprozessor automatisch aus. Ebenso können sie den Linker automatisch ausführen, weshalb die gesamte Sequenz vonVorverarbeitung,Zusammenstellung,Montage, UndVerknüpfungwird manchmal als "Kompilieren" statt als "Erstellen" bezeichnet. (Beachten Sie auch, dass das Erstellen mehr als diese Schritte umfassen kann - es kann beispielsweise das Generieren von Ressourcendateien, das Ausführen vonein Skript zur Konfiguration der Erstellung, usw.)
3: Sie müssen nur im Makefile selbst mit Tabulatoren einrücken. Die Verwendung eines Makefiles stellt keine Anforderungen an die Art und Weise, wie Sie Ihre C++-Quellcodedateien selbst schreiben. Sie können die Einrückung jederzeit wieder von Tabulatoren auf Leerzeichen umstellen, wenn Sie an anderen Dateien arbeiten. (Und wenn SieWirklichWenn Sie Einrückungen mit Tabulatoren in einem Makefile nicht mögen, können Sie die.RECIPEPREFIX
spezielle Variable.)
Antwort3
Hier ist ein Beispiel: von myBash.sh
#!/bin/sh
g++ myProg.cpp -o myProg
./myProg