10
10
import java .nio .file .Paths ;
11
11
import java .nio .file .StandardCopyOption ;
12
12
import java .util .ArrayList ;
13
+ import java .util .Arrays ;
13
14
import java .util .Collections ;
14
15
import java .util .HashMap ;
15
16
import java .util .List ;
@@ -150,8 +151,7 @@ public NativeImageBuildItem build(NativeConfig nativeConfig, NativeImageSourceJa
150
151
String nativeImageName = getNativeImageName (outputTargetBuildItem , packageConfig );
151
152
String resultingExecutableName = getResultingExecutableName (nativeImageName , isContainerBuild );
152
153
153
- NativeImageBuildRunner buildRunner = getNativeImageBuildRunner (nativeConfig , outputDir ,
154
- nativeImageName , resultingExecutableName );
154
+ NativeImageBuildRunner buildRunner = getNativeImageBuildRunner (nativeConfig , outputDir , resultingExecutableName );
155
155
buildRunner .setup (processInheritIODisabled .isPresent ());
156
156
final GraalVM .Version graalVMVersion = buildRunner .getGraalVMVersion ();
157
157
@@ -184,8 +184,7 @@ public NativeImageBuildItem build(NativeConfig nativeConfig, NativeImageSourceJa
184
184
185
185
List <String > nativeImageArgs = commandAndExecutable .args ;
186
186
187
- int exitCode = buildRunner .build (nativeImageArgs , nativeImageName , resultingExecutableName , outputDir ,
188
- nativeConfig .debug .enabled , processInheritIODisabled .isPresent ());
187
+ int exitCode = buildRunner .build (nativeImageArgs , outputDir , processInheritIODisabled .isPresent ());
189
188
if (exitCode != 0 ) {
190
189
throw imageGenerationFailed (exitCode , nativeImageArgs );
191
190
}
@@ -194,11 +193,6 @@ public NativeImageBuildItem build(NativeConfig nativeConfig, NativeImageSourceJa
194
193
IoUtils .copy (generatedExecutablePath , finalExecutablePath );
195
194
Files .delete (generatedExecutablePath );
196
195
if (nativeConfig .debug .enabled ) {
197
- final String symbolsName = String .format ("%s.debug" , nativeImageName );
198
- Path generatedSymbols = outputDir .resolve (symbolsName );
199
- Path finalSymbolsPath = outputTargetBuildItem .getOutputDirectory ().resolve (symbolsName );
200
- IoUtils .copy (generatedSymbols , finalSymbolsPath );
201
- Files .delete (generatedSymbols );
202
196
final String sources = "sources" ;
203
197
final Path generatedSources = outputDir .resolve (sources );
204
198
final Path finalSources = outputTargetBuildItem .getOutputDirectory ().resolve (sources );
@@ -207,6 +201,17 @@ public NativeImageBuildItem build(NativeConfig nativeConfig, NativeImageSourceJa
207
201
}
208
202
System .setProperty ("native.image.path" , finalExecutablePath .toAbsolutePath ().toString ());
209
203
204
+ if (objcopyExists ()) {
205
+ if (nativeConfig .debug .enabled ) {
206
+ splitDebugSymbols (finalExecutablePath );
207
+ }
208
+ // Strip debug symbols regardless, because the underlying JDK might contain them
209
+ objcopy ("--strip-debug" , finalExecutablePath .toString ());
210
+ } else {
211
+ log .warn ("objcopy executable not found in PATH. Debug symbols will not be separated from executable." );
212
+ log .warn ("That will result in a larger native image with debug symbols embedded in it." );
213
+ }
214
+
210
215
return new NativeImageBuildItem (finalExecutablePath ,
211
216
new NativeImageBuildItem .GraalVMVersion (graalVMVersion .fullVersion , graalVMVersion .major ,
212
217
graalVMVersion .minor ,
@@ -239,9 +244,9 @@ public static boolean isContainerBuild(NativeConfig nativeConfig) {
239
244
}
240
245
241
246
private static NativeImageBuildRunner getNativeImageBuildRunner (NativeConfig nativeConfig , Path outputDir ,
242
- String nativeImageName , String resultingExecutableName ) {
247
+ String resultingExecutableName ) {
243
248
if (!isContainerBuild (nativeConfig )) {
244
- NativeImageBuildLocalRunner localRunner = getNativeImageBuildLocalRunner (nativeConfig , outputDir . toFile () );
249
+ NativeImageBuildLocalRunner localRunner = getNativeImageBuildLocalRunner (nativeConfig );
245
250
if (localRunner != null ) {
246
251
return localRunner ;
247
252
}
@@ -254,8 +259,7 @@ private static NativeImageBuildRunner getNativeImageBuildRunner(NativeConfig nat
254
259
log .warn (errorMessage + " Attempting to fall back to container build." );
255
260
}
256
261
if (nativeConfig .remoteContainerBuild ) {
257
- return new NativeImageBuildRemoteContainerRunner (nativeConfig , outputDir ,
258
- nativeImageName , resultingExecutableName );
262
+ return new NativeImageBuildRemoteContainerRunner (nativeConfig , outputDir , resultingExecutableName );
259
263
}
260
264
return new NativeImageBuildLocalContainerRunner (nativeConfig , outputDir );
261
265
}
@@ -368,12 +372,12 @@ private void checkGraalVMVersion(GraalVM.Version version) {
368
372
}
369
373
}
370
374
371
- private static NativeImageBuildLocalRunner getNativeImageBuildLocalRunner (NativeConfig nativeConfig , File outputDir ) {
375
+ private static NativeImageBuildLocalRunner getNativeImageBuildLocalRunner (NativeConfig nativeConfig ) {
372
376
String executableName = getNativeImageExecutableName ();
373
377
if (nativeConfig .graalvmHome .isPresent ()) {
374
378
File file = Paths .get (nativeConfig .graalvmHome .get (), "bin" , executableName ).toFile ();
375
379
if (file .exists ()) {
376
- return new NativeImageBuildLocalRunner (file .getAbsolutePath (), outputDir );
380
+ return new NativeImageBuildLocalRunner (file .getAbsolutePath ());
377
381
}
378
382
}
379
383
@@ -395,7 +399,7 @@ private static NativeImageBuildLocalRunner getNativeImageBuildLocalRunner(Native
395
399
if (javaHome != null ) {
396
400
File file = new File (javaHome , "bin/" + executableName );
397
401
if (file .exists ()) {
398
- return new NativeImageBuildLocalRunner (file .getAbsolutePath (), outputDir );
402
+ return new NativeImageBuildLocalRunner (file .getAbsolutePath ());
399
403
}
400
404
}
401
405
@@ -408,7 +412,7 @@ private static NativeImageBuildLocalRunner getNativeImageBuildLocalRunner(Native
408
412
if (dir .isDirectory ()) {
409
413
File file = new File (dir , executableName );
410
414
if (file .exists ()) {
411
- return new NativeImageBuildLocalRunner (file .getAbsolutePath (), outputDir );
415
+ return new NativeImageBuildLocalRunner (file .getAbsolutePath ());
412
416
}
413
417
}
414
418
}
@@ -442,6 +446,51 @@ private static String testGCCArgument(String argument) {
442
446
return "" ;
443
447
}
444
448
449
+ private boolean objcopyExists () {
450
+ // System path
451
+ String systemPath = System .getenv (PATH );
452
+ if (systemPath != null ) {
453
+ String [] pathDirs = systemPath .split (File .pathSeparator );
454
+ for (String pathDir : pathDirs ) {
455
+ File dir = new File (pathDir );
456
+ if (dir .isDirectory ()) {
457
+ File file = new File (dir , "objcopy" );
458
+ if (file .exists ()) {
459
+ return true ;
460
+ }
461
+ }
462
+ }
463
+ }
464
+
465
+ return false ;
466
+ }
467
+
468
+ private void splitDebugSymbols (Path executable ) {
469
+ Path symbols = Paths .get (String .format ("%s.debug" , executable .toString ()));
470
+ objcopy ("--only-keep-debug" , executable .toString (), symbols .toString ());
471
+ objcopy (String .format ("--add-gnu-debuglink=%s" , symbols .toString ()), executable .toString ());
472
+ }
473
+
474
+ private static void objcopy (String ... args ) {
475
+ final List <String > command = new ArrayList <>(args .length + 1 );
476
+ command .add ("objcopy" );
477
+ command .addAll (Arrays .asList (args ));
478
+ if (log .isDebugEnabled ()) {
479
+ log .debugf ("Execute %s" , String .join (" " , command ));
480
+ }
481
+ Process process = null ;
482
+ try {
483
+ process = new ProcessBuilder (command ).start ();
484
+ process .waitFor ();
485
+ } catch (IOException | InterruptedException e ) {
486
+ throw new RuntimeException ("Unable to invoke objcopy" , e );
487
+ } finally {
488
+ if (process != null ) {
489
+ process .destroy ();
490
+ }
491
+ }
492
+ }
493
+
445
494
private static class NativeImageInvokerInfo {
446
495
private final List <String > args ;
447
496
@@ -662,11 +711,6 @@ public NativeImageInvokerInfo build() {
662
711
nativeImageArgs .add ("-H:+DashboardAll" );
663
712
}
664
713
665
- // Disable single parsing of compiler graphs till https://github.com/oracle/graal/issues/3435 gets fixed
666
- if (graalVMVersion .isNewerThan (GraalVM .Version .VERSION_21_1 )) {
667
- nativeImageArgs .add ("-H:-ParseOnce" );
668
- }
669
-
670
714
nativeImageArgs .add (nativeImageName );
671
715
672
716
return new NativeImageInvokerInfo (nativeImageArgs );
0 commit comments