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