Accueil > Bienvenue > Journal de bord > Linux, binaire Java, et chemins windows codés en dur

Linux, binaire Java, et chemins windows codés en dur

dimanche 2 avril 2023, par Mathieu Brèthes

Toutes les versions de cet article : [Deutsch] [English] [français]

Bon je me note ça ici pour la postérité. Ca m’arrive de faire un peu le geek.

Imaginez la situation suivante : on vous a légué un programme Java dont vous n’avez pas le code source, vous vous dites "c’est super, Java c’est un langage indépendant de la plate-forme, je vais pouvoir le faire fonctionner sous Linux" ! Et quand vous le lancez, une erreur horrible de ce genre se produit :

Exception in thread "main" java.io.FileNotFoundException: c:\hello.txt (Aucun fichier ou dossier de ce type)

Il s’agit d’un chemin Windows codé en dur dans l’application. Vous n’avez bien sûr pas le code source pour corriger vous-même cette erreur stupide. Différentes solutions vous viennent à l’esprit : lancer Windows, utiliser l’émulateur Wine...

Mais pourquoi ne pas modifier la machine virtuelle Java (JVM) pour qu’elle transforme elle-même les chemins Windows en chemins Linux ? "Tout simplement ?"

Il se trouve que c’est la solution proposée par Chase Siebert, directeur de l’ingénierie chez Dropbox. Dans son post de blog, il explique que c’est faisable en modifiant un seul fichier ! Youpi, donc ! Vous suivez joyeusement ses instructions, qui nécessitent tout de même de télécharger le code source de la JVM (sudo apt-get install openjdk-src), de le chercher dans le dossier d’installation /usr/lib/jvm/openjdk-11/lib/src.zip puis de le dézipper et d’aller modifier le fichier File.java situé dans java.base/java/io, puis de le compiler (et là faut trouver les bons paramètres pour que ça marche) et ensuite d’ajouter l’archive résultante en paramètre de ligne de commande... Et là bien sûr, ça ne marche plus :

-Xbootclasspath/p is no longer a supported option.

C’est tout le problème d’un post de blog d’il y a 13 ans qui fonctionnait avec java 8. Maintenant vous avez Java 11. Pour faire maintenant, c’est à la fois plus simple et plus compliqué...

Etape 1 : organiser le projet

Créez un répertoire build pour votre build, un répertoire sdk pour le sdk, et un répertoire run pour votre programme.

Ca ressemble à ça :

./build
./run
./sdk

Dézippez le sdk dans sdk.

Copiez votre binaire java à exécuter dans run.

Etape 2 : compiler File.java avec les bonnes options

Modifiez le fichier File.java comme indiqué sur le post de blog mis en lien ci-plus haut. Rajoutez en tête de fichier un "import java.util.regex.Pattern ;" qui n’est pas indiqué dans le post de blog.

A la racine du sdk (qui contient le dossier java.base) lancer la ligne de commande suivante :

javac -XDstringConcat=inline -d ../build/java.base --patch-module java.base=. java.base/java/io/File.java

Ceci va compiler votre "patch" de File.java dans le dossier build/java.base . -XDstringConcat=inline est nécessaire pour éviter une erreur à l’exécution (c’est documenté ici pourquoi, et j’ai bien galéré à trouver cette page...).

Etape 3. Lancez votre programme !

Allez à présent dans le répertoire run et lancez votre programme avec la ligne de commande rigolote suivante :

java --patch-module java.base=../build/java.base monprogramme

Et voilà, votre c :\hello.txt est transformé en /hello.txt, qui avec un peu de chance existe sur votre disque...

Un dernier lien, j’ai trouvé la syntaxe de --patch-module correctement expliquée sur ce site (tout en bas de la page).

Voilà, comme ça il y a à présent 2 sites qui parlent de ce problème !


Voir en ligne : Java hack to deal with Windows file paths in Linux