Ilya Zakharevich on Wed, 16 Oct 2002 23:05:23 -0700


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

[PATCH CVS] dynamic linking on OS/2


This patch

  a) Adds a new file README.os2 (please update the distribution-build process);

  b) Enables the dynamic-linking build on OS/2 (with the limitation
     discussed in README.os2);

  c) Enables (on EMX) the style of signal handling (SysV style) which the PARI
     core expects;

	Before: One could interrupt GP only twice: once by ^C, once by ^Break;
		The second-time deliveries of these signals did not
		achieve anything.

	Now:	^Break still works only once (?!).  But ^C works reliably.

     (The difference between BSD-style and SysV-style is still voodoo
     for me, I just tried to compile with no switches, with -Zbsd-signals
     and -Zsysv-signals, and choose what work best.  ;-)

  d) Enables the same optimizations flags for OS/2 as for Linux.

  e) Better emulation of dlopen(NULL, flags) on OS/2.  The old version
     was relying on installing load/unload-DLL callbacks which does
     not scale well (would not work if the static PARI library would be
     included in some third-party DLL which wants to install such a
     callback itself).

  f) Fixes a wrong error message from the dlopen() imlementation (in a
     branch which probably would never be reached by PARI ;-]).

Enjoy,
Ilya

--- ./config/Makefile.SH-pre1	Tue Oct 15 23:32:52 2002
+++ ./config/Makefile.SH	Wed Oct 16 21:36:22 2002
@@ -32,8 +32,15 @@ esac
 language=`ls $src_dir/language/*.c | sed 's,.*/\(.*\)\.c,\1,'`
 basemath=`ls $src_dir/basemath/*.c | sed 's,.*/\(.*\)\.c,\1,'`
 modules=`ls $src_dir/modules/*.c   | sed 's,.*/\(.*\)\.c,\1,'`
+lib_prefix=lib
+dllib_prefix=lib
 case "$osname" in
-  os2) systems=os2;;
+  os2)	systems=os2; dllib_prefix="";
+	lib_prefix=lib	# Different, to allow gp-dyn link with DLL
+	export_lib_create=emximp; export_lib='$(DLLIBPARI)$(_A)'
+	export_file=pari.def; export_create="emxexp -u"
+	# Actually, the build will fail until the switch to -Zomf...
+	dlld_ignore=- ;;
   *)   systems=;;
 esac
 
@@ -195,12 +202,15 @@ AS         = $AS
 ASFLAGS    = $ASFLAGS
 AR	   = ar
 
-CC         = $CC
+CC_FLAVOR  =
+CC         = $CC \$(CC_FLAVOR)
 CPPFLAGS   = $CPPFLAGS
 CFLAGS     = $cflags
-LD         = $LD
+LD_FLAVOR  = \$(CC_FLAVOR)
+LD         = $LD \$(LD_FLAVOR)
 LDFLAGS    = $LDFLAGS
-DLLD       = $DLLD
+DLLD_FLAVOR  = \$(LD_FLAVOR)
+DLLD       = $DLLD \$(DLLD_FLAVOR)
 DLLDFLAGS  = $DLLDFLAGS
 EXTRADLLDFLAGS = $EXTRADLLDFLAGS
 CPP        = $CPP
@@ -221,12 +231,20 @@ CPP        = $CPP
 
 _O	   = .o
 _A	   = .a
-LIB_PREFIX = lib
-LIBPARI    = \$(LIB_PREFIX)$libpari_base
-LIBPARI_STA= \$(LIBPARI)\$(_A)
-LIBPARI_SO = \$(LIBPARI).$DLSUFFIX
+LIB_PREFIX = $lib_prefix
+DLLIB_PREFIX = $dllib_prefix
+LIBPARI_BASE = $libpari_base
+LIBPARI      = \$(LIB_PREFIX)\$(LIBPARI_BASE)
+DLLIBPARI    = \$(DLLIB_PREFIX)\$(LIBPARI_BASE)
+LIBPARI_STA  = \$(LIBPARI)\$(_A)
+LIBPARI_SO   = \$(DLLIBPARI).$DLSUFFIX
 LIBPARI_DYN   = \$(LIBPARI_SO)$sodest
 LIBPARI_SONAME= \$(LIBPARI_SO)$soname
+EXPORT_FILE   = $export_file
+EXPORT_CREATE = $export_create
+EXPORT_LIB = $export_lib
+EXPORT_LIB_CREATE = $export_lib_create
+DLLD_IGNORE = $dlld_ignore
 
 RUNPTH       = $RUNPTH
 RUNPTH_FINAL = $RUNPTH_FINAL
