Vasili Burdo on Thu, 17 Dec 2009 18:07:55 +0100


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

A patch for native PARI/GP build on Windows (Mingw+Msys)


It includes:
- Configuration changes to recognize Mingw build.
- Native hires plotting for Windows.
- Native support of Windows console including terminal size and colors.
- All tests are passed for gp-syn. For gp-sta, tests involving install() fail.

This patch is based on current PARI SVN.
Comments and suggestions are VERY welcome.

Vasili.

Index: config/arch-osname
===================================================================
--- config/arch-osname	(revision 12034)
+++ config/arch-osname	(working copy)
@@ -29,6 +29,9 @@
   cygwin*)  arch=`uname -m`
             if test -z "$arch"; then arch=ix86; fi
             osname=cygwin;;
+  mingw*)   arch=`uname -m`
+            if test -z "$arch"; then arch=ix86; fi
+            osname=mingw;;
   ultrix)   arch=mips;;
   nextstep) arch=`file /bin/sh | sed 's/.*(for architecture \(.*\))/\1/'`;;
   darwin*)  arch=`uname -p`
Index: config/get_dlld
===================================================================
--- config/get_dlld	(revision 12034)
+++ config/get_dlld	(working copy)
@@ -18,7 +18,7 @@
          soname=$sodest;;
   hpux) soname= ; sodest= ; DLSUFFIX=sl;;
   irix) soname= ; sodest= ;;
-  os2|cygwin)soname= ; sodest= ; DLSUFFIX=dll ;;
+  os2|cygwin|mingw)soname= ; sodest= ; DLSUFFIX=dll ;;
   darwin)soname= ; sodest= ; DLSUFFIX=dylib;;
   *) do_dll=no ;;
 esac
@@ -27,6 +27,7 @@
 # On FreeBSD 2.2.5 (Y. Uchikawa) and Cygwin, this does not work.
 case "$osname" in 
   freebsd|cygwin) DL_DFLT_NAME="\\\"\$(LIBPARI_DYN)\\\"" ;;
+  mingw) DL_DFLT_NAME="\\\"\$(LIBPARI_SO)\\\"" ;;
   *) DL_DFLT_NAME=NULL ;;
 esac
 
@@ -84,6 +85,7 @@
   case "$osname" in
     os2) DLLDFLAGS="$CFLAGS -Zdll" ;; # assume DLLD = gcc
     cygwin) DLLDFLAGS="-Wl,--out-implib=\$(LIBPARI_SO)\$(_A),--export-all-symbols";;
+	mingw) DLLDFLAGS="-Wl,--out-implib=\$(LIBPARI_SO)\$(_A)";;
   esac
   if test -n "$DLLDisGCC"; then
     case "$arch" in
Index: config/get_graphic_lib
===================================================================
--- config/get_graphic_lib	(revision 12034)
+++ config/get_graphic_lib	(working copy)
@@ -29,4 +29,9 @@
 . ./get_Qt   # QTDIR, QTLIB
 fi
 
+if test "$which_graphic_lib" == none; then
+  if test "$osname" == "mingw"; then
+    which_graphic_lib=win32
+  fi
+fi
 echo "Hi-Res Graphics: $which_graphic_lib"
Index: config/Makefile.SH
===================================================================
--- config/Makefile.SH	(revision 12034)
+++ config/Makefile.SH	(working copy)
@@ -48,6 +48,10 @@
 	export_file=pari.def; export_create="emxexp -u"
 	# Actually, the build will fail until the switch to -Zomf
 	dlld_ignore=- ;;
+  mingw)
+    CFLAGS="$CFLAGS -fno-omit-frame-pointer"
+    export_file='$(LIBPARI).def'
+    ;;
 esac
 
 PLOTCFLAGS=
@@ -65,6 +69,9 @@
   PLOTLIBS="-L\$(FLTKDIR)/lib -lfltk $FLTK_LIBS"
   postconfig='-fltk-config --post '
   graph=plotfltk;;
+win32)
+  PLOTLIBS="-lgdi32"
+  graph=plotWin32;;
 esac
 graph="plotport $graph"
 
@@ -489,6 +496,8 @@
 EOT
 else
   if test -n "$export_file"; then
+    case "$osname" in
+    os2)
     cat >> $file << EOT
 
 EXPORT_FILE_BASE = $src/systems/os2/pari.def.base
@@ -502,6 +511,19 @@
 	\$(EXPORT_LIB_CREATE) -o \$@ \$(EXPORT_FILE)
 
 EOT
