@@ -64,8 +64,10 @@ public EclipseJavaCompiler()
64
64
public CompilerResult performCompile (CompilerConfiguration config )
65
65
throws CompilerException
66
66
{
67
- // Build settings from configuration
68
67
List <String > args = new ArrayList <>();
68
+ args .add ("-noExit" ); // Make sure ecj does not System.exit on us 8-/
69
+
70
+ // Build settings from configuration
69
71
if ( config .isDebug () )
70
72
{
71
73
args .add ("-preserveAllLocals" );
@@ -146,13 +148,44 @@ else if(extras.containsKey("-errorsAsWarnings"))
146
148
147
149
for (Entry <String , String > entry : extras .entrySet ())
148
150
{
151
+ /*
152
+ * The compiler mojo makes quite a mess of passing arguments, depending on exactly WHICH
153
+ * way is used to pass them. The method method using <compilerArguments> uses the tag names
154
+ * of its contents to denote option names, and so the compiler mojo happily adds a '-' to
155
+ * all of the names there and adds them to the "custom compiler arguments" map as a
156
+ * name, value pair where the name always contains a single '-'. The Eclipse compiler (and
157
+ * javac too, btw) has options with two dashes (like --add-modules for java 9). These cannot
158
+ * be passed using a <compilerArguments> tag.
159
+ *
160
+ * The other method is to use <compilerArgs>, where each SINGLE argument needs to be passed
161
+ * using an <arg>xxxx</arg> tag. In there the xxx is not manipulated by the compiler mojo, so
162
+ * if it starts with a dash or more dashes these are perfectly preserved. But of course these
163
+ * single <arg> entries are not a pair. So the compiler mojo adds them as pairs of (xxxx, null).
164
+ *
165
+ * We use that knowledge here: if a pair has a null value then do not mess up the key but
166
+ * render it as a single value. This should ensure that something like:
167
+ * <compilerArgs>
168
+ * <arg>--add-modules</arg>
169
+ * <arg>java.se.ee</arg>
170
+ * </compilerArgs>
171
+ *
172
+ * is actually added to the command like as such.
173
+ *
174
+ * (btw: the above example will still give an error when using ecj <= 4.8M6:
175
+ * invalid module name: java.se.ee
176
+ * but that seems to be a bug in ecj).
177
+ */
149
178
String opt = entry .getKey ();
150
- if (! opt .startsWith ("-" ))
151
- opt = "-" + opt ; // compiler mojo apparently messes with this; make sure we are safe
152
- args .add (opt );
153
- String value = entry .getValue ();
154
- if (null != value && ! value .isEmpty ())
155
- args .add (value );
179
+ String optionValue = entry .getValue ();
180
+ if (null == optionValue ) {
181
+ //-- We have an option from compilerArgs: use the key as-is as a single option value
182
+ args .add (opt );
183
+ } else {
184
+ if (!opt .startsWith ("-" ))
185
+ opt = "-" + opt ;
186
+ args .add (opt );
187
+ args .add (optionValue );
188
+ }
156
189
}
157
190
158
191
// Output path
@@ -209,65 +242,102 @@ else if(extras.containsKey("-errorsAsWarnings"))
209
242
210
243
// Compile! Send all errors to xml temp file.
211
244
File errorF = null ;
212
- try {
245
+ try
246
+ {
213
247
errorF = File .createTempFile ("ecjerr-" , ".xml" );
214
248
215
249
args .add ("-log" );
216
250
args .add (errorF .toString ());
217
251
218
252
// Add all sources.
219
253
int argCount = args .size ();
220
- for (String source : config .getSourceLocations ()) {
254
+ for (String source : config .getSourceLocations ())
255
+ {
221
256
File srcFile = new File (source );
222
- if (srcFile .exists ()) {
223
- Set <String > ss = getSourceFilesForSourceRoot ( config , source );
257
+ if (srcFile .exists ())
258
+ {
259
+ Set <String > ss = getSourceFilesForSourceRoot (config , source );
224
260
args .addAll (ss );
225
261
}
226
262
}
227
263
args .addAll (extraSourceDirs );
228
- if (args .size () == argCount ) {
264
+ if (args .size () == argCount )
265
+ {
229
266
//-- Nothing to do -> bail out
230
267
return new CompilerResult (true , Collections .EMPTY_LIST );
231
268
}
232
269
270
+ getLogger ().debug ("ecj command line: " + args );
271
+
233
272
StringWriter sw = new StringWriter ();
234
273
PrintWriter devNull = new PrintWriter (sw );
235
274
236
275
//BatchCompiler.compile(args.toArray(new String[args.size()]), new PrintWriter(System.err), new PrintWriter(System.out), new CompilationProgress() {
237
- BatchCompiler .compile (args .toArray (new String [args .size ()]), devNull , devNull , new CompilationProgress () {
238
- @ Override public void begin (int i ) {
276
+ boolean success = BatchCompiler .compile (args .toArray (new String [args .size ()]), devNull , devNull , new CompilationProgress () {
277
+ @ Override
278
+ public void begin (int i )
279
+ {
239
280
}
240
281
241
- @ Override public void done () {
282
+ @ Override
283
+ public void done ()
284
+ {
242
285
}
243
286
244
- @ Override public boolean isCanceled () {
287
+ @ Override
288
+ public boolean isCanceled ()
289
+ {
245
290
return false ;
246
291
}
247
292
248
- @ Override public void setTaskName (String s ) {
293
+ @ Override
294
+ public void setTaskName (String s )
295
+ {
249
296
}
250
297
251
- @ Override public void worked (int i , int i1 ) {
298
+ @ Override
299
+ public void worked (int i , int i1 )
300
+ {
252
301
}
253
302
});
254
303
getLogger ().debug (sw .toString ());
255
304
256
305
List <CompilerMessage > messageList ;
257
306
boolean hasError = false ;
258
- if (errorF .length () < 80 ) {
259
- throw new IOException ("Failed to run the ECJ compiler:\n " + sw .toString ());
307
+ if (errorF .length () < 80 )
308
+ {
309
+ throw new EcjFailureException (sw .toString ());
260
310
}
261
311
messageList = new EcjResponseParser ().parse (errorF , errorsAsWarnings );
262
312
263
- for (CompilerMessage compilerMessage : messageList ) {
264
- if (compilerMessage .isError ()) {
313
+ for (CompilerMessage compilerMessage : messageList )
314
+ {
315
+ if (compilerMessage .isError ())
316
+ {
265
317
hasError = true ;
266
318
break ;
267
319
}
268
320
}
269
- return new CompilerResult (! hasError , messageList );
270
-
321
+ if (!hasError && !success && !errorsAsWarnings )
322
+ {
323
+ CompilerMessage .Kind kind = errorsAsWarnings ? CompilerMessage .Kind .WARNING : CompilerMessage .Kind .ERROR ;
324
+
325
+ //-- Compiler reported failure but we do not seem to have one -> probable exception
326
+ CompilerMessage cm = new CompilerMessage ("[ecj] The compiler reported an error but has not written it to its logging" , kind );
327
+ messageList .add (cm );
328
+ hasError = true ;
329
+
330
+ //-- Try to find the actual message by reporting the last 5 lines as a message
331
+ String stdout = getLastLines (sw .toString (), 5 );
332
+ if (stdout .length () > 0 )
333
+ {
334
+ cm = new CompilerMessage ("[ecj] The following line(s) might indicate the issue:\n " + stdout , kind );
335
+ messageList .add (cm );
336
+ }
337
+ }
338
+ return new CompilerResult (!hasError || errorsAsWarnings , messageList );
339
+ } catch (EcjFailureException x ) {
340
+ throw x ;
271
341
} catch (Exception x ) {
272
342
throw new RuntimeException (x ); // sigh
273
343
} finally {
@@ -279,6 +349,36 @@ else if(extras.containsKey("-errorsAsWarnings"))
279
349
}
280
350
}
281
351
352
+ private String getLastLines (String text , int lines )
353
+ {
354
+ List <String > lineList = new ArrayList <>();
355
+ text = text .replace ("\r \n " , "\n " );
356
+ text = text .replace ("\r " , "\n " ); // make sure eoln is \n
357
+
358
+ int index = text .length ();
359
+ while (index > 0 ) {
360
+ int before = text .lastIndexOf ('\n' , index - 1 );
361
+
362
+ if (before + 1 < index ) { // Non empty line?
363
+ lineList .add (text .substring (before + 1 , index ));
364
+ lines --;
365
+ if (lines <= 0 )
366
+ break ;
367
+ }
368
+
369
+ index = before ;
370
+ }
371
+
372
+ StringBuilder sb = new StringBuilder ();
373
+ for (int i = lineList .size () - 1 ; i >= 0 ; i --)
374
+ {
375
+ String s = lineList .get (i );
376
+ sb .append (s );
377
+ sb .append (System .getProperty ("line.separator" )); // 8-/
378
+ }
379
+ return sb .toString ();
380
+ }
381
+
282
382
static private void append (StringBuilder warns , String s ) {
283
383
if (warns .length () > 0 )
284
384
warns .append (',' );
0 commit comments