3131import java .nio .file .Files ;
3232import java .nio .file .NoSuchFileException ;
3333import java .nio .file .Path ;
34- import java .nio .file .Paths ;
35- import java .util .Arrays ;
3634import java .util .Collection ;
37- import java .util .Collections ;
3835import java .util .List ;
3936import java .util .SortedMap ;
4037import java .util .SortedSet ;
4138import java .util .TreeMap ;
4239import java .util .TreeSet ;
4340import java .util .concurrent .ConcurrentHashMap ;
4441import java .util .concurrent .ConcurrentMap ;
42+ import java .util .stream .Stream ;
4543
4644import org .graalvm .compiler .debug .DebugContext ;
4745import org .graalvm .compiler .debug .DebugContext .Activation ;
6058
6159import com .oracle .svm .core .BuildArtifacts ;
6260import com .oracle .svm .core .ParsingReason ;
61+ import com .oracle .svm .core .SubstrateOptions ;
6362import com .oracle .svm .core .feature .AutomaticallyRegisteredFeature ;
6463import com .oracle .svm .core .feature .InternalFeature ;
6564import com .oracle .svm .core .jdk .JNIRegistrationUtil ;
@@ -161,48 +160,62 @@ void addJavaShimExports(String... exports) {
161160
162161 private void addShimExports (String shimName , String ... exports ) {
163162 assert exports != null && exports .length > 0 ;
164- shimExports .computeIfAbsent (shimName , s -> new TreeSet <>()).addAll (Arrays .asList (exports ));
163+ shimExports .computeIfAbsent (shimName , s -> new TreeSet <>()).addAll (List .of (exports ));
164+ }
165+
166+ /** Returns symbols that are re-exported by shim libraries. */
167+ public static Stream <String > getShimLibrarySymbols () {
168+ if (ImageSingletons .contains (JNIRegistrationSupport .class )) {
169+ return singleton ().getShimExports ();
170+ }
171+ return Stream .empty ();
165172 }
166173
167174 @ Override
168175 public void beforeImageWrite (BeforeImageWriteAccess access ) {
176+ if (SubstrateOptions .StaticExecutable .getValue () || isDarwin ()) {
177+ return ; /* Not supported. */
178+ }
179+
169180 if (shimExports .containsKey ("jvm" ) || Options .CreateJvmShim .getValue ()) {
170181 /* When making a `jvm` shim, also re-export the JNI functions that VM exports. */
171182 addJvmShimExports ("JNI_CreateJavaVM" , "JNI_GetCreatedJavaVMs" , "JNI_GetDefaultJavaVMInitArgs" );
172183 }
173184
174- if (isWindows ()) {
175- ((BeforeImageWriteAccessImpl ) access ).registerLinkerInvocationTransformer (linkerInvocation -> {
176- /* Make sure the native image exports all the symbols necessary for shim DLLs. */
177- shimExports .values ().stream ()
178- .flatMap (Collection ::stream )
179- .distinct ()
180- .map ("/export:" ::concat )
181- .forEach (linkerInvocation ::addNativeLinkerOption );
182- return linkerInvocation ;
183- });
184- }
185+ ((BeforeImageWriteAccessImpl ) access ).registerLinkerInvocationTransformer (linkerInvocation -> {
186+ /* Make sure the native image contains all symbols necessary for shim libraries. */
187+ getShimExports ().map (isWindows () ? "/export:" ::concat : "-Wl,-u," ::concat )
188+ .forEach (linkerInvocation ::addNativeLinkerOption );
189+ return linkerInvocation ;
190+ });
191+ }
192+
193+ private Stream <String > getShimExports () {
194+ return shimExports .values ().stream ()
195+ .flatMap (Collection ::stream )
196+ .distinct ();
185197 }
186198
187199 private AfterImageWriteAccessImpl accessImpl ;
188200
189201 @ Override
190202 @ SuppressWarnings ("try" )
191203 public void afterImageWrite (AfterImageWriteAccess access ) {
204+ if (SubstrateOptions .StaticExecutable .getValue () || isDarwin ()) {
205+ return ; /* Not supported. */
206+ }
207+
192208 accessImpl = (AfterImageWriteAccessImpl ) access ;
193209 try (Scope s = accessImpl .getDebugContext ().scope ("JDKLibs" )) {
194- if (isWindows ()) {
195- /* On Windows, JDK libraries are in `<java.home>\bin` directory. */
196- Path jdkLibDir = Paths .get (System .getProperty ("java.home" ), "bin" );
197- /* Copy JDK libraries needed to run the native image. */
198- copyJDKLibraries (jdkLibDir );
199- /*
200- * JDK libraries can depend on `jvm.dll` and `java.dll`, so to satisfy their
201- * dependencies, we create shim DLLs that re-export the actual functions from the
202- * native image itself.
203- */
204- makeShimDLLs ();
205- }
210+ /* On Windows, JDK libraries are in `<java.home>\bin` directory. */
211+ Path jdkLibDir = Path .of (System .getProperty ("java.home" ), isWindows () ? "bin" : "lib" );
212+ /* Copy JDK libraries needed to run the native image. */
213+ copyJDKLibraries (jdkLibDir );
214+ /*
215+ * JDK libraries can depend on `libjvm` and `libjava`, so to satisfy their dependencies
216+ * we use shim libraries to re-export the actual functions from the native image itself.
217+ */
218+ makeShimLibraries ();
206219 } finally {
207220 accessImpl = null ;
208221 }
@@ -247,35 +260,50 @@ private void copyJDKLibraries(Path jdkLibDir) {
247260 }
248261 }
249262
250- /** Makes shim DLLs to satisfy dependencies of JDK libraries. */
263+ /** Makes shim libraries that are necessary to satisfy dependencies of JDK libraries. */
251264 @ SuppressWarnings ("try" )
252- private void makeShimDLLs () {
265+ private void makeShimLibraries () {
253266 for (String shimName : shimExports .keySet ()) {
254267 DebugContext debug = accessImpl .getDebugContext ();
255- try (Scope s = debug .scope (shimName + "ShimDLL " )) {
268+ try (Scope s = debug .scope (shimName + "Shim " )) {
256269 if (debug .isLogEnabled (DebugContext .INFO_LEVEL )) {
257270 debug .log ("exports: %s" , String .join (", " , shimExports .get (shimName )));
258271 }
259- makeShimDLL (shimName );
272+ makeShimLibrary (shimName );
260273 }
261274 }
262275 }
263276
264- /** Makes a shim DLL by re-exporting the actual functions from the native image itself . */
277+ /** Makes a shim library that re-exports functions from the native image. */
265278 @ SuppressWarnings ("try" )
266- private void makeShimDLL (String shimName ) {
267- Path shimDLL = accessImpl .getImagePath ().resolveSibling (shimName + ".dll" );
268- /* Dependencies are the native image (so we can re-export from it) and C Runtime. */
269- Path [] shimDLLDependencies = {getImageImportLib (), Paths .get ("msvcrt.lib" )};
270-
279+ private void makeShimLibrary (String shimName ) {
271280 assert ImageSingletons .contains (CCompilerInvoker .class );
272- List <String > linkerCommand = ImageSingletons .lookup (CCompilerInvoker .class )
273- .createCompilerCommand (Collections .emptyList (), shimDLL , shimDLLDependencies );
274- /* First add linker options ... */
275- linkerCommand .addAll (Arrays .asList ("/link" , "/dll" , "/implib:" + shimName + ".lib" ));
276- /* ... and then the exports that were added for re-export. */
277- for (String export : shimExports .get (shimName )) {
278- linkerCommand .add ("/export:" + export );
281+
282+ List <String > linkerCommand ;
283+ Path image = accessImpl .getImagePath ();
284+ Path shimLibrary = image .resolveSibling (System .mapLibraryName (shimName ));
285+ if (isWindows ()) {
286+ /* Dependencies are the native image (so we can re-export from it) and C Runtime. */
287+ linkerCommand = ImageSingletons .lookup (CCompilerInvoker .class )
288+ .createCompilerCommand (List .of (), shimLibrary , getImageImportLib (), Path .of ("msvcrt.lib" ));
289+ /* First add linker options ... */
290+ linkerCommand .addAll (List .of ("/link" , "/dll" , "/implib:" + shimName + ".lib" ));
291+ /* ... and then the exports that were added for re-export. */
292+ for (String export : shimExports .get (shimName )) {
293+ linkerCommand .add ("/export:" + export );
294+ }
295+ } else {
296+ /*
297+ * To satisfy the dynamic loader and enable re-export it is enough to have a library
298+ * with the expected name. So we just create an empty one ...
299+ */
300+ linkerCommand = ImageSingletons .lookup (CCompilerInvoker .class )
301+ .createCompilerCommand (List .of ("-shared" , "-x" , "c" ), shimLibrary , Path .of ("/dev/null" ));
302+ /* ... and add an explicit dependency on the native image if it is a shared library. */
303+ if (!accessImpl .getImageKind ().isExecutable ) {
304+ linkerCommand .addAll (List .of ("-Wl,-no-as-needed" , "-L" + image .getParent (), "-l:" + image .getFileName (),
305+ "-Wl,--enable-new-dtags" , "-Wl,-rpath,$ORIGIN" ));
306+ }
279307 }
280308
281309 DebugContext debug = accessImpl .getDebugContext ();
@@ -284,8 +312,8 @@ private void makeShimDLL(String shimName) {
284312 if (FileUtils .executeCommand (linkerCommand ) != 0 ) {
285313 VMError .shouldNotReachHere ();
286314 }
287- BuildArtifacts .singleton ().add (ArtifactType .JDK_LIBRARY_SHIM , shimDLL );
288- debug .log ("%s.dll : OK" , shimName );
315+ BuildArtifacts .singleton ().add (ArtifactType .JDK_LIBRARY_SHIM , shimLibrary );
316+ debug .log ("%s: OK" , shimLibrary . getFileName () );
289317 } catch (InterruptedException e ) {
290318 throw new InterruptImageBuilding ();
291319 } catch (IOException e ) {
@@ -295,6 +323,7 @@ private void makeShimDLL(String shimName) {
295323
296324 /** Returns the import library of the native image. */
297325 private Path getImageImportLib () {
326+ assert isWindows ();
298327 Path image = accessImpl .getImagePath ();
299328 String imageName = String .valueOf (image .getFileName ());
300329 String importLibName = imageName .substring (0 , imageName .lastIndexOf ('.' )) + ".lib" ;
0 commit comments