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
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