plugin-test
Bryce Denney

This is a series of simple programs that test your platform for shared 
library support.  The tests start from something trivial that should 
work everywhere, and gradually add one feature at a time, until at 
the end (not done yet) it should test all of the shared library 
features that Bochs needs to support plugins.

test1-static: build a static library and link against it
test2-dynamic: with same code, build a shared library and link against it
test3-twomodules: build 2 shared libs and link against them
test4-interdep: build 2 shared libs, one depends on the other, and link
test5-execsymbols: can a shared lib can access a symbol from the executable?
test6-ltdlopen: use ltdl library to dlopen modules, should work on many
  platforms, but doesn't seem to work on win32.
test7-win32dll: same as test6-ltdlopen but specific to win32 DLLs
test8-execlass: define a C++ class in main, use it from the modules
test9-modclass: define a C++ class in a module, use it from main
test10-modvirtual: define an abstract interface with instantiations in modules
test11-modglobalconstr: test if global constructors in shared libs are called
test12-modglobalconstr2: work around lack of global constructors, if needed

-----------------------------------------------------------------------
Results of platform testing:

x86 Linux:
passing: 1,2,3,4,5,6,8,9,10,11,12.
This platform will support plugins.
   
Cygwin with these environment variables (Mingw):
  export CPPFLAGS=-mno-cygwin; 
  export CFLAGS=-mno-cygwin
  export CXXFLAGS=-mno-cygwin; 
  export LDFLAGS=-mno-cygwin
passing 1,6,7,8,9,10,11,12.
When compiling in Cygwin, Bochs always compiles with -mno-cygwin, so
this is the normal build environment.  This platform will support plugins.

Cygwin without -mno-cygwin:
passing: 1,2,3,4.  failing 5-12.
This platform will NOT support plugins yet.

Solaris:
passing: 1,2,3,4,5,6,8,9,10,12.
This platform will support plugins.
NOTE: Global constructors in shared modules are not executed when
the module is loaded.  That is why test 11 fails.  As long as we don't depend
on global constructors, Solaris plugins should work fine.

MacOS X:
passing: 1,2,3,4,5,6,8,9,10,11,12.
This platform will support plugins.
NOTE: You must have the dlcompat library installed where configure can
find it.  On the SF compile farm, I use these commands before configure:
   export LIBS='-L/sw/lib'
   export CFLAGS='-I/sw/include'
   export CPPFLAGS='-I/sw/include'
   export CXXFLAGS='-I/sw/include'
NOTE: On MacOS X we cannot have the same symbol name in two different
modules; we must name the symbols so that the symbol names are unique.  In
tests 6,7-12, the modules.h file uses #defines to rename each global symbol
to something unique.

No other platform data is available.
To check for plugin support on other platforms, run "do_tests.sh" and
send the results to Bryce.
-----------------------------------------------------------------------




Notes for win32 DLLs:

*.dll.a is an import library

libtool makes an import library when you link against a DLL

dlltool --as=as --dllname cygmodule2-0.dll --def .libs/cygmodule2-0.dll-def --output-lib .libs/libimp-cygmodule2-0.a

the dll-def file is created at the time that the DLL is created.

Exporting a class from a DLL...
http://www.codeguru.com/win32/dyndllclass.shtml




Win32 DLL Topics
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_core_dll_topics.asp

------
Mutual DLL imports
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_core_mutual_imports.asp

Exporting or importing to another executable file presents complications when
the imports are mutual (or "circular"). For example, two DLLs import symbols
from each other, similar to mutually-recursive functions.

The problem with mutually-importing executable files (usually DLLs) is that
neither can be built without building the other first. Each build process
requires, as input, an import library produced by the other build process.

The solution is to use the LIB utility with the /DEF option, which produces an
import library without building the executable file. Using this utility, you
can build all the import libraries you need, no matter how many DLLs are
involved or how complicated the dependencies are.

The general solution for handling mutual imports is: 

1.Take each DLL in turn. (Any order is feasible, although some orders are more
optimal.) If all the needed import libraries exist and are current, run LINK to
build the executable file (DLL). This produces an import library. Otherwise,
run LIB to produce an import library.

Running LIB with the /DEF option produces an additional file with an .EXP
extension. The .EXP file must be used later to build the executable file.

