1 module reggae.backend.make; 2 3 import reggae.build; 4 import reggae.range; 5 import reggae.rules; 6 import reggae.config; 7 8 import std.conv; 9 import std.array; 10 import std.path; 11 import std.algorithm; 12 13 14 struct Makefile { 15 Build build; 16 string projectPath; 17 18 this(Build build) @safe pure { 19 this.build = build; 20 this.projectPath = ""; 21 } 22 23 this(Build build, string projectPath) @safe pure { 24 this.build = build; 25 this.projectPath = projectPath; 26 } 27 28 string fileName() @safe pure nothrow const { 29 return "Makefile"; 30 } 31 32 //only the main targets 33 string simpleOutput() @safe const { 34 35 const outputs = build.targets.map!(a => a.outputs[0]).join(" "); 36 auto ret = text("all: ", outputs, "\n"); 37 38 foreach(topTarget; build.targets) { 39 foreach(t; DepthFirst(topTarget)) { 40 41 mkDir(t); 42 43 ret ~= text(t.outputs.join(" "), ": "); 44 ret ~= t.dependencyFilesString(projectPath); 45 immutable implicitFiles = t.implicitFilesString(projectPath); 46 if(!implicitFiles.empty) ret ~= " " ~ t.implicitFilesString(projectPath); 47 ret ~= " Makefile\n"; 48 49 ret ~= "\t" ~ command(t) ~ "\n"; 50 } 51 } 52 53 return ret; 54 } 55 56 //includes rerunning reggae 57 string output() @safe const { 58 auto ret = simpleOutput; 59 ret ~= "Makefile: " ~ buildFilePath ~ " " ~ reggaePath ~ "\n"; 60 immutable _dflags = dflags == "" ? "" : " --dflags='" ~ dflags ~ "'"; 61 ret ~= "\t" ~ reggaePath ~ " -b make" ~ _dflags ~ " " ~ projectPath ~ "\n"; 62 63 return ret; 64 } 65 66 private void mkDir(in Target target) @trusted const { 67 foreach(output; target.outputs) { 68 import std.file; 69 if(!output.dirName.exists) mkdirRecurse(output.dirName); 70 } 71 } 72 73 //the only reason this is needed is to add auto dependency 74 //tracking 75 string command(in Target target) @safe const { 76 immutable cmd = target.shellCommand(projectPath); 77 immutable depfile = target.outputs[0] ~ ".dep"; 78 79 immutable rawCmdLine = target.rawCmdString(projectPath); 80 81 if(rawCmdLine.isDefaultCommand) { 82 immutable rule = rawCmdLine.getDefaultRule; 83 return rule.canFind("compile") ? cmd ~ makeAutoDeps(depfile) : cmd; 84 } else { 85 return cmd; 86 } 87 } 88 } 89 90 91 //For explanation of the crazy Makefile commands, see: 92 //http://stackoverflow.com/questions/8025766/makefile-auto-dependency-generation 93 //http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/ 94 private string makeAutoDeps(in string depfile) @safe pure nothrow { 95 immutable pFile = depfile ~ ".P"; 96 return "\n\t@cp " ~ depfile ~ " " ~ pFile ~ "; \\\n" ~ 97 " sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \\\n" ~ 98 " -e '/^$$/ d' -e 's/$$/ :/' < " ~ depfile ~ " >> " ~ pFile ~"; \\\n" ~ 99 " rm -f " ~ depfile ~ "\n\n" ~ 100 "-include " ~ pFile ~ "\n\n"; 101 }