1 /** 2 Command-line options 3 */ 4 module dpp.runtime.options; 5 6 @safe: 7 8 version(Windows) 9 enum exeExtension = ".exe"; 10 else 11 enum exeExtension = ""; 12 13 14 struct Options { 15 16 enum usage = "Usage: d++ [options] [D compiler options] <filename.dpp> [D compiler args]"; 17 18 string[] dppFileNames; 19 string indentation; 20 bool debugOutput; 21 string[] includePaths; 22 bool keepPreCppFiles; 23 bool keepDlangFiles; 24 bool parseAsCpp; 25 bool preprocessOnly; 26 string dlangCompiler = "dmd"; 27 string[] dlangCompilerArgs; 28 string[] defines; 29 bool earlyExit; 30 bool hardFail; 31 bool cppStdLib; 32 33 this(string[] args) { 34 35 import clang: systemPaths; 36 import std.exception: enforce; 37 import std.path: stripExtension, extension, buildPath, absolutePath; 38 import std.file: tempDir; 39 import std.algorithm: map, filter, canFind, startsWith; 40 import std.array: array; 41 import std.conv: text; 42 43 parseArgs(args); 44 if(earlyExit) return; 45 46 if(preprocessOnly) 47 enforce(args.length == 2, 48 text("Wrong argument length. Expected 2, got ", args.length, 49 " for preprocessing only.\n", usage)); 50 else 51 enforce(args.length >= 2, "Not enough arguments\n" ~ usage); 52 53 dppFileNames = args.filter!(a => a.extension == ".dpp").array; 54 enforce(dppFileNames.length != 0, "No .dpp input file specified\n" ~ usage); 55 56 // Remove the name of this binary and the name of the .dpp input file from args 57 // so that a D compiler can use the remaining entries. 58 dlangCompilerArgs = 59 args[1..$].filter!(a => a.extension != ".dpp").array ~ 60 dFileNames; 61 62 // if no -of option is given, default to the name of the .dpp file 63 if(!dlangCompilerArgs.canFind!(a => a.startsWith("-of")) && !dlangCompilerArgs.canFind("-c")) 64 dlangCompilerArgs ~= "-of" ~ 65 args. 66 filter!(a => a.extension == ".dpp" || a.extension == ".d") 67 .front 68 .stripExtension 69 ~ exeExtension; 70 71 version(Windows) 72 assert(!cppStdLib, "C++ std lib functionality not implemented yet for Windows"); 73 74 if(cppStdLib) { 75 dlangCompilerArgs ~= "-L-lstdc++"; 76 } 77 78 includePaths = systemPaths ~ includePaths; 79 } 80 81 string[] dFileNames() @safe pure const { 82 import std.algorithm: map; 83 import std.array: array; 84 return dppFileNames.map!toDFileName.array; 85 } 86 87 static string toDFileName(in string dppFileName) @safe pure nothrow { 88 import std.path: stripExtension; 89 return dppFileName.stripExtension ~ ".d"; 90 } 91 92 private void parseArgs(ref string[] args) { 93 import std.getopt: getopt, defaultGetoptPrinter, config; 94 auto helpInfo = 95 getopt( 96 args, 97 config.passThrough, 98 "print-cursors", "Print debug information", &debugOutput, 99 "include-path", "Include paths", &includePaths, 100 "keep-pre-cpp-files", "Do not delete the temporary pre-preprocessed file", &keepPreCppFiles, 101 "keep-d-files", "Do not delete the temporary D file to be compiled", &keepDlangFiles, 102 "preprocess-only", "Only transform the .dpp file into a .d file, don't compile", &preprocessOnly, 103 "compiler", "D compiler to use", &dlangCompiler, 104 "parse-as-cpp", "Parse header as C++", &parseAsCpp, 105 "define", "C Preprocessor macro", &defines, 106 "hard-fail", "Translate nothing if any part fails", &hardFail, 107 "c++-std-lib", "Link to the C++ standard library", &cppStdLib, 108 ); 109 110 if(helpInfo.helpWanted) { 111 () @trusted { 112 defaultGetoptPrinter(usage, helpInfo.options); 113 }(); 114 earlyExit = true; 115 } 116 } 117 118 Options indent() pure nothrow const { 119 Options ret; 120 foreach(i, ref elt; ret.tupleof) { 121 static if(__traits(compiles, this.tupleof[i].dup)) 122 elt = this.tupleof[i].dup; 123 else 124 elt = this.tupleof[i]; 125 } 126 127 ret.includePaths = includePaths.dup; 128 ret.defines = defines.dup; 129 ret.indentation = indentation ~ " "; 130 131 return ret; 132 } 133 134 void log(T...)(auto ref T args) @trusted const { 135 version(unittest) import unit_threaded.io: writeln = writelnUt; 136 else import std.stdio: writeln; 137 138 version(unittest) enum shouldLog = true; 139 else const shouldLog = debugOutput; 140 141 if(shouldLog) 142 debug writeln(indentation, args); 143 } 144 }