2.After using either LINK or LIB to build all the import libraries, go back and
run LINK to build any executable files that were not built in the previous
step. Note that the corresponding .EXP file must be specified on the LINK line.

If you had run the LIB utility earlier to produce an import library for DLL1,
LIB would have produced the file DLL1.EXP as well. You must use DLL1.EXP as
input to LINK when building DLL1.DLL.
-----------

this makes a symbol table for a file

dlltool.exe  --export-all --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 --output-def def.txt uselib.exe

These lines from  test4 show that libtool does know how to make
import libraries:
> generating import library for `cygmodule1-0.dll'
> dlltool --as=as --dllname cygmodule1-0.dll --def .libs/cygmodule1-0.dll-def --output-lib .libs/libimp-cygmodule1-0.a

Now what I want to see is generation of an import library corresponding to
a BINARY.


/bin/sh.exe ../libtool g++ -g -O2 -c module1.cc
mkdir .libs
g++ -g -O2 -c module1.cc  -DDLL_EXPORT -DPIC -o .libs/module1.lo
In file included from module1.cc:2:
module1.h:4: warning: #warning I will export DLL symbols for MODULE1
In file included from module1.cc:3:
module2.h:8: warning: #warning I will import DLL symbols for MODULE2
g++ -g -O2 -c module1.cc -o module1.o >/dev/null 2>&1
mv -f .libs/module1.lo module1.lo
/bin/sh.exe ../libtool g++ -g -O2 -c module2.cc
rm -f .libs/module2.lo
g++ -g -O2 -c module2.cc  -DDLL_EXPORT -DPIC -o .libs/module2.lo
In file included from module2.cc:3:
module2.h:4: warning: #warning I will export DLL symbols for MODULE2
g++ -g -O2 -c module2.cc -o module2.o >/dev/null 2>&1
mv -f .libs/module2.lo module2.lo
/bin/sh.exe ../libtool g++ -no-undefined -o libmodule2.la module2.lo -rpath `pwd`/lib
rm -fr .libs/libmodule2.la .libs/libmodule2.* .libs/libmodule2.*
generating symbol list for `libmodule2.la'
 dlltool --export-all --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 --output-def .libs/cygmodule2-0.dll-def  module2.lo 
 sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]*//" -e "s/ *;.*$//" < .libs/cygmodule2-0.dll-def > .libs/libmodule2.exp
if test "x`head -1 .libs/libmodule2.exp`" = xEXPORTS; then cp .libs/libmodule2.exp .libs/cygmodule2-0.dll-def; else echo EXPORTS > .libs/cygmodule2-0.dll-def; _lt_hint=1; cat .libs/libmodule2.exp | while read symbol; do set dummy $symbol; case $# in 2) echo " $2 @ $_lt_hint ; " >> .libs/cygmodule2-0.dll-def;; *) echo " $2 @ $_lt_hint $3 ; " >> .libs/cygmodule2-0.dll-def;; esac; _lt_hint=`expr 1 + $_lt_hint`; done; fi
 gcc -Wl,--base-file,.libs/cygmodule2-0.dll-base -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o .libs/cygmodule2-0.dll  module2.lo  
 dlltool --as=as --dllname cygmodule2-0.dll --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 --def .libs/cygmodule2-0.dll-def --base-file .libs/cygmodule2-0.dll-base --output-exp .libs/cygmodule2-0.dll-exp
 gcc -Wl,--base-file,.libs/cygmodule2-0.dll-base .libs/cygmodule2-0.dll-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o .libs/cygmodule2-0.dll  module2.lo  
 dlltool --as=as --dllname cygmodule2-0.dll --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 --def .libs/cygmodule2-0.dll-def --base-file .libs/cygmodule2-0.dll-base --output-exp .libs/cygmodule2-0.dll-exp --output-lib .libs/libmodule2.dll.a
 gcc .libs/cygmodule2-0.dll-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o .libs/cygmodule2-0.dll  module2.lo  
ar cru .libs/libmodule2.a  module2.o 
ranlib .libs/libmodule2.a
creating libmodule2.la
(cd .libs && rm -f libmodule2.la && ln -s ../libmodule2.la libmodule2.la)
mkdir -p lib bin
/bin/sh.exe ../libtool cp libmodule2.la `pwd`/lib
cp .libs/libmodule2.dll.a /home/bryce/bochs-testing/plugin-test/test4-interdep/lib/libmodule2.dll.a
dlpath=`bash 2>&1 -c '. .libs/libmodule2.lai;echo $dlname'`
 dldir=/home/bryce/bochs-testing/plugin-test/test4-interdep/lib/`dirname $dlpath`
 test -d $dldir || mkdir -p $dldir
 cp .libs/cygmodule2-0.dll $dldir/cygmodule2-0.dll
