Jose's Blog

01.11.2017

Compiling Giac in Windows (VS2008)

Filed under: Uncategorized — admin @ 22:09

Finally, the day has come when I can proudly write that I have successfully compiled a computer algebra system in windows using visual studio and I actually was able to compile it as a dynamic library and link it with another C++ program that uses it. Maybe in other operating system with gcc compiler this is a trivial task, in windows with msvc this is for me far from trivial.

Here is a walkthrough. It would help if you understood the steps in compiling giac with gcc (either with mingwc or in a cygwin environment) in windows. You can look at my previous blog post to get an idea. If you just want to compile and not think of the technicalities (steps below), you may download a project archive here.

First I explain how to compile the project (not link)

  1. Make sure you make a project with the following c++ source files:
    alg_ext.cc
    cocoa.cc
    csturm.cc
    derive.cc
    desolve.cc
    ezgcd.cc
    first.cc
    gauss.cc
    gausspol.cc
    gen.cc
    global.cc
    help.cc
    identificateur.cc
    ifactor.cc
    index.cc
    input_lexer.cc (and input_lexer.ll)
    input_parser.cc
    intg.cc
    intgab.cc
    isom.cc
    lin.cc
    maple.cc
    mathml.cc
    misc.cc
    modfactor.cc
    modpoly.cc
    moyal.cc
    pari.cc
    permu.cc
    plot.cc
    plot3d.cc
    prog.cc
    quater.cc
    risch.cc
    rpn.cc
    series.cc
    solve.cc
    sparse.cc
    subst.cc
    sym2poly.cc
    symbolic.cc
    tex.cc
    threaded.cc
    ti89.cc
    tinymt32.cc
    unary.cc
    usual.cc
    vecteur.cc
    
  2. For the sake of completeness I provided a sample project file with the corresponding source codes. global.cc had to be patched because we use MPIR.

  3. Visual studio may not have stdint.h and some code may use it. I have included a stdint.h in the project archive that I am going to share. Otherwise, it is easy to add the necessary typedef from stdint.h. You can create your own stdint.h by creating the following file:

    typedef __int8 int8_t;
    typedef unsigned __int8 uint8_t;
    typedef __int32 int32_t;
    typedef unsigned __int32 uint32_t;
    typedef __int64 int64_t;
    typedef unsigned __int64 uint64_t;
    

    I also patched global.cc (also in the project archive I am sharing) because mpir already defines R_OK (which is defined in global.cc). See the next item for explanation. The patch just changes line ca. 172 that defines R_OK for the first time. To avoid conflict with mpir I changed this definition to

    #ifndef HAVE_LIBMPIR 
      int R_OK=4;
    #endif
    
  4. Make sure you have the following preprocessor definition set in the Project Properties->Configuration Properties->Preprocessor
    WIN32
    WINDOWS
    HAVE_CONFIG_H
    IN_GIAC
    GIAC_VECTOR
    _USE_MATH_DEFINES
    VISUALC (not __VISUALC__)
    _CRT_SECURE_NO_WARNINGS
    _SCL_SECURE_NO_WARNINGS
    _CRT_NON_CONFORMING_SWPRINTFS
    STATIC_BUILTIN_LEXER_FUNCTIONS
    NO_CLOCK (clock() is not standardly defined in msvc)
    HAVE_NO_CWD (getcwd is not standardly defined in msvc)
    MS_SMART (otherwise in gen.cc #include "../../../_windows/src/stdafx.h" would cause error, stdafx.h does not reside in this relative directory by default, without this we also get error in ifactor.cc when calling PREFETCH)
    NO_UNARY_FUNCTION_COMPOSE
    MS_SMART
    HAVE_LIBMPIR (needed for a patch in global.cc when using mpir, R_OK is already defined. See attached files)
    
  5. Make sure in config.h of the original giac source code, the following are NOT defined:
    HAVE_GETCWD (getcwd  is not standardly defined in msvc)
    HAVE_SYS_TIME_H
    HAVE_LIBPTHREAD (otherwise you get a lot of VLA errors in vecteur.cc)
    HAVE_PTHREAD_H (otherwise you get a lot of VLA errors in vecteur.cc)
    HAVE_READLINE_HISTORY_H (they are not standardly available in msvc)
    HAVE_READLINE_READLINE_H (they are not standardly available in msvc)
    

    Also uncomment

     #define HAVE_NO_CWD 1 //(getcwd  is not standardly defined in msvc) 
  6. In line ca. 1634 of vecteur.cc where the method rand_1 is defined, the code uses rand() which is ambiguous in VS2008 (error C2660). I took the liberty and changed rand() to std::rand() (I hope this is what the author of the code wanted).
  7. In line ca. 35 of rpn.cc, after #ifndef NSPIRE there is #include which is nonexistent in MSVC. Workaround:
    changed #ifndef NSPIRE to #if !defined(NSPIRE) && !defined(__VISUALC__)
  8. In the original static_lexer.h, for some reasons the unicode literals are not understood as variables (probably an msvc setting that I have not figured out how to set). At the moment the fast and dirty (since I don’t think I am going to use these specific giac commands) solution I could think of is to enclose the line with at_LINEAR? and the last two lines of the code of static_lexer.h (where unorthodox characters are used as “at” variables) between #ifndef __VISUALC__ and #endif. This patch of static_lexer.h is also in the archive I am sharing.
  9. In some compilers input_lexer.ll and input_lexer.cc will cause some problems when only std::log(10) is used (compiler cannot detect what type of overload of log this is). Therefore I replace std::log(10) with std::log(10.0)

After doing all these, you should not get any serious compile errors (maybe you get some that I have overlooked, but I am sure they are easy to resolve). The next hurdle is to link. I made a fix but I am not sure if this is the best fix. There are global unary functions that are supposed to be defined somewhere and called by static_extern.h. The linker initially complained about unresolved external symbols: at_ugamma, at_regroup, at_is_inside, at_igamma, at_IP and at_FP. Maybe Bernard can help me on this, but the only way I could find to link was just to enclose these external global initialization (which should be defined somewhere, but where?) within #ifndef __VISUALC__ and #endif. This I did in both static_lexer.h and static_extern.h

After doing this, I was able to finally link and compile. One thing that is not mentioning is that I used CMake to export dll as it is often required in Visual Studio to apply __declspec(dllexport) to the methods we want to export when compiling the dynamic library and apply __declspec(dllimport) when importing from the library. The new CMake (not so new anymore) allows you to do this (with additional parameters in Pre-Link Build Events of Visual Studio). I will not go into detail about this, this can be read here .
This allowed me to both created a giac dll and a lib. The end result is around 8.7Mb for both the dll and the lib, but since the dll is only shared I find this a significant improvement to the size you get from compiling with mingw32.

Finally, to test that it works. I linked giac to another project having only one source (make sure you add the include directories of giac, mpir and mpfir in C/C++ -> Additonal Include Directories of the project property):

#include <giac/config.h>
#include <giac/giac.h>

using namespace std;
using namespace giac;

gen pgcd(gen a,gen b){
  gen q,r;
  for (;b!=0;){
    r=irem(a,b,q);
    a=b;
    b=r;
  }
  return a;
}

int main(){
  cout << "Enter 2 integers ";
  gen a,b;
  cout << "Trying a giac self-implementation of gcd:\n";
  cin >> a >> b;
  cout << pgcd(a,b) << endl;
  return 0;
}

I was able to compile, link and execute this program and get the result similar to the one I got in my last blog (compiling in mingw32).

As promised here is a 7zip file containing the project and the giac source I compiled with (and the setup needed in VS2008). Note: I only set Release configuration and you still need to link/compile with mpir (you can get the source here) and set it up in the project for this to work.

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress