Description:
I saw autoimport failing for DLLized libstdc++. I tried it on simple app (iostreams only) without patching headers and end up with unresolved references to some C++ symbols.
Cause:
?
Solution/Workaround:
More information (e.g., easy non-libstdc++-relying testcase) required.
Hello Paul,
What were the unresolved symbols?
I had initial problems with libstdc++ revolving around functions taking long double args (mainly in complexio).
Removing these (by editing an output-def file) and rebuilding libstdc++dll with this def fixed the problem and I was able to use autoimport and autoexport together to build a dll that linked against libstdc++.dll names (that is, autoimport to get symbols from libstdc++.dll, autoexport to build new dll).
Danny
Making libstdc++.dll with my a2dll from static lib, and compiling
#include <iostream.h>
main()
{
cout<<"Happy New year1";
}
====
give
====
Warning: resolving _cout by linking to __imp__cout (auto-import)
fu000001.o(.idata$3+0xc): undefined reference to `libstdc___a_iname'
nmth000000.o(.idata$4+0x0): undefined reference to `_nm__cout'
====
For reference, here's patch (against Mumit's) for new gcc release (of course, I postponed it due problem report from you):
====
diff -cr gcc-2.95.2-1/include/g++-3/iostream.h E:\packages\mingw\gcc/include/g++-3/iostream.h
*** gcc-2.95.2-1/include/g++-3/iostream.h Fri Jan 21 20:12:00 2000
--- E:\packages\mingw\gcc/include/g++-3/iostream.h Thu Dec 14 04:03:00 2000
***************
*** 30,35 ****
--- 30,41 ----
#include <streambuf.h>
+ #ifndef __STATIC__
+ #define _LIBSTDCPP_IMPORT __declspec(dllimport)
+ #else
+ #define _LIBSTDCPP_IMPORT
+ #endif
+
extern "C++" {
class istream; class ostream;
typedef ios& (*__manip)(ios&);
***************
*** 245,255 ****
{ return operator= (static_cast<ostream&> (rhs)); }
};
! extern _IO_istream_withassign cin;
// clog->rdbuf() == cerr->rdbuf()
! extern _IO_ostream_withassign cout, cerr;
! extern _IO_ostream_withassign clog
#if _G_CLOG_CONFLICT
__asm__ ("__IO_clog")
#endif
--- 251,261 ----
{ return operator= (static_cast<ostream&> (rhs)); }
};
! _LIBSTDCPP_IMPORT extern _IO_istream_withassign cin;
// clog->rdbuf() == cerr->rdbuf()
! _LIBSTDCPP_IMPORT extern _IO_ostream_withassign cout, cerr;
! _LIBSTDCPP_IMPORT extern _IO_ostream_withassign clog
#if _G_CLOG_CONFLICT
__asm__ ("__IO_clog")
#endif
*** gcc-2.95.2-1/\gcc-lib\mingw32\2.95.2specs Sat Aug 12 12:56:38 2000
--- E:\packages\mingw\gcc\lib\gcc-lib\mingw32\2.95.2\specs Fri Dec 29 03:13:57 2000
***************
*** 5,11 ****
*cpp:
! -idirafter /usr/local/include -remap %(cpp_cpu) %{posix:-D_POSIX_SOURCE} %{mthreads:-D_MT}
*cc1:
%(cc1_spec)
--- 5,11 ----
*cpp:
! -remap %(cpp_cpu) %{posix:-D_POSIX_SOURCE} %{mthreads:-D_MT} %{static:-D__STATIC__}
*cc1:
%(cc1_spec)
***************
*** 20,26 ****
%{mwindows:--subsystem windows} %{mconsole:--subsystem console} %{shared: %{mdll: %eshared and mdll are not compatible}} %{shared: --shared} %{mdll:--dll} %{shared|mdll: -e _DllMainCRTStartup@12}
*lib:
! %{pg:-lgmon} %{mwindows:-lgdi32 -lcomdlg32} -luser32 -lkernel32 -ladvapi32 -lshell32
*libgcc:
%{mthreads:-lmingwthrd} -lmingw32 -lgcc -lmoldname -lmsvcrt
--- 20,26 ----
%{mwindows:--subsystem windows} %{mconsole:--subsystem console} %{shared: %{mdll: %eshared and mdll are not compatible}} %{shared: --shared} %{mdll:--dll} %{shared|mdll: -e _DllMainCRTStartup@12}
*lib:
! -liberty %{pg:-lgmon} %{mwindows:-lgdi32 -lcomdlg32} -luser32 -lkernel32 -ladvapi32 -lshell32
*libgcc:
%{mthreads:-lmingwthrd} -lmingw32 -lgcc -lmoldname -lmsvcrt
***************
*** 41,47 ****
0
*version:
! 2.95.2
*multilib:
. ;
--- 41,47 ----
0
*version:
! 2.95.2-mingw snapshot 20001228
*multilib:
. ;
***************
*** 80,86 ****
%{!mcpu*: %{m386:-mcpu=i386 -march=i386} %{m486:-mcpu=i486 -march=i486} %{mpentium:-mcpu=pentium} %{mpentiumpro:-mcpu=pentiumpro}}
*mingw_include_path:
! i386-mingw32msvc
*link_command:
%{!fsyntax-only: %{!c:%{!M:%{!MM:%{!E:%{!S:%(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r} %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}} %{static:} %{L*} %D %o %{!nostdlib:%{!nodefaultlibs:%G %L %G}} %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*}
--- 80,86 ----
%{!mcpu*: %{m386:-mcpu=i386 -march=i386} %{m486:-mcpu=i486 -march=i486} %{mpentium:-mcpu=pentium} %{mpentiumpro:-mcpu=pentiumpro}}
*mingw_include_path:
! mingw32
*link_command:
%{!fsyntax-only: %{!c:%{!M:%{!MM:%{!E:%{!S:%(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r} %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}} %{static:} %{L*} %D %o %{!nostdlib:%{!nodefaultlibs:%G %L %G}} %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*}
diff -c specs E:\packages\mingw\gcc\lib\gcc-lib\mingw32\2.95.2\specs
*** specs Sat Aug 12 12:56:38 2000
--- E:\packages\mingw\gcc\lib\gcc-lib\mingw32\2.95.2\specs Fri Dec 29 03:13:57 2000
***************
*** 5,11 ****
*cpp:
! -remap %(cpp_cpu) %{posix:-D_POSIX_SOURCE} %{mthreads:-D_MT}
*cc1:
%(cc1_spec)
--- 5,11 ----
*cpp:
! -remap %(cpp_cpu) %{posix:-D_POSIX_SOURCE} %{mthreads:-D_MT} %{static:-D__STATIC__}
*cc1:
%(cc1_spec)
***************
*** 20,26 ****
%{mwindows:--subsystem windows} %{mconsole:--subsystem console} %{shared: %{mdll: %eshared and mdll are not compatible}} %{shared: --shared} %{mdll:--dll} %{shared|mdll: -e _DllMainCRTStartup@12}
*lib:
! %{pg:-lgmon} %{mwindows:-lgdi32 -lcomdlg32} -luser32 -lkernel32 -ladvapi32 -lshell32
*libgcc:
%{mthreads:-lmingwthrd} -lmingw32 -lgcc -lmoldname -lmsvcrt
--- 20,26 ----
%{mwindows:--subsystem windows} %{mconsole:--subsystem console} %{shared: %{mdll: %eshared and mdll are not compatible}} %{shared: --shared} %{mdll:--dll} %{shared|mdll: -e _DllMainCRTStartup@12}
*lib:
! -liberty %{pg:-lgmon} %{mwindows:-lgdi32 -lcomdlg32} -luser32 -lkernel32 -ladvapi32 -lshell32
*libgcc:
%{mthreads:-lmingwthrd} -lmingw32 -lgcc -lmoldname -lmsvcrt
***************
*** 41,47 ****
0
*version:
! 2.95.2
*multilib:
. ;
--- 41,47 ----
0
*version:
! 2.95.2-mingw snapshot 20001228
*multilib:
. ;
***************
*** 80,86 ****
%{!mcpu*: %{m386:-mcpu=i386 -march=i386} %{m486:-mcpu=i486 -march=i486} %{mpentium:-mcpu=pentium} %{mpentiumpro:-mcpu=pentiumpro}}
*mingw_include_path:
! i386-mingw32msvc
*link_command:
%{!fsyntax-only: %{!c:%{!M:%{!MM:%{!E:%{!S:%(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r} %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}} %{static:} %{L*} %D %o %{!nostdlib:%{!nodefaultlibs:%G %L %G}} %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*}
--- 80,86 ----
%{!mcpu*: %{m386:-mcpu=i386 -march=i386} %{m486:-mcpu=i486 -march=i486} %{mpentium:-mcpu=pentium} %{mpentiumpro:-mcpu=pentiumpro}}
*mingw_include_path:
! mingw32
*link_command:
%{!fsyntax-only: %{!c:%{!M:%{!MM:%{!E:%{!S:%(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r} %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}} %{static:} %{L*} %D %o %{!nostdlib:%{!nodefaultlibs:%G %L %G}} %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*}
====
Paul,
That "long double" business was misleading. I was get getting unresolved references to things like
nmth000000.o(.idata$4+0x0): undefined reference to `_nm(char,...)(long double, long double)' Now I realise that is not a problem with long double but a sign of a confused demangler.
Your Happy New Year test works with auto-import if I do following:
1) Build libstdc++.dll and implib as per a2dll, but using ld-20001204, and excluding static libstdc++.a from the build (by using gcc -shared rather than g++ -shared).
2) Build test program with auto-import using ld-20001204.
If I used old ld to build libstdc++.dll.a in step 1 I get the unresolved references to _nm__cout or to the screwy long double name '_nm(char,...)(long double, long double)'
if test code has
cerr<<"Happy New Year" ;
Cheers
Danny
Paul, here's a test case showing failure with C++ code, not using iostreams. The problem is when there is dependency between two objects *within* the dll (like cerr and cout, in libstdc++.dll).
Testing was done with lastest beta (Jan 2001) of ld and bfd.
If dll implib is built with release or CVS ld, there is problem with auto-import.
If dll implib is built with your ld, no problem.
Here is the script:
rem build dll the old way (with declspecs)
c++ -c -DBUILDING_DLL=1 -DUSE_DECLSPEC -I. -g \ -o dllclass.o dllclass.cpp
c++ -c -DBUILDING_DLL=1 -DUSE_DECLSPEC -I. -g \
-o dllexterns.o dllexterns.cpp
rem use cvs ld to build dll
rm -f useCVSdll.exe
c++ -shared -Wl,--out-implib,libCVScxxdll.a \ -o CVScxxdll.dll dllclass.o dllexterns.o
rem don't use declspecs in client to test Paul's auto-import
c++ -c -I. -g -o usedll.o usedll.cpp
c++ -Bd:/test/ld-auto/ -o useCVSdll.exe -g usedll.o \ -L./ -lCVScxxdll
rem fails to link
useCVSdll
rem use Paul's ld
rm -f usePauldll.exe
c++ -shared -Bd:/test/ld-auto/ \ -Wl,--out-implib,libPaulcxxdll.a -o Paulcxxdll.dll \ dllclass.o dllexterns.o
rem don't use declspecs in client to test auto-import
c++ -c -I. -g -o usedll.o usedll.cpp
c++ -Bd:/test/ld-auto/ -o usePauldll.exe -g usedll.o \ -L./ -lPaulcxxdll
usePauldll
Here is the code:
/**********************************************
* dllclass.h
*/
#ifndef dllclass_h_included
#define dllclass_h_included
#if defined USE_DECLSPEC
#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */
#else
#define DLLIMPORT
#endif
struct DLLIMPORT
InnerClass {
InnerClass(int i=0);
int inner_int;
int in_method() const;
};
struct DLLIMPORT
OuterClass {
OuterClass();
OuterClass(InnerClass);
int out_method () const;
InnerClass InnerObject;
};
#endif /* dllclass_h_included */
/*****************************************************
* dllclass.cpp
*/
#include "dllclass.h"
#include <stdio.h>
InnerClass::InnerClass(const int i):inner_int(i)
{
printf("In InnerClass ctor in dll\n");
};
int
InnerClass::in_method () const
{
int retval=inner_int;
printf("In InnerClass method in dll, retval= %i \n", retval);
return retval;
}
OuterClass::OuterClass()
{
printf("In OuterClass ctor in dll\n");
InnerClass InnerObject();
}
OuterClass::OuterClass(InnerClass src):InnerObject(src)
{
printf("In OuterClass ctor in dll\n");
};
int
OuterClass::out_method () const
{
int retval= (InnerObject.in_method() + 10);
printf("In OuterClass method in dll, retval= %i \n", retval);
return retval;
}
/***************************************************************
* dllexterns.cpp
*/
#include "dllclass.h"
DLLIMPORT InnerClass global_innerclass(10);
DLLIMPORT OuterClass global_outerclass(global_innerclass);
/**********************************************************
* usedll.cpp
*/
#include <stdio.h>
#include "dllclass.h"
extern DLLIMPORT InnerClass global_innerclass;
extern DLLIMPORT OuterClass global_outerclass;
int main () {
printf("In main\n");
global_outerclass.out_method();
return 1;
}
************************************************************
Cheers
Danny