cp .libs/libmodule2.lai /home/bryce/bochs-testing/plugin-test/test4-interdep/lib/libmodule2.la
cp .libs/libmodule2.a /home/bryce/bochs-testing/plugin-test/test4-interdep/lib/libmodule2.a
ranlib /home/bryce/bochs-testing/plugin-test/test4-interdep/lib/libmodule2.a
chmod 644 /home/bryce/bochs-testing/plugin-test/test4-interdep/lib/libmodule2.a
----------------------------------------------------------------------
Libraries have been installed in:
   /home/bryce/bochs-testing/plugin-test/test4-interdep/lib

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the `PATH' environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH' environment variable
     during linking
   - use the `-Wl,--rpath -Wl,LIBDIR' linker flag

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
/bin/sh.exe ../libtool g++ -no-undefined -o libmodule1.la module1.lo -rpath `pwd`/lib libmodule2.la
generating import library for `cygmodule2-0.dll'
dlltool --as=as --dllname cygmodule2-0.dll --def .libs/cygmodule2-0.dll-def --output-lib .libs/libimp-cygmodule2-0.a
rm -fr .libs/libmodule1.la .libs/libmodule1.* .libs/libmodule1.*
generating symbol list for `libmodule1.la'
 dlltool --export-all --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 --output-def .libs/cygmodule1-0.dll-def  module1.lo 
 sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]*//" -e "s/ *;.*$//" < .libs/cygmodule1-0.dll-def > .libs/libmodule1.exp
if test "x`head -1 .libs/libmodule1.exp`" = xEXPORTS; then cp .libs/libmodule1.exp .libs/cygmodule1-0.dll-def; else echo EXPORTS > .libs/cygmodule1-0.dll-def; _lt_hint=1; cat .libs/libmodule1.exp | while read symbol; do set dummy $symbol; case $# in 2) echo " $2 @ $_lt_hint ; " >> .libs/cygmodule1-0.dll-def;; *) echo " $2 @ $_lt_hint $3 ; " >> .libs/cygmodule1-0.dll-def;; esac; _lt_hint=`expr 1 + $_lt_hint`; done; fi
 gcc -Wl,--base-file,.libs/cygmodule1-0.dll-base -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o .libs/cygmodule1-0.dll  module1.lo  .libs/libimp-cygmodule2-0.a 
 dlltool --as=as --dllname cygmodule1-0.dll --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 --def .libs/cygmodule1-0.dll-def --base-file .libs/cygmodule1-0.dll-base --output-exp .libs/cygmodule1-0.dll-exp
 gcc -Wl,--base-file,.libs/cygmodule1-0.dll-base .libs/cygmodule1-0.dll-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o .libs/cygmodule1-0.dll  module1.lo  .libs/libimp-cygmodule2-0.a 
 dlltool --as=as --dllname cygmodule1-0.dll --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 --def .libs/cygmodule1-0.dll-def --base-file .libs/cygmodule1-0.dll-base --output-exp .libs/cygmodule1-0.dll-exp --output-lib .libs/libmodule1.dll.a
 gcc .libs/cygmodule1-0.dll-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o .libs/cygmodule1-0.dll  module1.lo  .libs/libimp-cygmodule2-0.a 
ar cru .libs/libmodule1.a  module1.o 
ranlib .libs/libmodule1.a
creating libmodule1.la
(cd .libs && rm -f libmodule1.la && ln -s ../libmodule1.la libmodule1.la)
mkdir -p lib bin
/bin/sh.exe ../libtool cp libmodule1.la `pwd`/lib
libtool: install: warning: relinking `libmodule1.la'
cd /home/bryce/bochs-testing/plugin-test/test4-interdep; /bin/sh ../libtool --mode=relink g++ -no-undefined -o libmodule1.la module1.lo -rpath /home/bryce/bochs-testing/plugin-test/test4-interdep/lib libmodule2.la
generating symbol list for `libmodule1.la'
 dlltool --export-all --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 --output-def .libs/cygmodule1-0.dll-def  module1.lo 
 sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]*//" -e "s/ *;.*$//" < .libs/cygmodule1-0.dll-def > .libs/libmodule1.exp
