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 bool ignoreMacros; 33 bool detailedUntranslatable; 34 string[] ignoredNamespaces; 35 string[] ignoredCursors; 36 bool alwaysScopedEnums; 37 string cppStandard = "c++17"; 38 string[] clangOptions; 39 40 this(string[] args) { 41 42 import clang: systemPaths; 43 import std.exception: enforce; 44 import std.path: stripExtension, extension, buildPath, absolutePath; 45 import std.file: tempDir; 46 import std.algorithm: map, filter, canFind, startsWith; 47 import std.array: array; 48 import std.conv: text; 49 50 parseArgs(args); 51 if(earlyExit) return; 52 53 if(preprocessOnly) 54 keepDlangFiles = true; 55 56 dppFileNames = args.filter!(a => a.extension == ".dpp").array; 57 enforce(dppFileNames.length != 0, "No .dpp input file specified\n" ~ usage); 58 59 // Remove the name of this binary and the name of the .dpp input file from args 60 // so that a D compiler can use the remaining entries. 61 dlangCompilerArgs = 62 args[1..$].filter!(a => a.extension != ".dpp").array ~ 63 dFileNames; 64 65 // if no -of option is given, default to the name of the .dpp file 66 if(!dlangCompilerArgs.canFind!(a => a.startsWith("-of")) && !dlangCompilerArgs.canFind("-c")) 67 dlangCompilerArgs ~= "-of" ~ 68 args. 69 filter!(a => a.extension == ".dpp" || a.extension == ".d") 70 .front 71 .stripExtension 72 ~ exeExtension; 73 74 version(Windows) 75 assert(!cppStdLib, "C++ std lib functionality not implemented yet for Windows"); 76 77 if(cppStdLib) { 78 dlangCompilerArgs ~= "-L-lstdc++"; 79 parseAsCpp = true; 80 } 81 82 includePaths = systemPaths ~ includePaths; 83 } 84 85 string[] dFileNames() @safe pure const { 86 import std.algorithm: map; 87 import std.array: array; 88 return dppFileNames.map!toDFileName.array; 89 } 90 91 static string toDFileName(in string dppFileName) @safe pure nothrow { 92 import std.path: stripExtension; 93 return dppFileName.stripExtension ~ ".d"; 94 } 95 96 private void parseArgs(ref string[] args) { 97 import std.getopt: getopt, defaultGetoptPrinter, config; 98 auto helpInfo = 99 getopt( 100 args, 101 config.passThrough, 102 "print-cursors", "Print debug information", &debugOutput, 103 "include-path", "Include paths", &includePaths, 104 "keep-pre-cpp-files", "Do not delete the temporary pre-preprocessed file", &keepPreCppFiles, 105 "keep-d-files", "Do not delete the temporary D file to be compiled", &keepDlangFiles, 106 "preprocess-only", "Only transform the .dpp file into a .d file, don't compile", &preprocessOnly, 107 "compiler", "D compiler to use", &dlangCompiler, 108 "parse-as-cpp", "Parse header as C++", &parseAsCpp, 109 "define", "C Preprocessor macro", &defines, 110 "hard-fail", "Translate nothing if any part fails", &hardFail, 111 "c++-std-lib", "Link to the C++ standard library", &cppStdLib, 112 "ignore-macros", "Ignore preprocessor macros", &ignoreMacros, 113 "ignore-ns", "Ignore a C++ namespace", &ignoredNamespaces, 114 "ignore-cursor", "Ignore a C++ cursor", &ignoredCursors, 115 "detailed-untranslatables", "Show details about untranslatable cursors", &detailedUntranslatable, 116 "scoped-enums", "Don't redeclare enums to mimic C", &alwaysScopedEnums, 117 "c++-standard", "The C++ language standard (e.g. \"c++14\")", &cppStandard, 118 "clang-option", "Pass option to libclang", &clangOptions, 119 ); 120 121 if(helpInfo.helpWanted) { 122 () @trusted { 123 defaultGetoptPrinter(usage, helpInfo.options); 124 }(); 125 earlyExit = true; 126 } 127 } 128 129 Options indent() pure nothrow const { 130 Options ret; 131 foreach(i, ref elt; ret.tupleof) { 132 static if(__traits(compiles, this.tupleof[i].dup)) 133 elt = this.tupleof[i].dup; 134 else 135 elt = this.tupleof[i]; 136 } 137 138 ret.includePaths = includePaths.dup; 139 ret.defines = defines.dup; 140 ret.indentation = indentation ~ " "; 141 142 return ret; 143 } 144 145 void log(T...)(auto ref T args) @trusted const { 146 version(unittest) import unit_threaded.io: writeln = writelnUt; 147 else import std.stdio: writeln; 148 149 version(unittest) enum shouldLog = true; 150 else const shouldLog = debugOutput; 151 152 if(shouldLog) 153 debug writeln(indentation, args); 154 } 155 }