72 } catch (IllegalArgumentException e) { |
56 } catch (IllegalArgumentException e) { |
73 Log.error(e.getMessage()); |
57 Log.error(e.getMessage()); |
74 return -1; |
58 return -1; |
75 } |
59 } |
76 |
60 |
77 Log.setLogLevel(options.getLogLevel()); |
|
78 |
|
79 if (!validateOptions(options)) |
|
80 return -1; |
|
81 |
|
82 if (!createIfMissing(options.getDestDir())) |
|
83 return -1; |
|
84 |
|
85 if (!createIfMissing(options.getStateDir())) |
|
86 return -1; |
|
87 |
|
88 Path gensrc = options.getGenSrcDir(); |
|
89 if (gensrc != null && !createIfMissing(gensrc)) |
|
90 return -1; |
|
91 |
|
92 Path hdrdir = options.getHeaderDir(); |
|
93 if (hdrdir != null && !createIfMissing(hdrdir)) |
|
94 return -1; |
|
95 |
|
96 Log.debug("=========================================================="); |
61 Log.debug("=========================================================="); |
97 Log.debug("Launching sjavac client with the following parameters:"); |
62 Log.debug("Launching sjavac client with the following parameters:"); |
98 Log.debug(" " + options.getStateArgsString()); |
63 Log.debug(" " + options.getStateArgsString()); |
99 Log.debug("=========================================================="); |
64 Log.debug("=========================================================="); |
100 |
65 |
101 // Load the prev build state database. |
66 // Prepare sjavac object |
102 JavacState javac_state = JavacState.load(options, out, err); |
67 boolean background = Util.extractBooleanOption("background", options.getServerConf(), true); |
103 |
68 Sjavac sjavac; |
104 // Setup the suffix rules from the command line. |
69 // Create an sjavac implementation to be used for compilation |
105 Map<String, Transformer> suffixRules = new HashMap<>(); |
70 if (background) { |
106 |
71 try { |
107 // Handling of .java-compilation |
72 sjavac = new SjavacClient(options); |
108 suffixRules.putAll(javac_state.getJavaSuffixRule()); |
73 } catch (PortFileInaccessibleException e) { |
109 |
74 Log.error("Port file inaccessible."); |
110 // Handling of -copy and -tr |
75 return -1; |
111 suffixRules.putAll(options.getTranslationRules()); |
76 } |
112 |
77 } else { |
113 // All found modules are put here. |
78 sjavac = new SjavacImpl(); |
114 Map<String,Module> modules = new HashMap<>(); |
|
115 // We start out in the legacy empty no-name module. |
|
116 // As soon as we stumble on a module-info.java file we change to that module. |
|
117 Module current_module = new Module("", ""); |
|
118 modules.put("", current_module); |
|
119 |
|
120 // Find all sources, use the suffix rules to know which files are sources. |
|
121 Map<String,Source> sources = new HashMap<>(); |
|
122 |
|
123 // Find the files, this will automatically populate the found modules |
|
124 // with found packages where the sources are found! |
|
125 findSourceFiles(options.getSources(), |
|
126 suffixRules.keySet(), |
|
127 sources, |
|
128 modules, |
|
129 current_module, |
|
130 options.isDefaultPackagePermitted(), |
|
131 false); |
|
132 |
|
133 if (sources.isEmpty()) { |
|
134 Log.error("Found nothing to compile!"); |
|
135 return -1; |
|
136 } |
79 } |
137 |
80 |
138 // Create a map of all source files that are available for linking. Both -src and |
81 CompilationResult cr = sjavac.compile(args); |
139 // -sourcepath point to such files. It is possible to specify multiple |
|
140 // -sourcepath options to enable different filtering rules. If the |
|
141 // filters are the same for multiple sourcepaths, they may be concatenated |
|
142 // using :(;). Before sending the list of sourcepaths to javac, they are |
|
143 // all concatenated. The list created here is used by the SmartFileWrapper to |
|
144 // make sure only the correct sources are actually available. |
|
145 // We might find more modules here as well. |
|
146 Map<String,Source> sources_to_link_to = new HashMap<>(); |
|
147 |
82 |
148 List<SourceLocation> sourceResolutionLocations = new ArrayList<>(); |
83 out.print(cr.stdout); |
149 sourceResolutionLocations.addAll(options.getSources()); |
84 err.print(cr.stderr); |
150 sourceResolutionLocations.addAll(options.getSourceSearchPaths()); |
|
151 findSourceFiles(sourceResolutionLocations, |
|
152 Collections.singleton(".java"), |
|
153 sources_to_link_to, |
|
154 modules, |
|
155 current_module, |
|
156 options.isDefaultPackagePermitted(), |
|
157 true); |
|
158 |
85 |
159 // Find all class files allowable for linking. |
86 if (!background) |
160 // And pickup knowledge of all modules found here. |
87 sjavac.shutdown(); |
161 // This cannot currently filter classes inside jar files. |
|
162 // Map<String,Source> classes_to_link_to = new HashMap<String,Source>(); |
|
163 // findFiles(args, "-classpath", Util.set(".class"), classes_to_link_to, modules, current_module, true); |
|
164 |
88 |
165 // Find all module sources allowable for linking. |
89 return cr.returnCode; |
166 // Map<String,Source> modules_to_link_to = new HashMap<String,Source>(); |
|
167 // findFiles(args, "-modulepath", Util.set(".class"), modules_to_link_to, modules, current_module, true); |
|
168 |
|
169 // Add the set of sources to the build database. |
|
170 javac_state.now().flattenPackagesSourcesAndArtifacts(modules); |
|
171 javac_state.now().checkInternalState("checking sources", false, sources); |
|
172 javac_state.now().checkInternalState("checking linked sources", true, sources_to_link_to); |
|
173 javac_state.setVisibleSources(sources_to_link_to); |
|
174 |
|
175 int round = 0; |
|
176 printRound(round); |
|
177 |
|
178 // If there is any change in the source files, taint packages |
|
179 // and mark the database in need of saving. |
|
180 javac_state.checkSourceStatus(false); |
|
181 |
|
182 // Find all existing artifacts. Their timestamp will match the last modified timestamps stored |
|
183 // in javac_state, simply because loading of the JavacState will clean out all artifacts |
|
184 // that do not match the javac_state database. |
|
185 javac_state.findAllArtifacts(); |
|
186 |
|
187 // Remove unidentified artifacts from the bin, gensrc and header dirs. |
|
188 // (Unless we allow them to be there.) |
|
189 // I.e. artifacts that are not known according to the build database (javac_state). |
|
190 // For examples, files that have been manually copied into these dirs. |
|
191 // Artifacts with bad timestamps (ie the on disk timestamp does not match the timestamp |
|
192 // in javac_state) have already been removed when the javac_state was loaded. |
|
193 if (!options.areUnidentifiedArtifactsPermitted()) { |
|
194 javac_state.removeUnidentifiedArtifacts(); |
|
195 } |
|
196 // Go through all sources and taint all packages that miss artifacts. |
|
197 javac_state.taintPackagesThatMissArtifacts(); |
|
198 |
|
199 // Check recorded classpath public apis. Taint packages that depend on |
|
200 // classpath classes whose public apis have changed. |
|
201 javac_state.taintPackagesDependingOnChangedClasspathPackages(); |
|
202 |
|
203 // Now clean out all known artifacts belonging to tainted packages. |
|
204 javac_state.deleteClassArtifactsInTaintedPackages(); |
|
205 // Copy files, for example property files, images files, xml files etc etc. |
|
206 javac_state.performCopying(Util.pathToFile(options.getDestDir()), suffixRules); |
|
207 // Translate files, for example compile properties or compile idls. |
|
208 javac_state.performTranslation(Util.pathToFile(gensrc), suffixRules); |
|
209 // Add any potentially generated java sources to the tobe compiled list. |
|
210 // (Generated sources must always have a package.) |
|
211 Map<String,Source> generated_sources = new HashMap<>(); |
|
212 |
|
213 try { |
|
214 |
|
215 Source.scanRoot(Util.pathToFile(options.getGenSrcDir()), Util.set(".java"), null, null, null, null, |
|
216 generated_sources, modules, current_module, false, true, false); |
|
217 javac_state.now().flattenPackagesSourcesAndArtifacts(modules); |
|
218 // Recheck the the source files and their timestamps again. |
|
219 javac_state.checkSourceStatus(true); |
|
220 |
|
221 // Now do a safety check that the list of source files is identical |
|
222 // to the list Make believes we are compiling. If we do not get this |
|
223 // right, then incremental builds will fail with subtility. |
|
224 // If any difference is detected, then we will fail hard here. |
|
225 // This is an important safety net. |
|
226 javac_state.compareWithMakefileList(Util.pathToFile(options.getSourceReferenceList())); |
|
227 |
|
228 // Do the compilations, repeatedly until no tainted packages exist. |
|
229 boolean again; |
|
230 // Collect the name of all compiled packages. |
|
231 Set<String> recently_compiled = new HashSet<>(); |
|
232 boolean[] rc = new boolean[1]; |
|
233 boolean background = Util.extractBooleanOption("background", options.getServerConf(), true); |
|
234 Sjavac sjavac; |
|
235 // Create an sjavac implementation to be used for compilation |
|
236 if (background) { |
|
237 sjavac = new SjavacClient(options); |
|
238 } else { |
|
239 int poolsize = Util.extractIntOption("poolsize", options.getServerConf()); |
|
240 if (poolsize <= 0) |
|
241 poolsize = Runtime.getRuntime().availableProcessors(); |
|
242 sjavac = new PooledSjavac(new SjavacImpl(), poolsize); |
|
243 } |
|
244 |
|
245 do { |
|
246 if (round > 0) |
|
247 printRound(round); |
|
248 // Clean out artifacts in tainted packages. |
|
249 javac_state.deleteClassArtifactsInTaintedPackages(); |
|
250 again = javac_state.performJavaCompilations(sjavac, options, recently_compiled, rc); |
|
251 if (!rc[0]) { |
|
252 Log.debug("Compilation failed."); |
|
253 break; |
|
254 } |
|
255 if (!again) { |
|
256 Log.debug("Nothing left to do."); |
|
257 } |
|
258 round++; |
|
259 } while (again); |
|
260 Log.debug("No need to do another round."); |
|
261 |
|
262 // Only update the state if the compile went well. |
|
263 if (rc[0]) { |
|
264 javac_state.save(); |
|
265 // Reflatten only the artifacts. |
|
266 javac_state.now().flattenArtifacts(modules); |
|
267 // Remove artifacts that were generated during the last compile, but not this one. |
|
268 javac_state.removeSuperfluousArtifacts(recently_compiled); |
|
269 } |
|
270 if (!background) |
|
271 sjavac.shutdown(); |
|
272 |
|
273 return rc[0] ? 0 : -1; |
|
274 } catch (ProblemException e) { |
|
275 Log.error(e.getMessage()); |
|
276 return -1; |
|
277 } catch (Exception e) { |
|
278 e.printStackTrace(err); |
|
279 return -1; |
|
280 } |
|
281 } |
90 } |
282 |
|
283 private static boolean validateOptions(Options options) { |
|
284 |
|
285 String err = null; |
|
286 |
|
287 if (options.getDestDir() == null) { |
|
288 err = "Please specify output directory."; |
|
289 } else if (options.isJavaFilesAmongJavacArgs()) { |
|
290 err = "Sjavac does not handle explicit compilation of single .java files."; |
|
291 } else if (options.getServerConf() == null) { |
|
292 err = "No server configuration provided."; |
|
293 } else if (!options.getImplicitPolicy().equals("none")) { |
|
294 err = "The only allowed setting for sjavac is -implicit:none"; |
|
295 } else if (options.getSources().isEmpty()) { |
|
296 err = "You have to specify -src."; |
|
297 } else if (options.getTranslationRules().size() > 1 |
|
298 && options.getGenSrcDir() == null) { |
|
299 err = "You have translators but no gensrc dir (-s) specified!"; |
|
300 } |
|
301 |
|
302 if (err != null) |
|
303 Log.error(err); |
|
304 |
|
305 return err == null; |
|
306 |
|
307 } |
|
308 |
|
309 private static boolean createIfMissing(Path dir) { |
|
310 |
|
311 if (Files.isDirectory(dir)) |
|
312 return true; |
|
313 |
|
314 if (Files.exists(dir)) { |
|
315 Log.error(dir + " is not a directory."); |
|
316 return false; |
|
317 } |
|
318 |
|
319 try { |
|
320 Files.createDirectories(dir); |
|
321 } catch (IOException e) { |
|
322 Log.error("Could not create directory: " + e.getMessage()); |
|
323 return false; |
|
324 } |
|
325 |
|
326 return true; |
|
327 } |
|
328 |
|
329 |
|
330 /** Find source files in the given source locations. */ |
|
331 public static void findSourceFiles(List<SourceLocation> sourceLocations, |
|
332 Set<String> sourceTypes, |
|
333 Map<String,Source> foundFiles, |
|
334 Map<String, Module> foundModules, |
|
335 Module currentModule, |
|
336 boolean permitSourcesInDefaultPackage, |
|
337 boolean inLinksrc) { |
|
338 |
|
339 for (SourceLocation source : sourceLocations) { |
|
340 source.findSourceFiles(sourceTypes, |
|
341 foundFiles, |
|
342 foundModules, |
|
343 currentModule, |
|
344 permitSourcesInDefaultPackage, |
|
345 inLinksrc); |
|
346 } |
|
347 } |
|
348 |
|
349 private static void printRound(int round) { |
|
350 Log.debug("****************************************"); |
|
351 Log.debug("* Round " + round + " *"); |
|
352 Log.debug("****************************************"); |
|
353 } |
|
354 |
|
355 } |
91 } |