+    ;;
+    mingw)
+    cat >> $file << EOT
+    
+\$(EXPORT_FILE): \$(OBJS)
+	echo LIBRARY \$(LIBPARI) > \$@
+	echo EXPORTS >> \$@
+	nm --defined-only \$(OBJS) | grep -E '[0-9a-f]+ [A-Z] [^.]' | cut -d ' ' -f 3 | cut -c '2-' >> \$@
+	nm --defined-only \$(OBJS) | grep -E '[0-9a-f]+ [BCDGRS] [^.]' | cut -d ' ' -f 3 | cut -c '2-' | sed -e 's/\(.*\)/\1 DATA/'>> \$@
+
+EOT
+    ;;
+    esac
   fi
   cat >> $file << EOT
 
Index: config/paricfg.h.SH
===================================================================
--- config/paricfg.h.SH	(revision 12034)
+++ config/paricfg.h.SH	(working copy)
@@ -10,7 +10,7 @@
 
 if test -n "$perl"; then
   case "$osname" in
-    os2) gphelp="perl -S gphelp -detex" ;;
+    os2|mingw) gphelp="perl -S gphelp -detex" ;;
     *) gphelp="$bindir/gphelp" ;;
   esac
 fi
@@ -73,6 +73,19 @@
   fi
 fi
 
+if test "$osname" = "mingw"; then
+cat >> $file << EOT
+
+#undef UNIX
+#undef GPDATADIR
+#define GPDATADIR win32_GPDATADIR()
+#define GNUZCAT
+#undef ZCAT 
+#define ZCAT "gzip.exe -dc"
+
+EOT
+fi
+
 if test -n "$readline"; then
   cat >> $file <<EOT
 /*  Use GNU readline library */
Index: Configure
===================================================================
--- Configure	(revision 12034)
+++ Configure	(working copy)
@@ -125,7 +125,7 @@
 
 EOT
 case "$osname" in
-  os2) shell_q='"'; echo "shell_q='\"'"  >> $dflt_conf_file;;
+  os2|mingw) shell_q='"'; echo "shell_q='\"'"  >> $dflt_conf_file;;
     *) shell_q="'"; echo "shell_q=\"'\"" >> $dflt_conf_file;;
 esac
 
Index: src/graph/plotWin32.c
===================================================================
--- src/graph/plotWin32.c	(revision 0)
+++ src/graph/plotWin32.c	(revision 0)
@@ -0,0 +1,125 @@
+/* $Id: plotnull.c 7522 2005-12-09 18:14:24Z kb $
+
+Copyright (C) 2000  The PARI group.
+
+This file is part of the PARI/GP package.
+
+PARI/GP is free software; you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free Software
+Foundation. It is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY WHATSOEVER.
+
+Check the License for details. You should have received a copy of it, along
+with the package; see the file 'COPYING'. If not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "pari.h"
+#include "paripriv.h"
+#include "rect.h"
+#include <windows.h>
+
+static void SetForeground(void *data, long col)
+{
+	int r,g,b;
+	color_to_rgb(gel(pari_colormap,col), &r, &g, &b);
+	
+	HPEN hOldPen = SelectObject((HDC)data, CreatePen(PS_SOLID, 2, RGB(r,g,b)));
+	if( hOldPen ) DeleteObject(hOldPen);
+}
+
+static void DrawPoint(void *data, long x, long y)
+{
+	//printf("DrawPoint\n");
+	Ellipse((HDC)data,x-1,y-1,x+1,y+1);
+}
+
+static void DrawLine(void *data, long x1, long y1, long x2, long y2)
+{
+	//printf("DrawLine %d:%d %d:%d\n", x1,y1,x2,y2);
+	MoveToEx((HDC)data, x1, y1, NULL);
+	LineTo((HDC)data,x2,y2);
+}
+
+static void DrawRectangle(void *data, long x, long y, long w, long h)
+{
+	//printf("DrawRectangle %d:%d %d:%d\n", x,y,x+w,y+h);
+	RECT rc;
+	rc.left = x; rc.right  = x+w;
+	rc.top  = y; rc.bottom = y+h;
+	FrameRect((HDC)data, &rc, GetStockObject(HOLLOW_BRUSH));
+}
+
+static void DrawPoints(void *data, long nb, struct plot_points *p)
+{
+	//printf("DrawPoints\n");
+	long i;
+	for(i=0; i<nb; ++i)
+		DrawPoint(data,p[i].x,p[i].y);
+}
+
+static void DrawLines(void *data, long nb, struct plot_points *p)
+{
+	//printf("DrawLines\n");
+	long i;
+	MoveToEx((HDC)data, p[0].x, p[0].y, NULL);
+	for(i=1; i<nb; ++i)
+		LineTo((HDC)data,p[i].x,p[i].y);
+}
+
+static void DrawString(void *data, long x, long y, char *text, long numtext)
+{
+	//printf("DrawString(%d:%d %s\n",x, y, text);
+	TextOut((HDC)data, x, y, text, numtext);
+}
+
+void rectdraw0(long *w, long *x, long *y, long lw)
+{
+  char tmppath[MAX_PATH], fname[MAX_PATH];
+  struct plot_eng plotWin32;
+  HDC hEmf;
+  
+  GetTempPath(sizeof(tmppath), tmppath);
+  sprintf(fname, "%s\\gp-ploth-%x.emf", tmppath, time(NULL)/(24*60*60)*1000+GetTickCount());
+  
+  hEmf = CreateEnhMetaFile(GetDC(NULL), fname, NULL, NULL);
+  SetMapMode(hEmf, MM_TEXT);
+  SelectObject(hEmf, GetStockObject(DEFAULT_GUI_FONT));
+  SetBkColor(hEmf, RGB(255,255,255));
+  SetBkMode(hEmf, TRANSPARENT);
+  
+  plotWin32.sc=&SetForeground;
+  plotWin32.pt=&DrawPoint;
+  plotWin32.ln=&DrawLine;
+  plotWin32.bx=&DrawRectangle;
+  plotWin32.mp=&DrawPoints;
+  plotWin32.ml=&DrawLines;
+  plotWin32.st=&DrawString;
+  plotWin32.pl=&pari_plot;
+  
+  gen_rectdraw0(&plotWin32, (void*)hEmf, w, x, y, lw, 1, 1);
+  DeleteEnhMetaFile(CloseEnhMetaFile(hEmf));
+  
+  ShellExecute(NULL,NULL,fname,NULL,NULL,SW_SHOWDEFAULT);
+}
+
+void
+PARI_get_plot(long f)
+{
+	HDC hdc;
+	TEXTMETRIC tm;
+    if (pari_plot.init) return;      // pari_plot is already set
+
+    pari_plot.init    = 1;
+    pari_plot.width   = GetSystemMetrics(SM_CXSCREEN)/2;
+    pari_plot.height  = GetSystemMetrics(SM_CYSCREEN)/2;
+    pari_plot.hunit   = pari_plot.width/100;
+    pari_plot.vunit   = pari_plot.height/100;
+	
+	hdc = GetDC(0);
+	SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
+	GetTextMetrics(hdc, &tm);
+	ReleaseDC(0,hdc);
+	
+    pari_plot.fwidth  = tm.tmAveCharWidth;
+    pari_plot.fheight = tm.tmHeight;
+}
Index: src/language/es.c
===================================================================
--- src/language/es.c	(revision 12034)
+++ src/language/es.c	(working copy)
@@ -21,6 +21,9 @@
 #include "pari.h"
 #include "paripriv.h"
 #include "anal.h"
+#ifdef _WIN32
+#include <windows.h>
+#endif
 
 typedef struct outString {
   char *string; /* start of the output buffer */
