C-Integration
Grundgedanke: Starte einen C-Compiler aus/mit Mathematica, kompiliere den Code und verbinde diesen mit Mathematica.
Weitere Anwendungen:
- Benutze in Mathematica anstatt dem internen Mathematica-Compiler einen externen C-Compiler
- Integriere C-Programme in Mathematica und nutze diese als normale Mathematica-Funktionen
- Integriere C-Programme in Mathematica und parallelisiere diese mit Mathematica
- Baue eigenständige C-Programme aus Mathematica
.exe, .lib oder .obj
Erstellen von Software
Erstellen einer Executable
Executables lassen sich mit vielen verschiedenen C-Compilern auf verschiedenen Rechnerarchitekturen erstellen. Mit folgendem Mathematica Code lässt sich das bewerkstelligen.
Needs["CCompilerDriver`"]
CreateExecutable["
#include <stdio.h>
int main(){
printf(\"hello world\\n\");
}
", "hello"]
Erstellen einer Library-Datei
Wie bei einer ausführbaren Datei lassen sich Library-Dateien mit vielen Compilern auf verschiedenen Plattformen generieren.
Needs["CCompilerDriver`"]
file = FileNameJoin[ {$CCompilerDirectory, "SystemFiles", "CSource",
"createDLL_demo.c"}];
CreateLibrary[{file}, "demoLibrary"]
Erstellen einer Object-Datei
Die Object-Dateien lassen sich als Eingabe für CreateExeceutable oder CreateLibrary benutzen.
Needs["CCompilerDriver`"]
file = FileNameJoin[ {$CCompilerDirectory, "SystemFiles", "CSource",
"createDLL_demo.c"}];
CreateObjectFile[{file}, "demoLibrary"]
Verteilen von selbst geschriebener Software
Verteilen von selbst geschriebener Software
Kunden dürfen die mit Mathmatica generierten Executables im Rahmen der Lizenzbedingungen frei verteilen, wobei die jeweilige Lizenzierungsklasse (Industrie, Lehre, Behörde, Schule, Student, Home Edition) eingehalten werden muss. Ein Student darf also keine Programme für die Industrie erstellen ohne eine Industrie-Lizenz zu besitzen.
Wie üblich dürfen die benutzen Libraries nicht verändert oder rückentwickelt "reverse engineered" werden.
Da es sich hier um eine lizenzrechtliche Angelegenheit handelt, hier der Originaltext:
Computer code generated by the user in Mathematica may require certain Mathematica components to be included with the code package in order to run. These Mathematica components, listed below, may be redistributed with the code package. Using these included components in any way other than to distribute and run the program code is expressly prohibited.
WolframRTL.dll
WolframRTL.lib
WolframRTL_Minimal.dll
WolframRTL_Minimal.lib
WolframRTL_Static_Minimal.lib
libWolframRTL.so
libWolframRTL_Minimal.so
libWolframRTL_Static_Minimal.a
libWolframRTL.dylib
libWolframRTL_Minimal.dylib
MathLink Programme kompilieren
MathLink-Programme kompilieren
Der Treiber des C-Compilers erkennt, dass ein MathLink Template benutzt wird und ruft mprep auf, bevor die Ausgabe als Eingabe für den C-Compiler überreicht wird.
Needs["CCompilerDriver`"]
files = FileNames["*",
FileNameJoin[{$InstallationDirectory, "SystemFiles", "Links",
"MathLink", "DeveloperKit", $SystemID, "MathLinkExamples",
"addtwo"}]];
prog = CreateExecutable[files, "addTwo"]
Mit
Install[prog]
wird das Objekt gelinkt, und folgender Aufruf führt nun die Berechnung durch:
AddTwo[2, 3]
In diesem Fall erhalten wir als Ergebnis die Zahl "5".
C-Compiler
C-Compiler
Unterstützte C-Compiler
Unterstützte C-Compiler
Windows: Visual Studio Express 2008, 2010 Visual Studio Professional 2005, 2008, 2010 Cygwin 1.7.5 mit GCC 3.4 MinGW 5.1.6
Windows-x86-64: Visual Studio Express 2008, 2010 Visual Studio Professional 2005, 2008, 2010 Intel C/C++ Compiler 11.1
Linux: GCC 4.0
Linux-x86-64: GCC 4.0 Intel C/C++ Compiler 11.1
MacOSX-x86: GCC 4.0
MacOSX-x86-64: GCC 4.0 Intel C/C++ Compiler 11.1
Aufruf von C-Compilern
Der Aufruf von C-Compilern ist auch möglich. Im Folgenden finden Sie ein kleines Beispiel, in dem der TinyCC benutzt wird. Hierfür gibt es allerdings keinen Support.
Needs["CCompilerDriver`"]
Needs["CCompilerDriver`GenericCCompiler`"]
greeter = CreateExecutable["
#include <stdio.h>
int main() {
printf(\"Hello TinyCC world.\\n\");
}",
"hiworld", "Compiler" -> GenericCCompiler,
"CompilerInstallation" -> "/Pfad/zum/C-Compiler",
"CompilerName" -> "tcc"]
Import["!\"" <> greeter <> "\"", "Text"]
Ein kleines Beispiel
Ein kleines Beispiel
Sie können - wie hier in dem Beispiel zu sehen ist - sehr schnell "standalone" Applikationen erstellen. Hier wird ein RC-Tiefpassfilter erstellt, der Signale in Textform entgegen nimmt und das Ausgangssignal erzeugt.
Als erstes definieren wir unsere Tiefpass-Funktion.
lopass = Compile[{{x, _Real, 1}, dt, RC},
Module[{a = dt/(RC + dt), yprev = First[x], yi},
Table[yi = a*x[[i]] + (1 - a)*yprev;
yprev = yi;
yi, {i, 1, Length[x]}]]];
Nun wird der C-Code und der Header erstellt.
targetDir = CreateDirectory[]
fnSource = FileNameJoin[{targetDir, "lopass.c"}];
Export[fnSource, lopass];
Dann wird eine C-Main-Funktion geschrieben, um den generierten Code aufzurufen.
lopassmainSrcFile = FileNameJoin[{targetDir, "lopassMain.c"}];
Export[lopassmainSrcFile, lopassmainSrc, "Text"]
Danach wird mit der Wolfram Runtime Library kompiliert, um eine ausführbare Datei zu erstellen.
Needs["CCompilerDriver`"];
lopassExe =
CreateExecutable[{fnSource, lopassmainSrcFile}, "lowpass",
"TargetDirectory" -> targetDir,
"Libraries" -> "WolframRTL_Static_Minimal"]
Nun können Sie Ihre Datei weiterverteilen und außerhalb von Mathematica nutzen. Sie können die Datei allerdings auch aus Mathematica selbst aufrufen, um sie zu testen oder vorzuführen. Wir erstellen nun ein Eingangssignal.
input = Table[Sin[x] + Sin[x*10] + Sin[x*50], {x, 0, 10, 0.01}];
ListPlot[input, Joined -> True]
Eine Textdatei wird aus unserem Signal erstellt.
inputText =
StringJoin[ToString[Length[input]], "\n",
Riffle[ToString /@ input, "\n"],(* dt*)"0.01",(*RC *)"0.3"];
inputFile = FileNameJoin[{targetDir, "input.txt"}];
Export[inputFile, inputText, "Text"]
Die ausführbare Datei wird gestartet, das Ausgabesignal konvertiert und unser Eingangs- (blau) und Ausgangssignal (rot) in einem Plot gezeichnet.
SetDirectory[targetDir]; outputLines =
Import["!" <> lopassExe <> " < " <> inputFile, "Lines"];
ResetDirectory[];
output = ToExpression /@ outputLines;
output = If[
Length[output] > 1 && First[output] === 0 &&
output[[2]] === Length[output] - 2,
Drop[output, 2],
$Failed
];
ListPlot[{input, output}, Joined -> True]