1 module dbuild.target; 2 3 4 /// A target to be checked for, to possibly bypass the build 5 abstract class Target 6 { 7 /// target name 8 string name; 9 /// files used to build the artifacts in the src dir 10 string[] srcFiles; 11 /// full path to the target artifact 12 string artifact; 13 14 private this(string name, string[] srcFiles) 15 { 16 this.name = name; 17 this.srcFiles = srcFiles; 18 } 19 20 /// resolve the target file in the install dir, and set the targetPath field 21 abstract void resolveArtifact(in string installDir); 22 23 /// Check if the target is up-to-date vs the provided src files. 24 /// Returns: true if the target is up-to-date, false if it needs rebuild 25 bool check(in string srcDir) 26 { 27 import std.algorithm : map; 28 import std.exception : enforce; 29 import std.file : exists, isFile, timeLastModified; 30 import std.path : buildPath; 31 32 if (!artifact.length) return false; 33 34 if (!exists(artifact) || !isFile(artifact)) { 35 return false; 36 } 37 38 const artifactTime = timeLastModified(artifact); 39 40 foreach (sf; srcFiles.map!(f => srcDir.buildPath(f))) { 41 enforce(exists(sf) && isFile(sf), sf~": No such file!"); 42 43 if (timeLastModified(sf) > artifactTime) { 44 return false; 45 } 46 } 47 48 return true; 49 } 50 } 51 52 Target fileTarget(string name, string[] srcFiles=null) 53 { 54 return new FileTarget(name, srcFiles); 55 } 56 57 Target libTarget(string name, string[] srcFiles=null) 58 { 59 return new LibTarget(name, srcFiles); 60 } 61 62 private: 63 64 class FileTarget : Target 65 { 66 this(string name, string[] srcFiles) 67 { 68 super(name, srcFiles); 69 } 70 71 override void resolveArtifact(in string installDir) 72 { 73 import std.path : buildPath; 74 75 artifact = buildPath(installDir, name); 76 } 77 } 78 79 class LibTarget : Target 80 { 81 this (string name, string[] srcFiles) 82 { 83 super(name, srcFiles); 84 } 85 86 override void resolveArtifact(in string installDir) 87 { 88 // looking for a file that can be a library of name "target" 89 // e.g. libtarget.a, libtarget.so, target.lib, etc. 90 import std.algorithm : any, canFind; 91 import std.file : exists, isFile; 92 import std.range : only; 93 import std.path : buildPath; 94 95 bool testFile(in string path) { 96 if (exists(path) && isFile(path)) { 97 artifact = path; 98 return true; 99 } 100 else { 101 return false; 102 } 103 } 104 105 // the directories and file extensions to look for 106 const libDir = buildPath(installDir, "lib"); 107 const lib64Dir = buildPath(installDir, "lib64"); 108 const binDir = buildPath(installDir, "bin"); 109 110 // if name already has an extension (may be with version behind) 111 // we try to look only for exact filename in a few directories 112 string[] exts = [".a"]; 113 version(Posix) { 114 exts ~= [".so"]; 115 } 116 else version(Windows) { 117 exts ~= [".lib", ".dll"]; 118 } 119 else { 120 static assert(false); 121 } 122 123 if (exts.any!(e => name.canFind(e))) { 124 foreach (sd; only(installDir, libDir, lib64Dir, binDir)) { 125 if (testFile(buildPath(sd, name))) break; 126 } 127 return; 128 } 129 130 // testing now for standard names 131 const libnamea = "lib"~name~".a"; 132 auto search = [ 133 buildPath(libDir, libnamea), buildPath(lib64Dir, libnamea) 134 ]; 135 version(Posix) { 136 const libnameso = "lib"~name~".so"; 137 search ~= [ buildPath(libDir, libnameso), buildPath(lib64Dir, libnameso) ]; 138 } 139 else version(Windows) { 140 const namelib = name~".lib"; 141 const namedll = name~".dll"; 142 const libnamedlla = "lib"~name~".dll.a"; 143 search ~= [ 144 buildPath(libDir, namelib), buildPath(lib64Dir, namelib), 145 buildPath(libDir, libnamedlla), buildPath(lib64Dir, libnamedlla), 146 buildPath(binDir, namedll) 147 ]; 148 } 149 150 foreach(s; search) { 151 if (testFile(s)) break; 152 } 153 } 154 }