@@ -240,6 +258,7 @@ DYNRELOC     = $DYNRELOC
 RM = rm -f
 MV = mv -f
 LN = $ln_s
+CP_F = cp -f
 
 # Change these installation directories to suit your needs.
 # DESTDIR is used to install to a false hierachy (to build a Debian package)
@@ -504,15 +523,32 @@ if test -z "$DLLD"; then
 
 EOT
 else
+  if test -n "$export_file"; then
+    cat >> $file << EOT
+
+EXPORT_FILE_BASE = $src/systems/os2/pari.def.base
+VERSION_VERBOSE = $pari_release_verbose
+
+\$(EXPORT_FILE): \$(OBJS) \$(EXPORT_FILE_BASE)
+	cat \$(EXPORT_FILE_BASE) | sed 's/<DLL_BASE>/\$(DLLIBPARI)/' | sed 's/<VENDOR>/www.parigp-home.de\//' | sed 's/<VERSION>/\$(VERSION_VERBOSE)/' | sed 's/<DESCR>/GP\/PARI compiled with \$(CFLAGS)/' > \$@
+	\$(EXPORT_CREATE) \$(OBJS) >> \$@
+
+\$(DLLIBPARI)\$(_A): \$(EXPORT_FILE)
+	\$(EXPORT_LIB_CREATE) -o \$@ \$(EXPORT_FILE)
+
+EOT
+  fi
   if test -z "$DYNLIBS"; then
     cat >> $file << EOT
-gp-dyn: \$(OBJSGP) \$(LIBPARI_DYN) \$(GNUPLOT_OBJS)
+
+gp-dyn: \$(OBJSGP) \$(LIBPARI_DYN) \$(GNUPLOT_OBJS) \$(EXPORT_LIB)
 	\$(RM) \$@
 	\$(LD) -o \$@ \$(LDFLAGS) \$(OBJSGP) \$(GNUPLOT_OBJS) \$(RUNPTH) \$(TOPLDDYN) \$(LDDYN) \$(PLOTLIBS) \$(LIBS)
 
-\$(LIBPARI_DYN): \$(OBJS)
+\$(LIBPARI_DYN): \$(OBJS) \$(EXPORT_FILE)
 	-\$(RM) \$(LIBPARI_DYN)
-	\$(DLLD) -o \$@ \$(DLLDFLAGS) \$(OBJS) \$(EXTRADLLDFLAGS)
+	\$(DLLD_IGNORE)\$(DLLD) -o \$@ \$(DLLDFLAGS) \$(OBJS) \$(EXTRADLLDFLAGS) \$(EXPORT_FILE)
+
 EOT
     if test "$soname" != "$sodest"; then
       cat >> $file << EOT
--- ./Configure-pre1	Tue Oct 15 23:46:48 2002
+++ ./Configure	Wed Oct 16 22:37:18 2002
@@ -37,14 +37,15 @@ extract_dir_list="$doc_dir $emacs_dir $m
 # Version number and patch level.
 . $config_dir/version
 version=$VersionMajor.$VersionMinor
-pari_release="$VersionMajor.$VersionMinor.$patch"
+pari_release="$version.$patch"
 if test `expr $VersionMinor % 2` = 1; then
-  echo "Configuring pari-$version.$patch (STABLE)"
+  pari_release_verbose="$pari_release (STABLE)"
   libpari_base=pari
 else
-  echo "Configuring pari-$version.$patch (DEVELOPMENT VERSION)"
+  pari_release_verbose="$pari_release (DEVELOPMENT VERSION)"
   libpari_base=pari-$version
 fi
+echo "Configuring pari-$pari_release_verbose"
 
 cd $config_dir
 
@@ -518,11 +519,12 @@ if test -n "$__gnuc__"; then
   case "$osname-$arch" in hpux-*) DLCFLAGS=-fPIC;; esac
   # Specific optimisations for some architectures
   case "$osname-$arch" in
-    linux-i?86|cygwin*) OPTFLAGS="$OPTFLAGS \
+    linux-i?86|cygwin*|os2-*) OPTFLAGS="$OPTFLAGS \
       -malign-loops=2 -malign-jumps=2 -malign-functions=2";;
-    os2-*) cflags=-Zmt;;
     *-sparcv8*) cflags=-mv8;;
   esac
+  if test "X$osname" = os2; then cflags=-Zmt; fi
+
   # omit-frame-pointer incompatible with -pg
   PRFFLAGS="-pg $OPTFLAGS"
   case "$optimization" in
@@ -639,9 +641,10 @@ case "$osname-$arch" in
 	full|profiling) LDFLAGS="-g0 -O4 $LDFLAGS";;
       esac;;
   solaris-*) LD=$CC; LDFLAGS=$cflags; runpathprefix=-R ;;
