Extension LibreOffice : bug de Giac compilé avec MSVC19
après toutes ces années, je me suis replongé dans mon extension pour le tableur de OpenOffice.org/LibreOffice (OOo/LO).
Depuis nos échanges de 2009 qui m'avait permis de compiler mon extension, beaucoup de changements ont eu lieu et je voulais mettre à jour mon programme mais le temps me manquait et je voulais surtout attendre de voir si LO allait s'imposer. C'est chose faite donc je devais m'y remettre pour plusieurs raisons :
- pour que mon programme fonctionne dans LO (l'API a évolué et ça ne s'installait plus),
- sous Linux : pour compiler une version indépendante des librairies présentes sur la distribution car en cas de mise à jour du système, si les dépendances ne sont plus satisfaites, OOo/LO plante au démarrage et il faut désinstaller l'extension, voir quelles sont les librairies manquantes et les installer manuellement. Bref, pas du tout à la portée d'un utilisateur lambda.
- sous windows : pour compiler une version 64 bits (il n'y a pas de problème de librairies manquantes sous windows puisque mon extension ne dépend que des dll mpir et mpfr que je peux mettre dans mon extension).
- pour intégrer une version plus récente de giac (c'était la version 0.8.3 à l'époque).
J'ai bien avancé :
Sous Linux, tout est bon, ça compile et fonctionne dans LO avec giac 1.7.0. Je n'ai pas encore attaqué la version statique de ma librairie mais je devrais y arriver. Je t'enverrai un lien pour télécharger l'extension dès que je l'aurai finalisée.
Sous windows, je savais que ça serait plus difficile. Je rappelle qu'il faut compiler avec le même compilateur que celui qui sert à fabriquer OOo/LO, donc celui de microsoft (cl.exe). Cela nous avait conduit il y a 12 ans (!) à quelques ajustements sur le code source de Giac.
J'ai repris la démarche avec le code de giac version 1.7.0 et j'ai pu recompiler une librairie giac_oo.lib avec MS Visual Studio 19 en 64 bits avec support des librairies mpir et mpfr.
J'ai compilé ensuite mon extension pour windows x64 avec le SDK de LO. Ça s'installe et ça fonctionne... presque ; il me reste un bug lié à giac que je ne sais pas résoudre, n'en maîtrisant pas le code. Cela ne te prendra peut-être que quelques minutes à résoudre.
J'ai mis dans un répertoire partagé tous les fichiers dont je parle dans la suite (exécutables et sources) : https://drive.google.com/drive/folders/ ... sp=sharing
Voici ce bug que je peux reproduire facilement avec mon programme giac_oo.exe issu de giac_oo.cpp :
Si j'évalue une expression du genre : "1+1" ou "evalf(pi,30)", ça fonctionne bien.
Mais si j'évalue "simplifier(x+y)" j'obtiens une erreur venant du fichier MSVC\include\vector "Expression : vector iterators incompatible" (après débogage : exception levée dans le fichier monomial.h ligne 479 : if(new_coord.begin()==a) )
Si tu as le temps de te pencher sur ce problème de compilation de la librairie giac pour x64, je te décris ci-dessous toutes les étapes qui te permettront de compiler et déboguer giac-oo.exe et ainsi remonter jusqu'à la source de l'instruction dans le fichier monomial.h comme je l'ai fait.
1) Télécharger et installer Microsoft Visual Studio community 2019 (la version 2022 vient de sortir mais j'avais commencé avant).
Cocher le composant "developpement desktop en C++" à l'installation
Dans un répertoire, créer un fichier vcvars64.bat qui contient : call "c:\program files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\Auxiliary\Build\VCVARS64.bat"
Dans ce même répertoire, créer un fichier hello.cpp pour tester la compilation en ligne de commande :
Code : Tout sélectionner
#include <iostream>
using namespace std;
int main()
{
cout << "Hello, world, from Visual C++!" << endl;
}
Code : Tout sélectionner
vcvars64.bat
cl /EHsc hello.cpp
./hello.exe
2) Compiler mpir
Le site https://github.com/BrianGladman/mpir contient un projet compilable par MSVC 19.
Menu code, download zip, extraire l'archive mpir dans le répertoire contenant vcvars64.bat.
Ouvrir mpir/msvc/vs19/mpir.sln avec MSVC19.
Choisir architecture x64 et mode Debug.
Clic droit sur dll_mpir_gc puis "projet uniquement->générer uniquement la dll"
Aller dans mpir/msvc/vs19/dll_mpir_gc/x64/Debug et :
Copier gmp.h de mpir dans c:\program files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include
Copier mpir.lib dans c:\program files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\lib\x64
Copier mpir.dll dans le répertoire du programme qui s'en servira.
Tester avec HelloGMP :
Code : Tout sélectionner
// compil : cl /MDd /EHsc helloGMP.cpp mpir.lib
#include <iostream>
#include <gmp.h>
///From http://www.richelbilderbeek.nl/CppMpz_tToStr.htm
const std::string Mpz_tToStr(const mpz_t& i)
{
static char buffer[256];
mpz_get_str(buffer,10,i);
return std::string(buffer);
}
int main()
{
mpz_t i;
mpz_init_set_str(i,"123456789012345678901234567890",10);
//Perform i = i * i
mpz_mul(i,i,i);
std::cout
<< "Hello GMP,\n"
<< Mpz_tToStr(i) << " times.\n";
mpz_clear(i);
}
Code : Tout sélectionner
cl /MDd /EHsc helloGMP.cpp mpir.lib
./helloGMP.exe
sources de mpfr : https://github.com/BrianGladman/mpfr
ouvrir mpfr/build.vs19/dll_mpfr.sln
Choisir architecture x64 et mode Debug.
Clic droit sur dll_mpfr et "projet uniquement->générer uniquement la dll"
Aller dans mpfr/dll/x64/Debug et
Copier mpfr.h de dans c:\program files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include
Copier mpfr.lib dans c:\program files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\lib\x64
Copier mpfr.dll dans le répertoire du programme qui s'en servira
Tester avec helloMPFR.cpp :
Code : Tout sélectionner
// compil : cl /MDd /EHsc helloMPFR.cpp mpfr.lib mpir.lib
#include <stdio.h>
#include <gmp.h>
#include <mpfr.h>
int main (void)
{
unsigned int i;
mpfr_t s, t, u;
mpfr_init2 (t, 200);
mpfr_set_d (t, 1.0, MPFR_RNDD);
mpfr_init2 (s, 200);
mpfr_set_d (s, 1.0, MPFR_RNDD);
mpfr_init2 (u, 200);
for (i = 1; i <= 100; i++)
{
mpfr_mul_ui (t, t, i, MPFR_RNDU);
mpfr_set_d (u, 1.0, MPFR_RNDD);
mpfr_div (u, u, t, MPFR_RNDD);
mpfr_add (s, s, u, MPFR_RNDD);
}
printf ("Sum is ");
mpfr_out_str (stdout, 10, 0, s, MPFR_RNDD);
putchar ('\n');
mpfr_clear (s);
mpfr_clear (t);
mpfr_clear (u);
mpfr_free_cache ();
return 0;
}
Code : Tout sélectionner
cl /MDd /EHsc helloMPFR.cpp mpfr.lib mpir.lib
./helloMPFR.exe
Installer cygwin64 et dans le setup installer make qui ne l'est pas par défaut.
Dans giac-1.7.0/src de giac :
- copier config.h.vcc en config.h et décommenter #define HAVE_LIBMPFR 1 (j'ai mis mon config.h dans le répertoire partagé)
- modifier Makefile.vcc pour adapter le chemin vers visual studio 19. J'ai ajouté des fichiers *.obj du Makefile.win64 sans vraiment savoir ce qui était superflu (j'ai mis mon Makefile.vcc dans le répertoire partagé).
- j'ai dû modifier beaucoup de fichiers à cause d'erreurs liées à la compilation (il y avait aussi énormément de warnings que j'ai ignorés, peut-être faudra-t-il creuser de ce côté là...) :
dans src/Graphe.h ajouter #include <math.h> pour définir la constante M_LN2
dans src/global.cc(1274) : char buf_[L+1]; ne compile pas avec cl : erreur C2131, allocation dynamique impossible à la compilation.
J'ai remplacé cette ligne par les deux suivantes :
Code : Tout sélectionner
char *buf_ = NULL;
buf_=(char *)calloc(L+1,sizeof(char));
dans input_lexer.cc(4895) : ajouter #include <io.h> et remplacer isatty par _isatty
enlever cutils, libbf, js (ne compilent pas, spécifiques win64 ? nécessaires ?)
renommer ces fichiers *.c en *.cc : nautywrapper, TmpFGLM, TmpLESystemSolver, caseval, graphic, libunicode, qjsgiac, quickjs, quickjs-libc.
dans graphe.cc(13421) : erreur C3848. Ajouter le type "const" dans graphe.h (ligne 566 pour bool operator() )
- Compiler :
Ouvrir une boite cmd.exe, aller dans giac-1.7.0/src et lancer
Code : Tout sélectionner
vcvars64.bat
c:\cygwin64\cygwin.bat
make -f Makefile.vcc
5) Compiler le programme de test giac-1.7.0/src/giac_oo.cpp :
Créer dans le repertoire include de MSVC un sous-repertoire giac.
Copier les .h de giac dans c:\program files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\giac
Copier mpir.dll et mpfr.dll dans giac-1.7.0/src
Programme giac_oo.cpp :
Code : Tout sélectionner
// compile-command windows : "cl /Zi /MDd /I. /EHsc giac_oo.cpp giac_oo.lib mpfr.lib mpir.lib"
// compile-command Linux : "g++ -g -o giac_oo giac_oo.cpp -lgiac -lgmp"
#include <giac/config.h>
#include <giac/gen.h>
#include <giac/prog.h>
int main(){
std::string s;
for (;;){
std::cout << "Expression: " ;
std::cin >> s;
giac::gen g(s,0);
if (is_zero(g))
return 0;
g=giac::protecteval(g,1,0);
std::cout << g.print(0) << std::endl;
}
}
Code : Tout sélectionner
cl /Zi /MDd /I. /EHsc giac_oo.cpp giac_oo.lib mpfr.lib mpir.lib
./giac_oo.exe
Ça bug sur l'expression "simplifier(x+y)".
Pour déboguer, lancer VS2019 et cliquer sur "ouvrir un projet ou une solution". Sélectionner le fichier giac_oo.exe puis clic droit et "déboguer", "démarrer une nouvelle instance"
taper simplifier(x+y) et cliquer sur recommencer après le plantage pour avoir accès à la pile des appels (accès au code source par clic-droit).
Voilà où j'en suis.
Je mets également dans le répertoire partagé une version brute de compilation de mon extension LO pour windows x64 qui installe les fonctions dans le tableur.
Il suffit de double cliquer pour l'installer.
Le même bug se produit bien sûr si on tape dans une cellule =csomme("x";"y")
Par contre =evaluer("pi";30) renvoie le bon résultat.
Merci d'avance pour ton aide !