1 /** 2 Code to make the executable do what it does at runtime. 3 */ 4 module dpp.runtime.app; 5 6 import dpp.from; 7 8 /** 9 The "real" main 10 */ 11 void run(in from!"dpp.runtime.options".Options options) @safe { 12 import std.stdio: File; 13 import std.exception: enforce; 14 import std.process: execute; 15 import std.array: join; 16 import std.file: remove; 17 18 foreach(dppFileName; options.dppFileNames) 19 preprocess!File(options, dppFileName, options.toDFileName(dppFileName)); 20 21 if(options.preprocessOnly) return; 22 23 const args = options.dlangCompiler ~ options.dlangCompilerArgs; 24 const res = execute(args); 25 enforce(res.status == 0, "Could not execute `" ~ args.join(" ") ~ "`:\n" ~ res.output); 26 if(!options.keepDlangFiles) { 27 foreach(fileName; options.dFileNames) 28 remove(fileName); 29 } 30 } 31 32 33 /** 34 Preprocesses a quasi-D file, expanding #include directives inline while 35 translating all definitions, and redefines any macros defined therein. 36 37 The output is a valid D file that can be compiled. 38 39 Params: 40 options = The runtime options. 41 */ 42 void preprocess(File)(in from!"dpp.runtime.options".Options options, 43 in string inputFileName, 44 in string outputFileName) 45 { 46 47 import dpp.runtime.context: Context; 48 import dpp.expansion: maybeExpand; 49 import std.algorithm: map, startsWith, filter; 50 import std.process: execute; 51 import std.exception: enforce; 52 import std.conv: text; 53 import std..string: splitLines; 54 import std.file: remove; 55 import std.array: replace; 56 57 const tmpFileName = outputFileName ~ ".tmp"; 58 scope(exit) if(!options.keepPreCppFile) remove(tmpFileName); 59 60 { 61 auto outputFile = File(tmpFileName, "w"); 62 63 outputFile.writeln(preamble); 64 65 /** 66 We remember the cursors already seen so as to not try and define 67 something twice (legal in C, illegal in D). 68 */ 69 auto context = Context(options.indent); 70 71 () @trusted { 72 foreach(immutable line; File(inputFileName).byLine.map!(a => cast(string)a)) { 73 // If the line is an #include directive, expand its translations "inline" 74 // into the context structure. 75 line.maybeExpand(context); 76 } 77 }(); 78 79 context.fixNames; 80 outputFile.writeln(context.translation); 81 } 82 83 const ret = execute(["cpp", tmpFileName]); 84 enforce(ret.status == 0, text("Could not run cpp on ", tmpFileName, ":\n", ret.output)); 85 86 { 87 auto outputFile = File(outputFileName, "w"); 88 auto lines = ret. 89 output 90 .splitLines 91 .filter!(a => !a.startsWith("#")) 92 ; 93 94 foreach(line; lines) { 95 outputFile.writeln(line); 96 } 97 } 98 } 99 100 101 private string preamble() @safe pure { 102 import std.array: replace, join; 103 import std.algorithm: filter; 104 import std..string: splitLines; 105 106 return q{ 107 108 import core.stdc.config; 109 import core.stdc.stdarg: va_list; 110 struct __locale_data { int dummy; } // FIXME 111 #define __gnuc_va_list va_list 112 alias _Bool = bool; 113 114 }.replace(" ", "").splitLines.filter!(a => a != "").join("\n"); 115 }