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 }