-  os2-*)     LD=$CC; LDFLAGS="$cflags -Zexe"
+  os2-*)     LD=$CC;  cflags="$cflags -Zsysv-signals"; LDFLAGS="$cflags -Zexe"
+	     DLLD=$LD; DLLDFLAGS="$cflags -Zdll"
       case "$optimization" in
-	full) LDFLAGS="$LDFLAGS -s";;
+	full) LDFLAGS="$LDFLAGS -s"; DLLDFLAGS="$DLLDFLAGS -s";;
       esac;;
   *)         LD=$CC; LDFLAGS=$cflags ;;
 esac
@@ -685,6 +688,10 @@ if test "$optimization" = profiling; the
 #   cygwin*) soname= ; sodest= ; DLSUFFIX=dll;;
     hpux-*)  soname= ; sodest= ; DLSUFFIX=sl;;
     irix-*)  soname= ; sodest= ;;
+    os2-*)  soname= ; sodest= ; DLSUFFIX=dll
+	    # DLL names better be 8+3
+	    libpari_base=`echo "$libpari_base" | sed 's/\./_/g'`
+	 ;;
     *) DLLD=;;
   esac
 fi
@@ -720,6 +727,7 @@ if test -n "$DLLD"; then
          esac;;
       sunos-*)   DLLDFLAGS="-assert nodefinitions" ;;
       solaris-*) DLLDFLAGS="-G -h \$(LIBPARI_SONAME)" ;;
+      os2-*)	 ;;
       *)         DLLD=;;
     esac
   fi
@@ -1374,7 +1382,7 @@ case "$osname" in
 esac
 
 for variable in\
-  pari_release\
+  pari_release pari_release_verbose\
   libpari_base version TOP config_dir src_dir emacs_dir doc_dir\
   bindir includedir mandir miscdir libdir datadir\
   optimization objdir static suffix\
--- ./src/systems/os2/pari.def.base-pre1	Sun Jun  9 11:15:08 2002
+++ ./src/systems/os2/pari.def.base	Wed Oct 16 21:25:20 2002
@@ -1,6 +1,7 @@
-LIBRARY 'pari' INITINSTANCE TERMINSTANCE
-; Can't put http://www.parigp-home.de/, since it is split on :
-DESCRIPTION '@#www.parigp-home.de/:@VERSION@#@GP/PARI compiled with @CFLAGS@
+LIBRARY '<DLL_BASE>' INITINSTANCE TERMINSTANCE
+; Can't put http://www.parigp-home.de/ in VENDOR, since it is split on :
+; One needs to be glad that www.parigp-home.de/ is good enough...
+DESCRIPTION '@#<VENDOR>:<VERSION>#@<DESCR>'
 CODE LOADONCALL
 DATA LOADONCALL NONSHARED MULTIPLE
 EXPORTS