@@ -376,7 +379,11 @@
 static void
 normalOutS(const char *s)
 {
+#ifdef _WIN32
+   win32_ansi_fputs(s, pari_outfile);
+#else
   fputs(s, pari_outfile);
+#endif
   if (pari_logfile) { fputs(s, pari_logfile); }
 }
 static void
@@ -396,7 +403,11 @@
 static void
 normalErrS(const char *s)
 {
+#ifdef _WIN32
+   win32_ansi_fputs(s, pari_errfile);
+#else
   fputs(s, pari_errfile);
+#endif
   if (pari_logfile) fputs(s, pari_logfile);
 }
 static void
@@ -1340,6 +1351,9 @@
 term_width_intern(void)
 {
   if (GP_DATA->flags & TEST) return 0;
+#ifdef _WIN32
+  return win32_terminal_width();
+#endif
 #ifdef HAS_TIOCGWINSZ
   {
     struct winsize s;
@@ -1364,6 +1378,9 @@
 term_height_intern(void)
 {
   if (GP_DATA->flags & TEST) return 0;
+#ifdef _WIN32
+  return win32_terminal_height();
+#endif
 #ifdef HAS_TIOCGWINSZ
   {
     struct winsize s;
@@ -2999,6 +3016,9 @@
 #  endif
 #  define HAVE_PIPES
 #endif
+#if defined(_WIN32)
+#  define HAVE_PIPES
+#endif
 #ifndef O_RDONLY
 #  define O_RDONLY 0
 #endif
@@ -3481,7 +3501,18 @@
 char *
 path_expand(const char *s)
 {
+#ifdef _WIN32
+  char *ss, *p;
+  ss = malloc(strlen(s)+1);
+  strcpy(ss,s);
+  for(p = ss; *p != 0; ++p) 	
+	if( *p == '\\' ) *p = '/';
+  p = _expand_env(_path_expand(ss));
+  free(ss);
+  return p;
+#else
   return _expand_env(_path_expand(s));
+#endif
 }
 
 void
@@ -3631,6 +3662,13 @@
 static int
 is_absolute(char *s)
 {
+#ifdef _WIN32
+  if( (*s >= 'A' && *s <= 'Z') || 
+      (*s >= 'a' && *s <= 'z') )
+  {
+      return *(s+1) == ':';
+  }
+#endif
   if (*s == '/') return 1;
   if (*s++ != '.') return 0;
   if (*s == '/') return 1;
@@ -4166,6 +4204,11 @@
 }
 static int
 pari_dir_exists(const char *s) { return mkdir(s, 0777); }
+#elif defined(_WIN32)
+static int
+pari_file_exists(const char *s) { return GetFileAttributesA(s) != ~0; }
+static int
+pari_dir_exists(const char *s) { return mkdir(s); }
 #else
 static int
 pari_file_exists(const char *s) { return 0; }
@@ -4239,7 +4282,7 @@
 #ifdef __EMX__
     if (!unix_shell())
 #endif
-#if defined(__EMX__) || defined(WINCE)
+#if defined(__EMX__) || defined(WINCE) || defined(_WIN32) 
     {
       char *t;
       for (t=s; *t; t++)
Index: src/systems/mingw/mingw.c
===================================================================
--- src/systems/mingw/mingw.c	(revision 0)
+++ src/systems/mingw/mingw.c	(revision 0)
@@ -0,0 +1,93 @@
+#include <windows.h>
+#include <stdio.h>
+
+const char* 
+win32_GPDATADIR()
+{
+    static char datadir[1024] = {0};
+    if( 0 == *datadir ) {
+        char* slash;
+        GetModuleFileNameA(0, datadir, sizeof(datadir) );
+        slash = strrchr(datadir, '\\');
+        if( slash ) *(slash+1) = 0;
+        //while( (slash = strchr(datadir, '\\')) )
+        //    *slash = '/';
+        strcat(datadir, "gp-data");
+    }
+    return datadir;
+}
+
+static WORD 
+win32_console_color(unsigned long c)
+{
+	int shift, intense = 0;
+	if( c >= 30 && c <= 37 ) { shift = 0; c %= 30; } else
+	if( c >= 40 && c <= 47 ) { shift = 4; c %= 40; } else
+	if( c >= 90 && c <= 97 ) { shift = 0; intense = 8; c %= 90; } else
+	if(c >= 100 && c <= 107) { shift = 4; intense = 8; c %= 100; } else
+	return 0;
+	
+	WORD w = 0;
+	switch(c) {
+	case 0: w = 0; break; //black
+	case 1: w = 4; break; //red
+	case 2: w = 2; break; //green
+	case 3: w = 6; break; //yellow RG
+	case 4: w = 1; break; //blue
+	case 5: w = 5; break; //magenta RB
+	case 6: w = 3; break; //cyan GB
+	case 7: w = 7; break; //white RGB
+	}
+	return (w|intense) << shift;
+}
+
+void
+win32_ansi_fputs(const char* s, void* f)
+{
+	if( !(f == stdout || f == stderr) ) {
+		fputs(s,f);
+		return;
+	}
+	
+	while(1) {
+		const char *p;
+		p = strstr(s, "\x1b[");
+		if( p > s )
+			fwrite(s,p-s,1,f);
+			
+		if( p ) 
+			p += 2; 
+		else {
+			(fputs)(s,f);
+			return;
+		}
+		
+		WORD color = 7;
+		unsigned long a1=0,a2=0,a3=0; 
+		a1 = strtoul(p,&p,10);
+		if( *p == ';' ) a2 = strtoul(p+1,&p,10);
+		if( *p == ';' ) a3 = strtoul(p+1,&p,10);
+		if( *p++ == 'm' ) {
+			if( a2|a3 ) 
+				color = win32_console_color(a2) | win32_console_color(a3);
+		}
+		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),color);
+		s = p;
+	}
+}
+
+int win32_terminal_width()
+{
+  CONSOLE_SCREEN_BUFFER_INFO sbi;
+  if( !GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &sbi) )
+      return 0;
+  return (sbi.srWindow.Right - sbi.srWindow.Left);
+}
+
+int win32_terminal_height()
+{
+  CONSOLE_SCREEN_BUFFER_INFO sbi;
+  if( !GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &sbi) )
+      return 0;
+  return (sbi.srWindow.Bottom - sbi.srWindow.Top);
+}
Index: src/test/dotest
===================================================================
--- src/test/dotest	(revision 12034)
+++ src/test/dotest	(working copy)
@@ -74,7 +74,7 @@
            gp=$execdir/gp-$suf;;
     esac
     (cat $file_in; echo 'print("Total time spent: ",gettime);') | $gp -q --test  > $file_test 2>&1
-    diff -c $file_out $file_test > $file_diff
+    diff -cwb $file_out $file_test > $file_diff
     pat=`grep "^[-+!] " $file_diff | grep -v "Total time"`
     time=`${tail}1 $file_test | sed -n 's,.*Total time spent: \(.*\),\1,p'`
     if test -n "$time"; then