if test "x`head -1 .libs/libmodule1.exp`" = xEXPORTS; then cp .libs/libmodule1.exp .libs/cygmodule1-0.dll-def; else echo EXPORTS > .libs/cygmodule1-0.dll-def; _lt_hint=1; cat .libs/libmodule1.exp | while read symbol; do set dummy $symbol; case $# in 2) echo " $2 @ $_lt_hint ; " >> .libs/cygmodule1-0.dll-def;; *) echo " $2 @ $_lt_hint $3 ; " >> .libs/cygmodule1-0.dll-def;; esac; _lt_hint=`expr 1 + $_lt_hint`; done; fi
 gcc -Wl,--base-file,.libs/cygmodule1-0.dll-base -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o .libs/cygmodule1-0.dll  module1.lo  -L/home/bryce/bochs-testing/plugin-test/test4-interdep/lib -lmodule2 
 dlltool --as=as --dllname cygmodule1-0.dll --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 --def .libs/cygmodule1-0.dll-def --base-file .libs/cygmodule1-0.dll-base --output-exp .libs/cygmodule1-0.dll-exp
 gcc -Wl,--base-file,.libs/cygmodule1-0.dll-base .libs/cygmodule1-0.dll-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o .libs/cygmodule1-0.dll  module1.lo  -L/home/bryce/bochs-testing/plugin-test/test4-interdep/lib -lmodule2 
 dlltool --as=as --dllname cygmodule1-0.dll --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12 --def .libs/cygmodule1-0.dll-def --base-file .libs/cygmodule1-0.dll-base --output-exp .libs/cygmodule1-0.dll-exp --output-lib .libs/libmodule1.dll.a
 gcc .libs/cygmodule1-0.dll-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o .libs/cygmodule1-0.dll  module1.lo  -L/home/bryce/bochs-testing/plugin-test/test4-interdep/lib -lmodule2 
cp .libs/libmodule1.dll.aT /home/bryce/bochs-testing/plugin-test/test4-interdep/lib/libmodule1.dll.a
dlpath=`bash 2>&1 -c '. .libs/libmodule1.lai;echo $dlname'`
 dldir=/home/bryce/bochs-testing/plugin-test/test4-interdep/lib/`dirname $dlpath`
 test -d $dldir || mkdir -p $dldir
 cp .libs/cygmodule1-0.dll $dldir/cygmodule1-0.dll
cp .libs/libmodule1.lai /home/bryce/bochs-testing/plugin-test/test4-interdep/lib/libmodule1.la
cp .libs/libmodule1.a /home/bryce/bochs-testing/plugin-test/test4-interdep/lib/libmodule1.a
ranlib /home/bryce/bochs-testing/plugin-test/test4-interdep/lib/libmodule1.a
chmod 644 /home/bryce/bochs-testing/plugin-test/test4-interdep/lib/libmodule1.a
----------------------------------------------------------------------
Libraries have been installed in:
   /home/bryce/bochs-testing/plugin-test/test4-interdep/lib

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the `PATH' environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH' environment variable
     during linking
   - use the `-Wl,--rpath -Wl,LIBDIR' linker flag

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
/bin/sh.exe ../libtool g++ -no-undefined -o uselib ./uselib.cc libmodule1.la libmodule2.la
generating import library for `cygmodule1-0.dll'
dlltool --as=as --dllname cygmodule1-0.dll --def .libs/cygmodule1-0.dll-def --output-lib .libs/libimp-cygmodule1-0.a
g++ -o .libs/uselib ./uselib.cc  .libs/libimp-cygmodule1-0.a .libs/libimp-cygmodule2-0.a -Wl,--rpath -Wl,/home/bryce/bochs-testing/plugin-test/test4-interdep/lib
In file included from ./uselib.cc:2:
module1.h:8: warning: #warning I will import DLL symbols for MODULE1
In file included from ./uselib.cc:3:
module2.h:8: warning: #warning I will import DLL symbols for MODULE2
creating uselib.exe



Try making a dll with everything in it, and then a nearly empty object that

build libmain.la with main.lo
build module1.la with libmain.la
build module2.la with libmain.la
build .exe from libmain.la

Then main.cc can dlopen module1.la
