1 module selfscript.compile;
2 
3 version (Windows) {
4     import core.sys.windows.windows;
5     import selfscript.windll;
6 }
7 
8 import std.stdio;
9 import std.process;
10 import f = std.file;
11 import std.string;
12 
13 import selfscript.dload;
14 
15 // general path and extension
16 private enum buildCache = "buildcache/";
17 version (Windows) {
18     private enum fileExtension = "dll";
19 } else {
20     private enum fileExtension = "so";
21 }
22 
23 // windows specific generated files
24 version (Windows) {
25     private enum winDllDefFile = buildCache~"dllSharedGcBody.def";
26     private enum winDllFile = buildCache~"dllSharedGcBody.d";
27     private enum winBuildFiles = [winDllDefFile,winDllFile];
28 }
29 
30 /// Creates the build cache folder
31 private void prepareBuilddir() 
32 {
33     version (Windows) {
34         alias exceptionType = f.WindowsException;
35     } else {
36         alias exceptionType = f.FileException;
37     }
38     try {
39         f.mkdir(buildCache);
40     }   
41     catch (exceptionType e) {
42         //ignore    
43     }
44     // on windows, create these two files we need
45     version (Windows) {
46         f.write(winDllDefFile,winDllDefFileContent);
47         f.write(winDllFile,winDllFileContent);
48     }
49 }
50 
51 //void makeTempfile(in char[] line) {
52 //   prepareBuilddir();
53 //    f.write(tempDfile,"\n\n extern(C) export void dllFunc(){\n"~line~"\n}\n");
54 //}
55 
56 
57 /** Compiles a file into a Script object. 
58 *   Parameters:
59 filename = name of the file to compile
60 buildDebug = if the script should be build with debug settings 
61 Return: false on failure.
62 */
63 bool compileScript(string filename, bool buildDebug = true, string[] compilerFlags = [])
64 {
65     import std.path;
66 
67     prepareBuilddir();
68     // build files
69     auto dmdCommandline = ["dmd", filename];
70     version (Windows) {
71         dmdCommandline ~= winBuildFiles;
72     }
73     version (Posix) {
74         dmdCommandline ~= ["-shared","-defaultlib="];
75     }
76     // dir and target
77     dmdCommandline ~= ["-od"~buildCache, "-of"~buildCache~baseName(filename,".d")~"."~fileExtension];
78     // additional flags, likely for libs n shit
79     dmdCommandline ~= compilerFlags;
80     // build settings 
81     if (buildDebug) {
82         dmdCommandline ~=  ["-g","-map"];
83     } else {
84         dmdCommandline ~= ["-O","-release", "-inline"];
85     }
86 
87     // execute and pray
88     if (wait(spawnProcess(dmdCommandline)) != 0) {
89         return false;
90     }
91 
92     return true;
93 }
94 
95 /** Evals a string input. 
96     includes creating the target file, compiling it, loading it, exectuing it and unloading it.
97     Paramter: 
98         input = the input to compile
99         tmpname = name for the temp. script object
100     Return: true on success, false on compiler or loading errors
101 */
102 bool eval(string input, string tmpname="evaltmp", bool buildDebug = true, string[] compilerFlags=[])
103 {
104     prepareBuilddir();
105     auto fname = buildCache~tmpname~".d";
106     f.write(fname,"\n\n extern(C) export void dllFunc(){\n"~input~"\n}\n");
107     if (compileScript(fname,buildDebug,compilerFlags)) {
108         auto s = new ScriptObjectDShared(buildCache~tmpname);
109         s.execute();
110         s.unload();
111 
112         return true;
113     }
114 
115     return false;
116 }