--- ./src/systems/os2.c-pre1	Sun Jun  9 11:15:08 2002
+++ ./src/systems/os2.c	Wed Oct 16 03:58:12 2002
@@ -33,6 +33,36 @@ unsigned long _DLL_InitTerm(unsigned lon
 
 #endif
 
+HMODULE
+find_myself(void)
+{
+
+  static APIRET APIENTRY (*pDosQueryModFromEIP) (HMODULE * hmod, ULONG * obj, ULONG BufLen, PCHAR Buf,
+		    ULONG * Offset, ULONG Address);
+  HMODULE doscalls_h, mod;
+  static int failed;
+  ULONG obj, offset, rc;
+  char buf[260];
+
+  if (failed)
+	return 0;
+  failed = 1;
+  doscalls_h = (HMODULE)dlopen("DOSCALLS",0);
+  if (!doscalls_h)
+	return 0;
+/*  {&doscalls_handle, NULL, 360}, */	/* DosQueryModFromEIP */
+  rc = DosQueryProcAddr(doscalls_h, 360, 0, (PFN*)&pDosQueryModFromEIP);
+  if (rc)
+	return 0;
+  rc = pDosQueryModFromEIP(&mod, &obj, sizeof(buf), buf, &offset, (ULONG)dlopen);
+  if (rc)
+	return 0;
+  failed = 0;
+  handle_found = 1;
+  dllHandle = mod;
+  return mod;
+}
+
 void *
 dlopen(char *path, int mode)
 {
@@ -43,22 +73,25 @@ dlopen(char *path, int mode)
 
 	fail[0] = 0;
 	if (!path) {			/* Our own handle. */
-	    if (handle_found) {
+	    if (handle_found || find_myself()) {
 		if (handle_loaded)
 		    return (void*)dllHandle;
 		rc = DosQueryModuleName(dllHandle, sizeof(dllname), dllname);
 		if (rc) {
 	            strcpy(fail, "can't find my DLL name by the handle");
+		    retcode = rc;
 		    return 0;
 		}
 		rc = DosLoadModule(fail, sizeof fail, dllname, &handle);
 		if (rc) {
 	            strcpy(fail, "can't load my own DLL");
+		    retcode = rc;
 		    return 0;
 		}
 		handle_loaded = 1;
 		goto ret;
 	    }
+	    retcode = ERROR_MOD_NOT_FOUND;
             strcpy(fail, "can't load from myself: compiled without -DDLOPEN_INITTERM");
 	    return 0;
 	}
@@ -78,8 +111,10 @@ dlopen(char *path, int mode)
 		int n = beg+8-path;
 		memmove(tmp, path, n);
 		memmove(tmp+n, dot, strlen(dot)+1);
-		if (DosLoadModule(fail, sizeof fail, tmp, &handle) == 0)
+		rc = DosLoadModule(fail, sizeof fail, tmp, &handle);
+		if (rc == 0)
 			goto ret;
+		retcode = rc;
 	}
 	handle = 0;
 
@@ -88,6 +123,8 @@ dlopen(char *path, int mode)
 	return (void *)handle;
 }
 
+#define ERROR_WRONG_PROCTYPE 0xffffffff
+
 void *
 dlsym(void *handle, char *symbol)
 {
@@ -100,7 +137,7 @@ dlsym(void *handle, char *symbol)
 		rc = DosQueryProcType((HMODULE)handle, 0, symbol, &type);
 		if (rc == 0 && type == PT_32BIT)
 			return (void *)addr;
-		rc = ERROR_CALL_NOT_IMPLEMENTED;
+		rc = ERROR_WRONG_PROCTYPE;
 	}
 	retcode = rc;
 	return NULL;
@@ -114,8 +151,13 @@ dlerror(void)
 
 	if (retcode == 0)
 		return NULL;
-	if (DosGetMessage(NULL, 0, buf, sizeof buf - 1, retcode,
-			  "OSO001.MSG", &len)) {
+	if (retcode == ERROR_WRONG_PROCTYPE) {
+		strcpy(buf, "Wrong procedure type");
+		len = strlen(buf);
+	}
+	if ((retcode != ERROR_WRONG_PROCTYPE)
+	    && DosGetMessage(NULL, 0, buf, sizeof buf - 1, retcode,
+			     "OSO001.MSG", &len)) {
 		if (fail[0])
 		  sprintf(buf, 
 "OS/2 system error code %d, possible problematic module: '%s'",
--- ./README.os2-pre1	Wed Oct 16 21:54:16 2002
+++ ./README.os2	Wed Oct 16 22:45:24 2002
@@ -0,0 +1,42 @@
+On OS/2 the build goes the same way as on Unix, e.g.,
+
+  sh Configure
+  make gp
+  make bench
+
+With the current implementation of install(), one can load the functions from
+the PARI library only if the GP executable is build for dynamic linking.
+
+By default, the build will go to an AOUT-type executables (to simplify
+the logic of Configure, and enable restricted binary compatibility with
+DOS/Windows).  Unfortunately, AOUT-type DLLs are very restricted; thus
+the build of dynamically linked target fails.
+
+To build with OMF-type target
+
+  cd Oos2-ix86
+  make _O=.obj _A=.lib CC_FLAVOR="-Zomf -Zcrtdll" RLLIBS=-lreadline_import DLLD_IGNORE= bench
+
+This build constructs a working DLL.  Both -Zomf and -Zcrtdll are crucial to
+have a functioning DLL (see EMX documentation for details).
+Use of the the readline-DLL (via the readline_import.lib library) is not only
+a convenience, but also statically linked readline library are often broken;
+sigh...
+
+To use the gnuplot-engine DLL gnpltdrw.DLL, one can give Configure the option
+--graphic=gnuplot-dynamic,gnpltdrw.  Thus the build process looks like this:
+
+  sh Configure --graphic=gnuplot-dynamic,gnpltdrw
+  make gp
+  cd Oos2-ix86
+  make _O=.obj _A=.lib CC_FLAVOR="-Zomf -Zcrtdll" RLLIBS=-lreadline_import DLLD_IGNORE= bench
+  cd ..
+
+The statically build PARI library is in a file named similar to libpari-2_2.a,
+the library for linking with the PARI DLL is named as pari-2_2.a (or
+pari-2_2.lib).
+
+As a debugging tool, the constructed DLL reports its build options via the
+standard OS/2 way:
+
+  bldlevel FULL_NAME_OF_THE_DLL