1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.objectweb.fractal.cecilia.adl.compiler.gnu;
25
26 import java.io.BufferedReader;
27 import java.io.File;
28 import java.io.FileReader;
29 import java.io.IOException;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.List;
33 import java.util.logging.Level;
34
35 import org.objectweb.fractal.adl.ADLException;
36 import org.objectweb.fractal.cecilia.adl.file.SourceFile;
37 import org.objectweb.fractal.cecilia.adl.directives.DirectiveHelper;
38
39 public class GnuDepCompilerTask extends GnuCompilerTask {
40
41
42 protected static final String DEPENDENCY_EXTENSION = ".d";
43
44
45
46
47
48
49
50
51
52
53
54 public GnuDepCompilerTask(final String gccCommand, final File outputDir,
55 final List<String> flags) {
56 super(gccCommand, outputDir, flags);
57 }
58
59
60
61
62
63 @Override
64 protected void compile(final SourceFile sourceFile, final File outputFile)
65 throws ADLException, InterruptedException {
66 final File depFile = getDependencyFile(outputFile);
67 List<String> newFlags = new ArrayList<String>();
68
69 if (needRecompile(outputFile, depFile)) {
70 newFlags.add("-MMD");
71 newFlags.add("-MF");
72 newFlags.add(depFile.toString());
73 newFlags.addAll(flags);
74 flags = newFlags;
75 super.compile(sourceFile, outputFile);
76 }
77 }
78
79
80
81
82
83 protected File getDependencyFile(final File outputFile) {
84 String name = outputFile.getName();
85 name = name.substring(0, name.lastIndexOf('.')) + DEPENDENCY_EXTENSION;
86 return new File(outputFile.getParent(), name);
87 }
88
89 protected boolean needRecompile(final File outputFile,
90 final File dependencyFile) {
91
92 if (!outputFile.exists()) {
93 if (depLogger.isLoggable(Level.FINE))
94 depLogger.fine("Output file '" + outputFile
95 + "' does not exist, compile it.");
96 return true;
97 }
98 final long outputTimestamp = outputFile.lastModified();
99 if (outputTimestamp == 0) {
100 if (depLogger.isLoggable(Level.WARNING))
101 depLogger.warning("Unable to determine timestamp of file '"
102 + outputFile + "', recompile.");
103 return true;
104 }
105
106 if (!dependencyFile.exists()) {
107 if (depLogger.isLoggable(Level.FINE))
108 depLogger.fine("Dependency file of '" + outputFile
109 + "' does not exist, recompile.");
110 return true;
111 }
112
113 final Collection<File> depFiles = getDependencies(dependencyFile,
114 outputFile);
115
116
117 if (depFiles == null) return true;
118
119 for (final File depfile : depFiles) {
120 if (!depfile.exists()) {
121 if (ioLogger.isLoggable(Level.FINE))
122 ioLogger.fine("Warning input file '" + depfile + " does not exist.");
123 } else if (depfile.lastModified() > outputTimestamp) {
124 if (depLogger.isLoggable(Level.FINE))
125 depLogger.fine("Input file '" + depfile
126 + " is more recent than output file '" + outputFile
127 + "', recompile.");
128 return true;
129 }
130 }
131
132 if (depLogger.isLoggable(Level.FINE))
133 depLogger.fine("Output file '" + outputFile
134 + "' is up to date, do not recompile.");
135 return false;
136 }
137
138 protected Collection<File> getDependencies(final File dependencyFile,
139 final File outputFile) {
140 if (depLogger.isLoggable(Level.FINEST)) {
141 depLogger.finest("Parsing dependency file \"" + dependencyFile + "\"...");
142 }
143 final List<Rule> rules = parseRules(dependencyFile);
144 if (depLogger.isLoggable(Level.FINEST)) {
145 depLogger.finest("Parsed rules=" + rules);
146 }
147
148 for (final Rule rule : rules) {
149 final File targetFile = new File(rule.target);
150 if (depLogger.isLoggable(Level.FINEST)) {
151 depLogger.finest("rule target file is \"" + targetFile + "\".");
152 }
153
154
155
156
157 if (!outputFile.equals(targetFile)
158 && !new File(outputFile.getName()).equals(targetFile)) {
159 if (depLogger.isLoggable(Level.FINEST)) {
160 depLogger
161 .finest("target file does not match \"" + outputFile + "\".");
162 }
163 continue;
164 }
165
166 final List<File> dependentFiles = new ArrayList<File>();
167 for (final String dependency : rule.dependencies) {
168 if (dependency.length() == 0) continue;
169 dependentFiles.add(new File(dependency));
170 }
171 return dependentFiles;
172 }
173
174 depLogger.warning("Invalid dependency file \"" + dependencyFile
175 + "\". Can't find a rule for file \"" + outputFile + "\"");
176 return null;
177 }
178
179 protected List<Rule> parseRules(final File dependencyFile) {
180 final List<Rule> rules = new ArrayList<Rule>();
181 try {
182 final BufferedReader reader = new BufferedReader(new FileReader(
183 dependencyFile));
184 String line = null, rule = "";
185 while ((line = reader.readLine()) != null) {
186 if (line.endsWith("\\")) {
187 rule += line.substring(0, line.length() - 1);
188 } else {
189 rule += line.trim();
190
191
192 if (rule.length() > 0) {
193 rules.add(new Rule(rule));
194 rule = "";
195 }
196 }
197 }
198 if (rule.length() > 0) rules.add(new Rule(rule));
199 } catch (final IOException e) {
200 depLogger.log(Level.WARNING, "An error occurs while reading \""
201 + dependencyFile + "\".", e);
202 }
203 return rules;
204 }
205
206 static final class Rule {
207 String target;
208 List<String> dependencies;
209
210 Rule(final String rule) {
211 final String[] parts = rule.split(":\\s+");
212 if (parts.length != 2) {
213 throw new IllegalArgumentException("Can't find rule target");
214 }
215 target = parts[0].trim();
216
217 target = DirectiveHelper.splitOptionString(target).get(0);
218 dependencies = new ArrayList<String>();
219
220 for (final String dependency : DirectiveHelper.splitOptionString(parts[1])) {
221 if (dependency.length() > 0) dependencies.add(dependency);
222 }
223 }
224 }
225 }