Der Befehlszeilencompiler von C# 2.0
Veröffentlicht: 14. Feb 2005
Von Andrew W. Troelsen
Dieser Artikel beschreibt die Erstellung von Anwendungen mithilfe des Befehlszeilencompilers csc.exe von C#. Dabei wird eine Reihe von Compileroptionen speziell für C# 2.0 vorgestellt, beispielsweise das erweiterte Flag /reference und die Unterstützung für starke Namen. Am Ende werden Sie in der Lage sein, in einer Umgebung ohne Assistenten Einzeldatei- und Mehrfachdatei-Assemblys zu erstellen. Dieser Artikel enthält auch Links zu englischsprachigen Seiten. (30 gedruckte Seiten)
Hinweis In diesem Artikel wird vorausgesetzt, dass Sie mit der Programmiersprache C# und den Mechanismen von .NET Framework vertraut sind. Erfahrungen im Umgang mit Befehlszeilentools sind ebenfalls sehr hilfreich.
Downloaden Sie die Datei CSCSample.msi (in Englisch).
Auf dieser Seite
Die Annehmlichkeiten von csc.exe
Ein erster Blick auf die Optionen des C#-Compilers
Konfigurieren der Umgebungsvariablen
Grundlagen der Befehlszeile
Optionen für die Eingabe und die Steuerung der Ausgabe
Kompilieren einer .NET-Codebibliothek
Arbeiten mit C#-Antwortdateien
Referenzieren externer Assemblys mithilfe von "/reference"
Verstehen der Referenz-Aliase von C# 2.0
Erstellen einer Mehrfachdateiassembly mithilfe von "/addmodule"
Erstellen einer Windows Forms-Anwendung
Arbeiten mit Ressourcen unter Verwendung von csc.exe
Definieren von "Präprozessor"-Symbolen mithilfe von "/define"
Debugorientierte Optionen von csc.exe
Zum Abschluss einige selten verwendete Optionen
Schlussbemerkung
Die Annehmlichkeiten von csc.exe
Nur wenige Entwickler bestreiten, dass integrierte Entwicklungsumgebungen (IDEs) wie Visual Studio 2005 und Visual C# Express 2005 zahlreiche Features bieten, die die Programmierung erheblich vereinfachen. Tatsache ist jedoch, dass IDEs allein oftmals nicht den Zugriff auf alle Möglichkeiten des zugrunde liegenden Compilers bieten. Visual Studio 2005 unterstützt zum Beispiel nicht die Erzeugung von Mehrfachdatei-Assemblys.
Das Verständnis vom Prozess der Codekompilierung auf Befehlszeilenebene kann zudem für Entwickler nützlich sein, die:
einen minimalistischen Ansatz bei der Erstellung von .NET Framework-Anwendungen bevorzugen.
eine Entmystifizierung der Vorgänge wünschen, die bei der Verarbeitung von Quellcode durch IDEs stattfinden.
.NET-Dienstprogramme für die Erstellung wie NAnt (in Englisch) oder MSBuild (in Englisch) einsetzen möchten.
keine integrierte Entwicklungsumgebung wie Visual Studio besitzen, jedoch über das frei erhältliche .NET Framework SDK verfügen.
auf Unix-basierten Systemen (hier gilt die Befehlszeile als Standard) mit dem .NET Framework arbeiten und die ECMA-konformen C#-Compiler Mono (in Englisch) und/oder Portable.NET (in Englisch) besser verstehen möchten.
alternative .NET-Programmiersprachen (in Englisch) erforschen, die derzeit nicht in Visual Studio integriert sind.
einfach nur ihre Kenntnisse der Programmiersprache C# erweitern möchten.
Wenn Sie diese Gründe ansprechen, lesen Sie weiter!
Ein erster Blick auf die Optionen des C#-Compilers
Der C#-Compiler csc.exe stellt zahlreiche Optionen zur Verfügung, die die Erstellung von .NET-Assemblys steuern. Allgemein betrachtet kann eine Befehlszeilenoption einer von acht Kategorien zugeordnet werden (Tabelle 1).
Tabelle 1: Kategorien von Flags, die von csc.exe zur Verfügung gestellt werden
Kategorie des C#-Compilers |
Definition |
---|---|
Ausgabedateien |
Optionen, die das Format erzeugter Assemblys, optionaler XML-Dateien zur Dokumentation und von Informationen über starke Namen steuern. |
Eingabedateien |
Optionen, die die Angabe von Eingabedateien und referenzierten Assemblys ermöglichen. |
Ressourcen |
Optionen, die zur Einbettung erforderlicher Ressourcen wie Symbolen und Zeichenfolgentabellen verwendet werden. |
Codeerzeugung |
Diese Optionen steuern die Erzeugung von Debugsymbolen. |
Fehler und Warnungen |
Optionen, die den Umgang des Compilers mit Quellcodefehlern bzw. -warnungen steuern. |
Sprache |
Aktiviert/Deaktiviert C#-Sprachfeatures (wie unsicheren Code) ebenso, wie die Definition bedingter Kompiliersymbole. |
Verschiedene |
Die interessanteste Option dieser Kategorie ermöglicht die Angabe einer Antwortdatei für csc.exe. |
Erweitert |
Zu dieser Kategorie zählen einige eher esoterische, oft weniger bedeutende Compileroptionen. |
Hinweis
Das Flag /incremental aus den Versionen 1.0 und 1.1 des C#-Compilers gilt als veraltet.
Im Zuge dieses Artikels lernen Sie die Hauptflags jeder einzelnen Compilerkategorie kennen (die Betonung liegt hier auf Haupt). Viele der erweiterten Optionen des C#-Compilers können für die meisten Entwicklungsszenarios getrost ignoriert werden. Wenn Sie ausführlichere Informationen über Features von csc.exe benötigen, die in diesem Artikel nicht behandelt werden, seien Sie versichert, dass diese im Microsoft Visual Studio 2005 Documentation Help-System dokumentiert sind (suchen Sie einfach nach csc.exe auf der Registerkarte für die Suche).
Hinweis Die MSDN-Dokumentation ist auch für die Einstellungen spezieller Optionen von csc.exe innerhalb von Visual Studio (wenn verfügbar) hilfreich, da diese darin beschrieben werden.
Konfigurieren der Umgebungsvariablen
Bevor Sie ein .NET SDK-Befehlszeilentool verwenden können, einschließlich des C#-Compilers, müssen Sie zuerst Ihren Entwicklungscomputer konfigurieren, damit er dessen Anwesenheit erkennt. Die einfachste Vorgehensweise besteht darin, die vorkonfigurierte Visual Studio-Eingabeaufforderung über Start | Programme | Visual Studio 2005 | Visual Studio Tools zu starten. Diese spezielle Konsole initialisiert automatisch die nötigen Umgebungsvariablen ohne Anstrengungen Ihrerseits. (Visual Studio .NET 2003-Benutzer starten die entsprechende Eingabeaufforderung.)
Hinweis
Wenn Sie keine Version von Visual Studio besitzen, jedoch das .NET Framework SDK installiert haben, können Sie die vorkonfigurierte Eingabeaufforderung über Start | Programme | Microsoft .NET Framework SDK 2.0 starten.
Wenn Sie .NET-Befehlszeilentools von jeder beliebigen Eingabeaufforderung aus einsetzen möchten, müssen Sie die Variable Path auf Ihrem Computer manuell aktualisieren. Dazu klicken Sie mit der rechten Maustaste auf das Symbol Arbeitsplatz auf Ihrem Desktop und wählen die Menüoption Eigenschaften aus. Klicken Sie in dem daraufhin angezeigten Dialogfeld auf der Registerkarte Erweitert auf die Schaltfläche Umgebungsvariablen. Fügen Sie in dem angezeigten Dialogfeld folgende Verzeichnisangaben am Ende der derzeit vorhandenen Variable Path an, die Sie im Listenfeld Systemvariablen finden (beachten Sie, dass die einzelnen Einträge durch ein Semikolon voneinander getrennt werden):
C:\Windows\Microsoft.NET\Framework\v2.0.40607 C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin
Hinweis Die obigen Angaben verweisen auf Pfade meiner aktuellen Beta-Version von .NET 2.0. Ihre Pfade können je nach der Installation und Version von Visual Studio und/oder vom .NET SDK davon abweichen, überprüfen Sie also sicherheitshalber Ihre Einstellungen.
Schließen Sie zur Bestätigung der Einstellungen alle Dialogfelder und derzeit geöffnete Konsolenfenster, sobald Sie die Variable Path aktualisiert haben. Jetzt sollte die Ausführung von csc.exe und anderer .NET-Tools von jeder Eingabeaufforderung aus möglich sein. Geben Sie zum Testen folgende Befehle ein:
csc -? ildasm -?
Wenn eine Menge Informationen angezeigt werden, haben Sie es richtig gemacht.
Grundlagen der Befehlszeile
Wer in der Arbeit mit der Befehlszeile bereits geübt ist, wird keine Probleme mit der Steuerung von csc.exe haben und kann sich mit dem nächsten Abschnitt beschäftigen. Wenn Sie allerdings die Befehlszeile nur wenig verwendet haben, möchte ich Ihnen einige grundlegende Einzelheiten erklären, um eine gemeinsame Ebene zu schaffen.
Die Optionen von csc.exe können entweder mit einem Schrägstrich oder einem Gedankenstrich angegeben werden. Es ist unzulässig, Leerzeichen zwischen / oder – und dem daran anschließenden Flag einzugeben. Dem entsprechend ist -help korrekt, - help jedoch falsch. Um dies zu erläutern, sei mithilfe des Flags help der gesamte Satz von Befehlszeilenoptionen überprüft.
csc –help csc /help
Wenn alles in Ordnung ist, sollten Sie alle möglichen Flags sehen können, wie in Abbildung 1 dargestellt.
Abbildung 1: Hilfe zu Flags
Viele Optionen können in Kurzform angegeben werden, so dass Sie bei der Eingabe Zeit sparen. Wenn die Kurzform für das Flag help das Zeichen ? ist, können Sie die Optionen von csc.exe folgendermaßen anzeigen:
csc –? csc /?
Viele Optionen erfordern zusätzliche Angaben wie Verzeichnispfade und Dateinamen. Bei Flags dieser Art wird ein Doppelpunkt verwendet, um die Zusatzangaben vom Flag zu trennen. Die Option /reference zum Beispiel benötigt den Namen der .NET-Assembly, die in das Assembly-Manifest aufgenommen werden soll:
csc /reference:MyLibrary.dll ...
Andere Flags sind binärer Natur, da sie entweder aktiviert (+) oder deaktiviert (-) werden. Binäre Flags sind in der Standardeinstellung immer deaktiviert, so dass Sie normalerweise nur das Pluszeichen verwenden. Um beispielsweise alle Kompilierwarnungen als Fehler zu behandeln, aktivieren Sie das Flag warnaserror:
csc /warnaserror+ ...
Die Reihenfolge der Flags spielt keine Rolle, bevor jedoch die Eingabedateien angegeben werden, müssen alle Flags angegeben werden. Wichtig ist ebenfalls, dass es unzulässig ist, Leerzeichen zwischen Trennzeichen und zugehörigen Daten einzufügen. Zum Beispiel /reference:MyLibrary.dll, nicht /reference: MyLibrary.dll.
Optionen für die Eingabe und die Steuerung der Ausgabe
Der erste Satz von Befehlszeilenoptionen, der untersucht werden soll, wird verwendet, um die Eingaben für den Compiler (Tabelle 2) anzugeben und die sich ergebende Ausgabe zu steuern (Tabelle 3). Beachten Sie, dass in der folgenden Tabelle auch C# 2.0-spezifische Optionen und die verfügbaren Abkürzungen gekennzeichnet sind.
Tabelle 2: Eingabeorientierte Optionen von csc.exe
Eingabeflags |
Definition |
Spezifisch für C# 2.0? |
---|---|---|
/recurse |
Veranlasst csc.exe, C#-Dateien zu kompilieren, die sich in Unterverzeichnissen eines Projekts befinden. Dieses Flag unterstützt Platzhalter. |
Nein |
/reference (/r) |
Wird zur Angabe externer Assemblys verwendet, die beim aktuellen Kompiliervorgang referenziert werden sollen. |
Nein, der C# 2.0-Compiler stellt jedoch eine Aliasvariante zur Verfügung. |
/addmodule |
Wird zur Angabe der Module verwendet, die in eine Mehrfachdateiassembly einbezogen werden sollen. |
Nein |
Tabelle 3: Ausgabeorientierte Optionen von csc.exe
Ausgabeflags |
Definition |
Spezifisch für C# 2.0? |
---|---|---|
/out |
Gibt den Namen für die zu erzeugende Assembly an. Wird dieses Flag weggelassen, wird dem Namen der Ausgabedatei der Name der ersten Eingabedatei (bei DLL-Assemblys) oder der Klasse zugrunde gelegt, die die Methode Main() definiert (bei EXE-Assemblys). |
Nein |
/target (/t) |
Gibt das Dateiformat der zu erzeugenden Assembly an. |
Nein |
/doc |
Wird zur Erzeugung von XML-Dokumentationsdateien verwendet. |
Nein |
/delaysign |
Ermöglicht das Erstellen einer Assembly unter Verwendung von verzögerter Signierung des starken Namens. |
Ja |
/keyfile |
Gibt den Pfad zur SNK-Datei an, die verwendet wird, um die Assembly mit einem starken Namen zu versehen. |
Ja |
/keycontainer |
Gibt den Namen des Containers an, der die SNK-Dateien enthält. |
Ja |
/platform |
Gibt die CPU an, die zum Hosten der Assembly benötigt wird (x86, Itanium, x64, anycpu). Die Standardeinstellung ist anycpu. |
Ja |
Die vielleicht vielseitigste der Eingabe-/Ausgabeoptionen ist /target. Dieses Flag gibt mithilfe einer Zusatzangabe (Tabelle 4) vor, welcher Typ von .NET-Assembly erzeugt werden soll.
Tabelle 4: Varianten des Flags "/target"
Zusatzangabe |
Definition |
---|---|
/target:exe |
Erzeugt eine konsolenbasierte Assembly. Dies ist die Standardeinstellung, wenn keine Option für /target angegeben wird. |
/target:winexe |
Erzeugt eine ausführbare, auf Windows Forms basierende Assembly. Obwohl Sie mit der Option /target:exe eine Windows Forms-Anwendung erstellen können, wird im Hintergrund Ihres Hauptfensters ein Konsolenfenster angezeigt. |
/target:library |
Wird zum Erstellen einer .NET-Codebibliothek (DLL-Datei) verwendet. |
/target:module |
Erzeugt ein Modul, das Teil einer Mehrfachdatei-Assembly wird. |
Kompilieren einer .NET-Codebibliothek
Um die Arbeit mit den Ein- und Ausgabeoptionen von csc.exe zu veranschaulichen, wird eine mit starkem Namen versehene Einzeldatei-Assembly ( MyCodeLibrary.dll) erstellt, die einen Klassentyp mit dem Namen SimpleType definiert. Um darzustellen, welche Rolle die Option /doc spielt, wird zusätzlich eine XML-Dokumentationsdatei erzeugt.
Erstellen Sie zunächst auf dem Laufwerk C einen Ordner mit dem Namen MyCSharpCode. Erstellen Sie in diesem Ordner ein Unterverzeichnis mit dem Namen MyCodeLibrary. Verwenden Sie einen Texteditor Ihrer Wahl (Notepad.exe ist durchaus geeignet), geben Sie folgenden Code ein, und speichern Sie die Datei unter dem Namen simpleType.cs im zuvor erstellten Verzeichnis C:\MyCSharpCode\MyCodeLibrary.
// simpleType.cs using System; namespace MyCodeLibrary { /// <summary> /// Simple utility type. /// </summary> public class SimpleType { /// <summary> /// Print out select environment information /// </summary> public static void DisplayEnvironment() { Console.WriteLine("Location of this program: {0}", Environment.CurrentDirectory); Console.WriteLine("Name of machine: {0}", Environment.MachineName); Console.WriteLine("OS of machine: {0}", Environment.OSVersion); Console.WriteLine("Version of .NET: {0}", Environment.Version); } } }
Öffnen Sie eine Eingabeaufforderung und navigieren Sie mithilfe des Befehls cd (change directory – wechsle Verzeichnis) zur Datei simpleType.cs (C:\MyCSharpCode\MyCodeLibrary):
cd MyCSharpCode\MyCodeLibrary
Oder
cd C:\MyCSharpCode\MyCodeLibrary
Geben Sie folgende Befehlszeichenfolge ein, um diese Quellcodedatei in eine Einzeldatei-Assembly mit dem Namen MyCodeLibrary.dll zu kompilieren:
csc /t:library /out:MyCodeLibrary.dll simpleType.cs
Zu diesem Zeitpunkt sollte sich eine neue .NET-Codebibliothek in Ihrem Anwendungsverzeichnis befinden, wie es in Abbildung 2 dargestellt wird.
Abbildung 2: Ihre neue .NET-Codebibliothek
Wenn Sie mehrere C#-Dateien in der Befehlszeile kompilieren möchten, können Sie jede Datei einzeln aufführen. Dies kann hilfreich sein, wenn Sie eine Untermenge von C#-Dateien kompilieren möchten, die sich in einem Verzeichnis befinden. Stellen Sie sich vor, es wäre eine weitere C#-Codedatei (die im gleichen Verzeichnis gespeichert wurde) mit dem Namen asmInfo.cs erstellt worden, die zur Beschreibung der Codebibliothek folgende Attribute auf Assemblyebene definiert:
// asmInfo.cs using System; using System.Reflection; // A few assembly level attributes. [assembly:AssemblyVersion("1.0.0.0")] [assembly:AssemblyDescription("Just an example library")] [assembly:AssemblyCompany("Intertech Training")]
Um die Dateien simpleType.cs und asmInfo.cs zu kompilieren, geben Sie Folgendes ein:
csc /t:library /out:MyCodeLibrary.dll simpleType.cs asmInfo.cs
Wie Sie wahrscheinlich hoffen, unterstützt csc.exe Platzhalter. Daher können Sie als Eingabeoption einfach *.cs angeben, um alle Dateien in einem einzelnen Verzeichnis zu kompilieren.
csc /t:library /out:MyCodeLibrary.dll *.cs
Angeben von Unterverzeichnissen mithilfe der Option "/recurse"
Sicherlich bevorzugen Sie bei der Erstellung von Anwendungen die Erzeugung einer logischen Verzeichnisstruktur für Ihr Projekt. Anstatt 25 C#-Dateien in einem einzigen Verzeichnis mit der Bezeichnung MeineAnwendung abzulegen, könnten Sie Ihre Codedateien in speziellen Unterverzeichnissen organisieren (\Core, \AsmInfo, \MenuSystem usw.). Da das vorliegende Beispiel nur aus einigen wenigen Dateien besteht, stellen Sie sich vor, Sie hätten die Datei asmInfo.cs in einem neuen Unterverzeichnis \AsmInfo abgelegt (siehe Abbildung 3).
Abbildung 3: Neues Unterverzeichnis \AsmInfo****
Verwenden Sie die Option /recurse, um den C#-Compiler anzuweisen, sowohl alle im Stammverzeichnis wie auch im Unterverzeichnis AsmInfo abgelegten Dateien zu kompilieren:
csc /t:library /out:MyCodeLibrary.dll /recurse:AsmInfo /doc:myDoc.xml *.cs
In diesem Fall wurde /recurse mit dem Namen eines speziellen Unterverzeichnisses erweitert. Zur Angabe mehrerer Unterverzeichnisse können wiederum Platzhalter verwendet werden. Wenn die Datei simpleType.cs in ein neues Unterverzeichnis namens Core verschoben werden müsste, könnten alle C#-Dateien in sämtlichen Unterverzeichnissen mit folgender Befehlszeichenfolge kompiliert werden:
csc /t:library /out:MyCodeLibrary.dll /recurse:*.cs
Die Ausgabe ist in beiden Fällen gleich.
Erzeugen einer XML-Dokumentationsdatei mithilfe von "/doc"
Die Klasse SimpleType wurde mit verschiedenen XML-Elementen ausgestattet. Wie Sie höchstwahrscheinlich wissen, verwendet der C#-Compiler diese mit drei Schrägstrichen versehenen Codekommentare, um eine XML-Dokumentationsdatei zu erstellen. Sie müssen die Option /doc zusammen mit dem Namen für die zu erzeugende Datei angeben, um csc.exe anzuweisen, eine solche Datei zu erstellen:
csc /t:library /out:MyCodeLibrary.dll /recurse:*.cs /doc:myDoc.xml
In Ihrem Anwendungsverzeichnis sollten Sie jetzt eine neue Datei namens myDoc.xml finden. Wenn Sie diese Datei öffnen, werden Sie feststellen, dass Ihre Klasse mithilfe von XML dokumentiert wurde, wie in Abbildung 5 dargestellt.
Abbildung 5: Dokumentausgabe in XML
Hinweis
Wenn Sie Einzelheiten über XML-Codekommentare für C# erfahren möchten, lesen Sie den Artikel XML Comments Let You Build Documentation Directly From Your Visual Studio .NET Source Files (in Englisch).
Erstellen eines starken Namens mithilfe der Option "/keyfile"
Als letzte Aufgabe dieses Beispiels soll die Assembly mit einem starken Namen versehen werden. Unter .NET 1.1 musste man zur Erzeugung einer Assembly mit starkem Namen das Attribut [AssemblyKeyFile] verwenden. Obwohl dies auch weiterhin ausgezeichnet funktioniert, stellt der Compiler von C# 2.0 jetzt das Flag /keyfile zur Verfügung, um den Speicherort von Schlüsseldateien mit starken Namen (SNK-Dateien) anzugeben.
Erstellen Sie einen neuen Ordner auf dem Laufwerk C mit dem Namen MyKeyPair und wechseln Sie mithilfe der Eingabeaufforderung in dieses Verzeichnis. Erzeugen Sie anschließend ein Schlüsselpaar mit dem Namen myKeyPair.snk, indem Sie die Option –k des Dienstprogramms sn.exe verwenden.
sn -k myKeyPair.snk
Geben Sie die folgende Befehlszeichenfolge ein, um MyCodeLibrary.dll mithilfe von csc.exe mit einem starken Namen zu versehen:
csc /t:library /out:MyCodeLibrary.dll /recurse:*.cs /doc:myDoc.xml /keyfile:C:\MyKeyPair\myKeypair.snk
Verwenden Sie das Sicherheitsdienstprogramm (secutil.exe) mit der Option –s zur Anzeige von Informationen über starke Namen, um zu überprüfen, ob die Assembly tatsächlich über einen starken Namen verfügt:
secutil /sMyCodeLibrary.dll
Der Wert des im Assembly-Manifest aufgezeichneten öffentlichen Schlüssels sollte wie in Abbildung 6 dargestellt ausgegeben werden.
Abbildung 6: Ausgabe des Wertes des öffentlichen Schlüssels
Der Compiler von C# 2.0 verfügt über einige andere auf starke Namen bezogene Flags ( /delaysign und /keycontainer), mit denen Sie sich vielleicht in Ruhe beschäftigen möchten. Wenn Sie die verzögerte Signierung aktivieren möchten, verwenden Sie insbesondere die Option /delaysign.
Arbeiten mit C#-Antwortdateien
Obwohl bei der Arbeit mit der Befehlszeile auf vorherige Eingaben zurückgegriffen werden kann, wird niemand bestreiten, dass die Eingabe dutzender Compileroptionen zu Verspannungen und Fehleingaben führen kann. Der C#-Compiler unterstützt die Verwendung von Antwortdateien, um zur Linderung beider Probleme beizutragen.
Hinweis Alle Eingabeaufforderungen ermöglichen das Navigieren durch vorherige Befehlseingaben mithilfe der Tasten Pfeil nach oben und Pfeil nach unten.
Antwortdateien (der Konvention folgend mit der Dateierweiterung RSP) enthalten sämtliche Optionen, die Sie csc.exe übergeben möchten. Sobald diese Datei erstellt wurde, können Sie den Dateinamen als einzige Option für den C#-Compiler angeben. Zur Verdeutlichung folgt eine Antwortdatei, die zur Erstellung von MyCodeLibrary.dll verwendet wird. Beachten Sie, dass Sie das Zeichen # für die Angabe von Kommentaren verwenden können:
# MyCodeLibraryArgs.rsp # These are the options used # to compile MyCodeLibrary.dll # Output target and name. /t:library /out:MyCodeLibrary.dll # Location of C# files. /recurse:*.cs # Give me an XML doc. /doc:myDoc.xml # Give me a strong name as well. /keyfile:C:\MyKeyPair\myKeypair.snk
Mit dieser Vorgabe können Sie jetzt MyCodeLibraryArgs.rsp unter Verwendung der Option @ angeben:
csc @MyCodeLibraryArgs.rsp
Sie können bei Bedarf auch mehrere Antwortdateien angeben:
csc @MyCodeLibraryArgs.rsp @MoreArgs.rsp @EvenMoreArgs.rsp
Beachten Sie, dass Antwortdateien in der Reihenfolge verarbeitet werden, in der sie vorliegen. Daher können Einstellungen in einer vorhergehenden Datei durch Einstellungen in einer später folgenden Datei überschrieben werden.
Standardantwortdatei und die Option "/noconfig"
Denken Sie abschließend daran, dass es die Standardantwortdatei csc.rsp gibt, die bei jeder Kompilierung automatisch von csc.exe verarbeitet wird. Wenn Sie sich den Inhalt dieser im gleichen Ordner wie csc.exe befindlichen Datei ansehen, finden Sie nicht viel mehr als einen Satz häufig referenzierter Assemblys (System.Windows.Forms.dll, System.Data.dll usw.).
Im seltenen Fall, dass Sie die Einbeziehung von csc.rsp nicht wünschen, können Sie das Flag /noconfig angeben:
csc /noconfig @MyCodeLibraryArgs.rsp
Hinweis Wenn Sie eine Assembly referenzieren, die Sie jedoch tatsächlich nicht verwenden, wird diese in Ihrem Assemblymanifest nicht aufgeführt. Sorgen Sie sich also nicht um Probleme mit aufgeblähtem Code, sie kommen nicht vor.
Referenzieren externer Assemblys mithilfe von "/reference"
Bis hierher wurde eine aus einer Datei bestehende, mit einem starken Namen versehene (und dokumentierte) Codebibliothek mithilfe des Befehlszeilencompilers erzeugt. Nötig ist noch eine Clientanwendung, um sie einzusetzen. Erzeugen Sie unter C:\MyCSharpCode einen neuen Ordner mit dem Namen MyClient und bilden Sie in diesem Ordner eine neue C#-Codedatei (simpleTypeClient.cs), die am Programmanfang die statische Methode SimpleType.DisplayEnvironment() aufruft:
// simpleTypeClient.cs using System; // Namespace in MyCodeLibrary.dll using MyCodeLibrary; namespace MyClientApp { public class MyApp { public static void Main() { SimpleType.DisplayEnvironment(); Console.ReadLine(); } } }
Da die Clientanwendung MyCodeLibrary.dll verwendet, muss die Option /reference (oder einfach /r) eingesetzt werden. Dieses Flag ist flexibel, so dass Sie den vollständigen Pfad zu der in Frage kommenden DLL-Datei wie folgt angeben können:
csc /t:exe /r:C:\MyCSharpCode\MyCodeLibrary\MyCodeLibrary.dll *.cs
Wenn sich eine Kopie der privaten Assembly im selben Ordner wie die Eingabedateien befindet, können Sie einfach den Namen der Assembly angeben:
csc /t:exe /r:MyCodeLibrary.dll *.cs
Beachten Sie, dass die Optionen für /out nicht angegeben wurden. Somit erzeugt csc.exe einen Namen auf der Grundlage der ersten Eingabedatei (simpleTypeClient.cs). Weiterhin ist das Argument /t:exe optional, da in der Standardeinstellung von /target eine Konsolenanwendung erzeugt wird.
Da MyCodeLibrary.dll eine private Assembly ist, müssen Sie auf jeden Fall eine Kopie dieser Bibliothek im Verzeichnis MyClient ablegen. Sobald Sie dies getan haben, können Sie die Anwendung simpleTypeClient.exe ausführen. In Abbildung 7 wird ein Testlauf dargestellt.
Abbildung 7: Mögliche Ausgabe eines Testlaufs
Hinweis
Erinnern Sie sich, dass eine Assembly mit starkem Namen nicht im GAC (Global Assembly Cache) bereitzustellen ist. Aufgrund der durch einen starken Namen gegebenen Sicherheitsvorteile gilt es als bewährte .NET-Praxis, jede Assembly, ob freigegeben oder nicht, mit einem starken Namen zu versehen.
Referenzieren von mehreren externen Assemblys
Sie können die Option /reference mehrfach angeben, wenn Sie auf der Befehlszeile mehrere Assemblys referenzieren möchten. Stellen Sie sich vor, die Clientanwendung benötige Typen, die in der Bibliothek mit dem Namen NewLib.dll enthalten sind:
csc /t:exe /r:MyCodeLibrary.dll /r:NewLib.dll *.cs
Sie können als etwas einfachere Alternative die Option /reference nur einmal angeben und jede Assembly in Form einer durch Semikolon getrennten Liste angeben:
csc /t:exe /r:MyCodeLibrary.dl;NewLib.dll *.cs
Die gleiche Syntax kommt selbstverständlich auch bei der Erstellung einer C#-Antwortdatei zum Einsatz.
Einige Worte zu "/lib"
Bevor die Rolle von Assembly-Aliasen in C# 2.0 erläutert wird, einige kurze Bemerkungen über das Flag /lib. Diese Option lässt sich einsetzen, um csc.exe das Verzeichnis bekanntzugeben, in dem sich die durch das Flag /reference angegebenen Assemblys befinden. Um dies zu veranschaulichen, nehmen Sie an, Sie hätten drei DLL-Assemblys im Stammverzeichnis von Laufwerk C. Um csc.exe anzuweisen, asm1.dll, asm2.dll und asm3.dll unter C:\ zu suchen, würden Sie Folgendes eingeben:
csc /lib:c:\ /reference:asm1.dll;asm2.dll;asm3.dll *.cs
Würden Sie nicht die Option /lib verwenden, müssten Sie diese drei .NET-Codebibliotheken manuell in das Verzeichnis kopieren, in dem sich auch die Eingabedateien befinden. Beachten Sie ebenfalls, dass das Ergebnis kumulativ ist, wenn Sie das Flag /lib mehrmals in einem Befehl eingeben.
Verstehen der Referenz-Aliase von C# 2.0
Abschließend ist zu der Option /reference anzumerken, dass unter C# 2.0 das Erzeugen eines Alias für eine referenzierte Assembly möglich ist. Dieses Feature ermöglicht die Lösung von Namenskonflikten bei identisch benannten Typen, die in eindeutig benannten Assemblys enthalten sind.
Erzeugen Sie einen neuen Ordner im Verzeichnis C:\MyCSharpCode mit dem Namen MyCodeLibrary2, um dieses nützliche Feature zu veranschaulichen. Speichern Sie Kopien der vorhandenen Dateien simpleType.cs und AsmInfo.cs in dem neuen Verzeichnis. Fügen Sie der Klasse SimpleType eine neue Methode hinzu, die eine vom Client übergebene Zeichenfolge anzeigt:
/// <summary> /// Display a user supplied message. /// </summary> public static void PrintMessage(string msg) { Console.WriteLine("You said: {0}", msg); }
Kompilieren Sie diese Dateien folgendermaßen, um eine neue Assembly mit dem Namen MyCodeLibrary2.dll zu erzeugen:
csc /t:library /out:MyCodeLibrary2.dll *.cs
Speichern Sie abschließend eine Kopie dieser neuen Codebibliothek im Ordner MyClient (Abbildung 8).
Abbildung 8: Neuer Code im Ordner MyClient
Wenn das aktuelle Clientprogramm sowohl MyCodeLibrary.dll als auch MyCodeLibrary2.dll referenzieren soll, kann dies folgendermaßen erreicht werden:
csc /t:exe /r:MyCodeLibrary.dll;MyCodeLibrary2.dll *.cs
Der Compiler zeigt an, dass ein Namenskonflikt besteht, da beide Assemblys eine Klasse namens SimpleType definieren:
simpleTypeClient.cs(13,7): error CS0433: The type 'MyCodeLibrary.SimpleType' exists in both 'c:\MyCSharpCode\MyClient\MyCodeLibrary.dll' and 'c:\MyCSharpCode\MyClient\MyCodeLibrary2.dll'
Auf den ersten Blick scheint es, dieses Problem könnte gelöst werden, indem man vollständig qualifizierte Namen im Clientcode verwendet. Dadurch wird das Problem, dass in beiden Assemblys derselbe vollständig qualifizierte Name (MyCodeLibrary.SimpleType) definiert wird, allerdings nicht behoben.
Mit der neuen Aliasoption des Flags /reference können eindeutige Namen für jede referenzierte Codebibliothek erzeugt werden. Sobald dies geschehen ist, kann der Clientcode aktualisiert werden, um einen Typ einer spezifischen Assembly zuzuordnen.
Der erste Schritt besteht in der Änderung der Datei simpleTypeClient.cs, um die Aliase, die mithilfe der neuen Syntax extern alias auf der Befehlszeile angegeben werden, verwenden zu können:
// Extern alias statements must be // listed before all other code! extern alias ST1; extern alias ST2; using System; namespace MyClientApp { public class MyApp { public static void Main() { // Bind assembly to type using the '::' operator. ST1::MyCodeLibrary.SimpleType.DisplayEnvironment(); ST2::MyCodeLibrary.SimpleType.PrintMessage("Hello!"); Console.ReadLine(); } } }
Beachten Sie die neue C# 2.0-Anweisung extern alias zum Abfangen der auf der Befehlszeile definierten Aliase. Hier ist ST1 der für MyCodeLibrary.dll definierte Alias, während ST2 der für MyCodeLibrary2.dll definierte Alias ist:
csc /r:ST1=MyCodeLibrary.dll /r:ST2=MyCodeLibrary2.dll *.cs
Beachten Sie, wie die Methode Main() in Anbetracht dieser Aliase den Bereichsoperator (::) von C# 2.0 zur Bindung des Assemblyalias an den Typ verwendet:
// This says "I want the MyCodeLibrary.SimpleType class // that is defined in MyCodeLibrary.dll". ST1::MyCodeLibrary.SimpleType.DisplayEnvironment();
Diese Variante der Option /reference bietet die Möglichkeit, Namenskonflikte zu vermeiden, die auftreten, wenn zwei eindeutig benannte Assemblys identisch benannte Typen enthalten.
Erstellen einer Mehrfachdateiassembly mithilfe von "/addmodule"
Wie Sie vielleicht bereits wissen, bietet eine Mehrfachdatei-Assembly die Möglichkeit, eine einzelne .NET-Binärdatei in kleinere Teile aufzuteilen. Dies kann sich als recht nützlich erweisen, wenn .NET-Module remote heruntergeladen werden. Das Endergebnis einer Mehrfachdatei-Assembly ist eine Sammlung von Dateien, die als einzelne Einheit referenziert und versioniert wird.
Eine Mehrfachdatei-Assembly besteht aus einer primären DLL, die das Assembly-Manifest enthält. Die zusätzlichen Module der Mehrfachdatei-Assembly, die der Konvention folgend die Dateierweiterung NETMODULE erhalten, werden im Manifest des primären Moduls aufgezeichnet und auf Anforderung von der CLR geladen. Bis heute können Mehrfachdatei-Assemblys nur mithilfe des Befehlszeilencompilers erstellt werden.
Erzeugen Sie ein neues Unterverzeichnis im Verzeichnis C:\MyCSharpCode mit dem Namen MultiFileAsm, um diese Vorgehensweise zu veranschaulichen. Ziel ist die Erstellung einer Mehrfachdatei-Assembly mit dem Namen AirVehicles. Das primäre Modul (Airvehicles.dll) soll einen einzelnen Klassentyp mit dem Namen Helicopter enthalten (wird gleich definiert). Das Assembly-Manifest führt ein weiteres Modul auf (ufos.netmodule), das einen Klassentyp mit dem Namen UFO definiert:
// ufo.cs using System; using System.Windows.Forms; namespace AirVehicles { public class UFO { public void AbductHuman() { MessageBox.Show("Resistance is futile"); } } }
Um ufo.cs in ein .NET-Modul zu kompilieren, geben Sie als Zieltyp /t:module an, so dass die NETMODULE-Benennungskonvention automatisch berücksichtigt wird. Da die Standardantwortdatei System.Windows.Forms.dll automatisch referenziert, muss diese Bibliothek nicht explizit referenziert werden:
csc /t:module ufo.cs
Wenn Sie ufo.netmodule in ildasm.exe laden, sehen Sie ein Modulebenen-Manifest, das den Namen des Moduls und extern referenzierte Assemblys dokumentiert (beachten Sie, dass für Dateien mit der Erweiterung NETMODULE keine Versionsnummer angegeben wird, da dies die Aufgabe des primären Moduls ist):
.assembly extern mscorlib{...} .assembly extern System.Windows.Forms{...} .module ufo.netmodule
Erzeugen Sie jetzt eine Datei mit dem Namen helicopter.cs, die zur Kompilierung des primären Moduls Airvehicles.dll verwendet wird:
// helicopter.cs using System; using System.Windows.Forms; namespace AirVehicles { public class Helicopter { public void TakeOff() { MessageBox.Show("Helicopter taking off!"); } } }
Wenn Airvehicles.dll das primäre Modul dieser Mehrfachdatei-Assembly ist, müssen Sie das Flag /t:library angeben. Wenn Sie allerdings die Binärdatei ufo.netmodule in das Assembly-Manifest aufnehmen möchten, müssen Sie auch die Option /addmodule angeben:
csc /t:library /addmodule:ufo.netmodule /out:airvehicles.dll helicopter.cs
Wenn Sie das Manifest auf Assemblyebene untersuchen (mithilfe von ildasm.exe), das in der Binärdatei airvehicles.dll enthalten ist, werden Sie feststellen, dass ufo.netmodule tatsächlich mit der Direktive .file CIL verzeichnet ist:
.assembly airvehicles{...} .file ufo.netmodule
Der Consumer einer Mehrfachdatei-Assembly muss sich weniger darum kümmern, dass die referenzierte Assembly aus einer Vielzahl binärer Dateien zusammengesetzt ist. Tatsächlich ist der Vorgang syntaktisch identisch mit der Verwendung einer Einzeldatei-Assembly. Um das Thema weiterhin interessant zu gestalten, erzeugen Sie eine Clientanwendung auf der Grundlage von Windows Forms.
Erstellen einer Windows Forms-Anwendung
Das nächste Beispielprojekt besteht aus einer Windows Forms-Anwendung, die die Mehrfachdatei-Assembly airvehicles.dll verwendet. Erzeugen Sie im Verzeichnis C:\MyCSharpCode ein neues Verzeichnis mit dem Namen WinFormClient. Erzeugen Sie eine von Form abgeleitete Klasse, die einen einzelnen Button-Typ definiert. Wenn darauf geklickt wird, soll dieser einen Helicopter- und einen UFO-Typ erzeugen und deren Member aufrufen:
using System; using System.Windows.Forms; using AirVehicles; public class MyForm : Form { private Button btnUseVehicles = new Button(); public MyForm() { this.Text = "My Multifile Asm Client"; btnUseVehicles.Text = "Click Me"; btnUseVehicles.Width = 100; btnUseVehicles.Height = 100; btnUseVehicles.Top = 10; btnUseVehicles.Left = 10; btnUseVehicles.Click += new EventHandler(btnUseVehicles_Click); this.Controls.Add(btnUseVehicles); } private void btnUseVehicles_Click(object o, EventArgs e) { Helicopter h = new Helicopter(); h.TakeOff(); UFO u = new UFO(); u.AbductHuman(); } private static void Main() { Application.Run(new MyForm()); } }
Hinweis Achten Sie darauf, die Binärdateien airvehicals.dll und ufo.netmodule in das Verzeichnis WinFormClient zu kopieren, bevor Sie fortfahren.
Achten Sie darauf, winexe als Zusatzangabe für das Flag /target anzugeben, um diese Anwendung als ausführbares Windows Forms-Programm zu kompilieren. Beachten Sie, dass für die Referenzierung einer Mehrfachdateiassembly nur der Name des primären Moduls angegeben wird:
csc /t:winexe /r:airvehicles.dll *.cs
Sobald Sie Ihr Programm ausführen und auf die Schaltfläche klicken, sollte jedes Meldungsfeld wie erwartet angezeigt werden. In Abbildung 9 wird ein von mir erzeugtes Meldungsfeld dargestellt.
Abbildung 9: Beispiel für ein Meldungsfeld
Arbeiten mit Ressourcen unter Verwendung von csc.exe
Als Nächstes wird erläutert, wie csc.exe zur Einbettung von Ressourcen (wie Zeichenfolgentabellen oder Bilddateien) in .NET-Assemblys eingesetzt werden kann. Die Option /win32Icon dient dazu, den Pfad zu einer Win32-Datei mit der Erweiterung ICO anzugeben. Nehmen Sie an, eine Symboldatei mit dem Namen HappyDude.ico wurde im Anwendungsverzeichnis der aktuellen Windows Forms-Anwendung gespeichert. Geben Sie folgende Befehlszeichenfolge ein, um HappyDude.ico als Symbol für die ausführbare Datei festzulegen:
csc /t:winexe /win32icon:HappyDude.ico /r:airvehicles.dll *.cs
An dieser Stelle sollte die ausführbare Assembly wie in Abbildung 10 dargestellt aktualisiert sein.
Abbildung 10: Die aktualisierte ausführbare Assembly
Neben der Möglichkeit, einer Anwendung mithilfe des Flags /win32icon ein Symbol zuzuweisen, stellt csc.exe drei weitere ressourcenorientierte Optionen zur Verfügung (siehe Tabelle 5).
Tabelle 5: Ressourcenorientierte Optionen von csc.exe
Ressourcenorientierte Option |
Definition |
---|---|
/resource |
Bettet Ressourcen, die in einer Datei mit der Erweiterung RESOURCES vorliegen, in die aktuelle Assembly ein. Beachten Sie, dass Ressourcen mit dieser Option sowohl "öffentlich" zur allgemeinen Verwendung als auch "privat" zur ausschließlichen Verwendung der aufnehmenden Assembly eingebettet werden können. |
/linkresource |
Erstellt im Assemblymanifest eine Verknüpfung zu einer externen Ressourcendatei, fügt die Ressourcen selbst jedoch nicht ein. |
/win32res |
Ermöglicht das Einbetten von Ressourcen aus Legacydateien mit der Erweiterung RES. |
Bevor Sie erfahren, wie Ressourcen in Assemblys eingebettet werden, möchte ich Ihnen eine kurze Einführung über Ressourcen auf der .NET-Plattform geben. Wie Sie vielleicht bereits wissen, entstehen .NET-Ressourcen typischerweise als Satz von Name/Wert-Paaren, die als XML- oder Textdateien (RESX- bzw. TXT-Dateien) gespeichert werden. Die XML- bzw. Textdatei wird anschließend in eine gleichwertige Binärdatei umgewandelt, die die Dateierweiterung RESOURCES erhält. Diese Binärdateien werden in die Assembly eingebettet und im Manifest verzeichnet. Wenn die Ressourcen programmgesteuert aus der Assembly gelesen werden sollen, stellt der Namespace System.Resources eine Anzahl von Typen für diesen Zweck zur Verfügung. Besonders erwähnenswert ist die Klasse ResourceManager.
Obwohl Sie sicherlich RESX-Dateien auch manuell erstellen können, verwenden Sie doch besser das Befehlszeilentool resgen.exe (oder natürlich Visual Studio .NET). Auch wenn dieser Artikel nicht der Ort für eine Beschreibung sämtlicher Einzelheiten von resgen.exe ist, soll ein einfaches Beispiel erläutert werden.
Einbetten von Ressourcen mithilfe von "/resource"
Erzeugen Sie ein neues Verzeichnis unter MyCSharpCode mit dem Namen MyResourceApp. Verwenden Sie Notepad.exe, um in diesem Verzeichnis eine neue Datei namens myStrings.txt anzulegen, die einige interessante Name/Wert-Paare Ihrer Wahl enthält. Beispiel:
# A list of personal data company=Intertech Training lastClassTaught=.NET Security lastPresentation=SD East Best Practices favoriteGameConsole=XBox favoriteComic=Cerebus
Wandeln Sie jetzt mithilfe einer Eingabeaufforderung und dem folgenden Befehl die TXT-Datei in eine XML-basierte RESX-Datei um:
resgen myStrings.txt myStrings.resx
Wenn Sie diese Datei mit Notepad.exe öffnen, werden zahlreiche XML-Elemente angezeigt, die Ihre Name/Wert-Paare beschreiben, beispielsweise:
<data name="company"> <value xml:space="preserve">Intertech Training</value> </data> <data name="lastClassTaught"> <value xml:space="preserve">.NET Security</value> </data>
Sie wandeln die RESX-Datei in eine binäre RESOURCES-Datei um, indem Sie einfach die Dateierweiterung als Argument von resgen.exe aktualisieren:
resgen myStrings.resx myStrings.resources
Jetzt liegt eine binäre Ressourcendatei mit dem Namen myStrings.resources vor. Diese Daten können Sie mithilfe von csc.exe in eine .NET-Assembly einbetten, indem Sie das Flag /resource verwenden. Nehmen Sie an, Sie hätten folgende C#-Datei (resApp.cs) erstellt, die sich im Verzeichnis MyResourceApp befindet:
// This simple app reads embedded // resources and displays them to the // console. using System; using System.Resources; using System.Reflection; public class ResApp { private static void Main() { ResourceManager rm = new ResourceManager("myStrings", Assembly.GetExecutingAssembly()); Console.WriteLine("Last taught a {0} class.", rm.GetString("lastClassTaught")); } }
Geben Sie folgenden Befehl ein, um diese Assembly unter Berücksichtigung der Datei myStrings.resources zu kompilieren:
csc /resource:myStrings.resources *.cs
Da das Flag /out nicht angegeben wurde, wird der Name der ausführbaren Datei auf der Grundlage der Datei gebildet, die die Methode Main() definiert, in diesem Fall resApp.exe. Wenn alles gut gegangen ist, sollte nach dem Start des Programms eine Ausgabe ähnlich der in Abbildung 11 angezeigt werden.
Abbildung 11: Ausgabe
Ich hoffe, die Erstellung von .NET-Einzeldatei- und Mehrfachdatei-Assemblys (mit Ressourcen!) mithilfe von csc.exe und einem Texteditor Ihrer Wahl bereitet Ihnen keine Schwierigkeiten mehr. Während Sie bisher die gebräuchlichsten Befehlszeilenoptionen von csc.exe kennen gelernt haben, beschäftigt sich der Rest des Artikels mit einigen seltener eingesetzten, jedoch ebenfalls nützlichen Optionen.
Erzeugen Sie ein neues Verzeichnis namens FinalExample im Ordner MyCSharpCode, wenn Sie die folgenden Beispiele nachvollziehen möchten.
Definieren von "Präprozessor"-Symbolen mithilfe von "/define"
Obwohl der C#-Compiler Code nicht im eigentlichen Sinn „vor-verarbeitet“, ermöglicht die Sprache doch, C-ähnliche Präprozessorsymbole zu definieren und so mit dem Compiler zu interagieren. Mithilfe der #define-Anweisung von C# ist es möglich, Token zu erzeugen, die den Ausführungspfad innerhalb der Anwendung steuern können.
Hinweis Definierte Symbole müssen vor der Verwendung irgendeiner Anweisung oder C#-Typdefinition aufgeführt werden.
Nehmen Sie beispielsweise an, Sie möchten ein Symbol namens DEBUG definieren. Erzeugen Sie dazu eine neue Datei mit dem Namen finalEx.cs und speichern Sie diese im Verzeichnis MyCSharpCode\FinalExample:
// Define a 'preprocessor' symbol named DEBUG. #define DEBUG using System; public class FinalExample { public static void Main() { #if DEBUG Console.WriteLine("DEBUG symbol defined"); #else Console.WriteLine("DEBUG not defined"); #endif } }
Beachten Sie, dass Sie über die Schlüsselwörter #if, #else und #endif auf ein mit #define definiertes Symbol hin prüfen und reagieren können. Wenn Sie dieses Programm kompilieren, wird bei der Ausführung von finalEx.exe auf der Konsole die Meldung "DEBUG symbol defined" ausgegeben:
csc *.cs
Wenn Sie allerdings die Symboldefinition auskommentiert haben:
// #define DEBUG
erfolgt die Ausgabe, wie Sie es erwarten: "DEBUG not defined".
Während der Entwicklung und dem Testen einer .NET-Assembly kann es hilfreich sein, Symbole auf der Befehlszeile zu definieren. Damit können Sie schnell im Handumdrehen Symbole angeben, anstatt den Code jedes Mal zu aktualisieren. Verwenden Sie die Option /define, wenn Sie das DEBUG-Symbol auf der Befehlszeile definieren möchten:
csc /define:DEBUG *.cs
Wenn Sie die Anwendung erneut ausführen, sollte "DEBUG symbol defined" angezeigt werden, obwohl die Anweisung #define auskommentiert wurde.
Debugorientierte Optionen von csc.exe
Auch die besten Programmierer müssen gelegentlich ihren Code debuggen. Auch wenn ich annehme, die meisten von Ihnen bevorzugen Visual Studio .NET zum Debuggen, lohnt es sich, einige wichtige debugorientierte Optionen von csc.exe zu erwähnen (Tabelle 6).
Tabelle 6: Debugorientierte Optionen von csc.exe
Debugorientierte Option |
Definition |
---|---|
/debug |
Weist csc.exe an, eine PDB-Datei zu erzeugen, die mit Debuggingtools wie cordbg.exe, dbgclr.exe oder Visual Studio verwendet werden kann. |
/warnaserror |
Behandelt alle Warnungen als schwerwiegende Fehler. |
/warn |
Ermöglicht die Angabe einer Warnstufe für die aktuelle Kompilierung (0, 1, 2, 3 oder 4). |
/nowarn |
Ermöglicht das Deaktivieren spezieller C#-Compilerwarnungen. |
/bugreport |
Diese Option erzeugt ein Fehlerprotokoll, wenn die Anwendung während der Ausführung abstürzt. Sie werden aufgefordert, Informationen zur Korrektur einzugeben, die an beliebige Personen gesendet werden kann (z. B. an das Qualitätssicherungsteam). |
Um die Verwendung der Option /debug zu verdeutlichen, müssen zuerst einige Programmierfehler in die Datei finalEx.cs eingefügt werden. Fügen Sie Folgendes in die Methode Main() ein:
// Create an array. string[] myStrings = {"Csc.exe is cool"}; // Go out of bounds. Console.WriteLine(myStrings[1]);
Wie Sie sehen, wird versucht, mit einem Index, der über die Grenzen des Arrays hinausgeht, auf den Inhalt des Arrays zuzugreifen. Wenn Sie das Programm erneut kompilieren und ausführen, erhalten Sie eine IndexOutOfRangeException. Nehmen Sie einen komplexeren, nicht so offensichtlichen Fehler an, da dieser Fehler leicht ausgemacht werden kann.
Um eine mit csc.exe erstellte Assembly zu debuggen, muss zuerst eine PDB-Datei erzeugt werden, die die von den verschiedenen .NET-Debugging-Dienstprogrammen benötigten Informationen enthält. Dazu können Sie einen der folgenden Befehle eingeben (sie sind gleichwertig in ihrer Funktion):
csc /debug *.cs csc /debug+ *.cs
Jetzt sollte eine neue Datei namens finalEx.pdb in Ihrem Anwendungsverzeichnis angezeigt werden, wie in Abbildung 12 dargestellt.
Abbildung 12: Die neue Datei finalEx.pdb in Ihrem Anwendungsverzeichnis
Das Flag /debug kann optional mit dem Token full oder pdbonly näher bestimmt werden. Wenn Sie /debug:full angeben (die Standardeinstellung), wird die Assembly so geändert, dass sie während der Ausführung an einen Debugger übergeben werden kann. Achten Sie darauf, diese Option nur zum Debuggen zu verwenden, da diese Option die Größe und Geschwindigkeit der sich ergebenden .NET-Assembly beeinträchtigt. Da full die Standardeinstellung des Flags /debug ist, sind diese Optionen alle funktionell gleichwertig:
csc /debug *.cs csc /debug+ *.cs csc /debug:full *.cs
Andererseits erzeugt die Angabe /debug:pdbonly eine PDB-Datei und eine Assembly, die nur debuggt werden kann, wenn sie direkt von einem Debuggingtool aus gestartet wird:
csc /debug:pdbonly *.cs
In jedem Fall können Sie die Anwendung, nachdem Sie über die erforderliche PDB-Datei verfügen, mit jedem beliebigen Debuggingtool debuggen (cordbg.exe, dbgclr.exe oder Visual Studio). Um weiterhin die Befehlszeile in den Vordergrund dieses Artikels zu stellen, wird das Debugging dieser Anwendung mit dem Dienstprogramm cordbg.exe durchgeführt:
cordbg finalEx.exe
Sobald die Debuggingsitzung gestartet wurde, können Sie mit dem Befehl so (step over) von Zeile zu Zeile gehen. Wenn Sie auf die fehlerhafte Codezeile treffen, erhalten Sie den Codedump, der in Abbildung 13 dargestellt wird.
Abbildung 13: Codedump bei dem Befehl "so"
Geben Sie exit ein und drücken Sie die Eingabetaste, um das Dienstprogramm cordbg.exe zu beenden.
Hinweis Eine Erläuterung der .NET-Debuggingtools ist nicht Thema dieses Artikels. Wenn Sie mehr über das Debuggen auf der Befehlszeile erfahren möchten, suchen Sie nach cordbg.exe in der Hilfe von Visual Studio.
Zum Abschluss einige selten verwendete Optionen
Bis hierher haben Sie die Einzelheiten der wesentlichen Optionen des C#-Befehlszeilencompilers kennen gelernt. Um das Thema zu vervollständigen, werden in Tabelle 7 die verbleibenden Flags knapp beschrieben, die bisher nicht behandelt wurden.
Tabelle 7: Die verbleibenden Optionen von csc.exe
Option |
Definition |
---|---|
/baseaddress |
Diese Option ermöglicht die Angabe der gewünschten Basisadresse zum Laden einer DLL. In der Standardeinstellung wird die Basisadresse von der CLR ausgewählt. |
/checked |
Gibt an, ob bei Integerarithmetik, die über die Grenzen eines Datentyps hinausgeht, zur Laufzeit eine Ausnahme ausgelöst wird. |
/codepage |
Gibt die für alle Quelldateien bei der Kompilierung zu verwendende Codepage an. |
/filealign |
Die Option steuert die Segmentgröße innerhalb der ausgegebenen Assembly (512, 1.024, 2.048, 4.096 oder 8.192 Byte). Wenn Sie für ein mobiles Gerät wie einen Pocket PC kompilieren, kann /filealign zur Angabe der geringstmöglichen Segmente verwendet werden. |
/langversion |
Diese Option stellt für den Compiler C#-Sprachfeatures nach ISO-1 ein, die den Features von C# 1.0 entsprechen. |
/main |
Wenn in Ihrem aktuellen Projekt mehrere Main()-Methoden definiert sind (kann während des Testens von Einheiten hilfreich sein), ermöglicht dieses Flag die Angabe der beim Laden der Assembly auszuführenden Main()-Methode. |
/nostdlib |
In der Standardeinstellung referenzieren Assembly-Manifeste automatisch die Datei mscorlib.dll. Dieser Mechanismus wird durch Angabe dieser Option deaktiviert. |
/optimize |
Durch Aktivierung dieser Option (/optimize+) wird der Compiler angewiesen, die kleinste und schnellste Assembly zu erzeugen, die möglich ist. Durch diese Option werden Metadaten erzeugt, die auch die CLR anweisen, den Code zur Laufzeit zu optimieren. |
/platform |
Dieses Flag weist den Compiler an, die Assembly für 32- oder 64-Bit-Prozessoren zu optimieren. Im Großen und Ganzen ist diese Option nur dann sinnvoll, wenn im C#-Code P/Invoke und/oder unsichere Codekonstrukte verwendet werden. Der Standardwert ist anycpu. |
/unsafe |
Bei Aktivierung dieser Option kann in C#-Dateien ein unsicherer Bereich deklariert werden, der normalerweise zur Manipulation von Zeigern im C++-Stil eingesetzt wird. |
/utf8output |
Mit dieser Option wird der Compiler angewiesen, Ausgabedaten im UTF-8-Format zu kodieren. |
Für die meisten Ihrer .NET-Projekte bieten die in Tabelle 7 aufgelisteten Optionen wenig Vorteile. Daher nehme ich an, Sie informieren sich über MSDN, wenn Sie weitere Einzelheiten erfahren möchten.
Schlussbemerkung
In diesem Artikel wurde die Erstellung von Assemblys mithilfe des C#-Befehlszeilencompilers vorgestellt. Wie Sie erfahren haben, können Sie den größten Teil Ihrer Arbeit mit zwei Flags erledigen, /target und /reference. In diesem Artikel wurden zusätzlich zur Erläuterung der wichtigsten Flags von csc.exe die Vorteile von Antwortdateien und die Erstellung von Mehrfachdatei-Assemblys erklärt.
Auch wenn in diesem Artikel nicht jede Einzelheit jeder Option, die csc.exe bietet, besprochen wurde, hoffe ich doch, das Sie jetzt über eine gute Ausgangsposition verfügen, um sich mithilfe der Visual Studio 2005-Dokumentation mit den verbleibenden Flags zu beschäftigen.
Viel Spaß beim Codieren!
Andrew Troelsen ist ein Microsoft MVP, der mit Intertech Training (in Englisch) als Berater und Kursleiter zusammenarbeitet. Andrew ist Autor zahlreicher Bücher, einschließlich des preisgekrönten C# and the .NET Platform Second Edition (in Englisch) (Apress 2002). Er verfasste eine monatliche Kolumne für (ausgerechnet) MacTech (in Englisch), in der er die .NET-Entwicklung auf Unix-basierten Systemen mithilfe von SSCLI, Portable.NET und Mono CLI-Distributionen untersucht hat.