1// tRule.cpp 
2// 
3// The base class for a rule. Rules support functionality such as setting targets/dependencies, and checking if the 
4// build rule is out of date. 
5// 
6// Copyright (c) 2006, 2017 Tristan Grimmer. 
7// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby 
8// granted, provided that the above copyright notice and this permission notice appear in all copies. 
9// 
10// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 
11// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 
12// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
13// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
14// PERFORMANCE OF THIS SOFTWARE. 
15 
16#include <System/tThrow.h> 
17#include <System/tPrint.h> 
18#include <System/tFile.h> 
19#include "Pipeline/tRule.h" 
20#ifdef PLATFORM_WINDOWS 
21#include "Pipeline/tSolution.h" 
22#endif 
23using namespace tPipeline
24 
25 
26tRuleError::tRuleError(const char* format, ...) : 
27 tError("[tRule] "
28
29 va_list marker
30 va_start(marker, format); 
31 Message += tvsPrintf(Message, format, marker); 
32
33 
34 
35void tRule::SetTarget(const tString& target
36
37 while (tStringItem* s = Dependencies.Remove()) 
38 delete s
39 
40 Target = target
41
42 
43 
44bool tRule::MaybeAddToDependenciesCaseInsensitive(const tString& dep
45
46 // This function only adds to the dependency list if the file in question hasn't already been added. 
47 // @todo Does not support changing between relative and absolute. 
48 if (dep.IsEmpty()) 
49 return false
50 
51 tString lowCase = dep
52 lowCase.Replace('\\', '/'); 
53 lowCase.LowCase(); 
54 
55 for (tStringItem* s = Dependencies.First(); s; s = s->Next()) 
56
57 tString lowCasePresent = *s
58 lowCasePresent.Replace('\\', '/'); 
59 lowCasePresent.LowCase(); 
60 
61 if (lowCase == lowCasePresent
62 return false
63
64 
65 // If we get here the file hasn't already been added... so we add it now. 
66 Dependencies.Append(new tStringItem(dep)); 
67 return true
68
69 
70 
71void tRule::AddDependency(const tString& dep
72
73 if (!tSystem::tFileExists(dep)) 
74 throw tRuleError("Cannot add dependency [%s]", dep.Pod()); 
75 
76 MaybeAddToDependenciesCaseInsensitive(dep); 
77
78 
79 
80 
81void tRule::AddDependency(tStringItem* dep
82
83 if (!tSystem::tFileExists(*dep)) 
84 throw tRuleError("Cannot add dependency [%s]", dep->Pod()); 
85 
86 MaybeAddToDependenciesCaseInsensitive(*dep); 
87
88 
89 
90void tRule::AddDependencies(tList<tStringItem>& deps
91
92 bool success = true
93 
94 tString badDependency
95 while (tStringItem* dep = deps.Remove()) 
96
97 if (!tSystem::tFileExists(*dep)) 
98
99 success = false
100 badDependency = *dep
101 delete dep
102
103 else 
104
105 MaybeAddToDependenciesCaseInsensitive(*dep); 
106
107
108 
109 if (!success
110 throw tRuleError("Cannot add dependency [%s]", badDependency.Chars()); 
111
112 
113 
114void tRule::AddDependencyDir(const tString& dir, const tString& ext
115
116 tList<tStringItem> deps
117 bool includeHidden = false
118 tSystem::tFindFiles(deps, dir, ext, includeHidden); 
119 
120 AddDependencies(deps); 
121 tAssert(deps.IsEmpty()); 
122
123 
124 
125void tRule::AddDependencyDirRec(const tString& dir, const tString& ext
126
127 tList<tStringItem> deps
128 bool includeHidden = false
129 tSystem::tFindFilesRecursive(deps, dir, ext, includeHidden); 
130 
131 AddDependencies(deps); 
132 tAssert(deps.IsEmpty()); 
133
134 
135 
136bool tRule::OutOfDate(bool checkClean
137
138 // Returns true if target has been specified and target doesn't exist or is older than any dependency. 
139 // Also returns false if any dep doesn't exist. 
140 if (Target.IsEmpty()) 
141 return false
142 
143 tStringItem* dep = Dependencies.First(); 
144 while (dep
145
146 if (!tSystem::tFileExists(*dep)) 
147 throw tRuleError("Cannot find dependency [%s] while targetting [%s].", dep->ConstText(), Target.ConstText()); 
148 
149 dep = dep->Next(); 
150
151 
152 if (!tSystem::tFileExists(Target)) 
153 return true
154 
155 if (checkClean && Clean
156 return true
157 
158 dep = Dependencies.First(); 
159 while (dep
160
161 if (tSystem::tIsFileNewer(*dep, Target)) 
162 return true
163 
164 dep = dep->Next(); 
165
166 
167 return false
168
169