When building a program that uses an objc library as a DLL, libobjc can't find its classes. When the program and the library are statically linked, it works. My libobjc itself is linked as a static library. Environment: System: Linux asgard.webkeks.org 2.6.28.5 #1 SMP Sat Feb 14 14:16:10 CET 2009 i686 Intel(R) Core(TM)2 CPU 6600 @ 2.40GHz GenuineIntel GNU/Linux host: mingw32 build: i686-pc-linux-gnu target: i686-pc-linux-gnu configured with: ../gcc-4.3.0-20080502/configure -v --prefix=/usr --libexecdir=/usr/lib --program-prefix=mingw32- --target=mingw32 --with-headers=/usr/mingw32/include --without-x --disable-nls --disable-win32-registry --disable-shared --disable-java-awt --disable-libgcj-debug --with-gcc --with-gnu-ld --with-gnu-as --enable-threads --enable-languages=c,c++,objc --enable-libgcj --enable-java-gc=boehm --enable-interpreter --enable-hash-synchronization --enable-libstdcxx-debug How-To-Repeat: asgard:/tmp$ cat foo.h #import <objc/Object.h> @interface MyObj: Object - (void)foo; @end asgard:/tmp$ cat foo.m #import <stdio.h> #import "foo.h" @implementation MyObj - (void)foo { puts("foo!"); } @end asgard:/tmp$ cat test.m #import "foo.h" int main() { MyObj *x = [MyObj new]; [x foo]; return 0; } asgard:/tmp$ mingw32-gcc -shared -Wl,--out-implib,libfoo.dll.a foo.m -o libfoo.dll -lobjc asgard:/tmp$ mingw32-gcc -L. test.m -lfoo -lobjc Info: resolving ___objc_class_name_MyObj by linking to __imp____objc_class_name_MyObj (auto-import) /usr/lib/gcc/mingw32/4.3.0/../../../../mingw32/bin/ld: warning: auto-importing has been activated without --enable-auto-import specified on the command line. This should work unless it involves constant data structures referencing symbols from auto-imported DLLs. asgard:/tmp$ wine a.exe objc runtime: cannot find class MyObj
Fix: I guess some change to libobjc is needed so it can find classes inside DLLs.
So the situation seems to be: - libobjc is a static library. - libfoo is a dll statically linked against libobjc. - test is program which is linked both against libfoo and libobjc. I'm guessing here since I have no experience mingw and with linking libobjc statically, but I could imagine that you may have two copies of libobjc in your executable each with it's own set of runtime structures, which may cause confusion. Is there any reason why libobjc isn't dynamically linked if you going to use DLL's? Note I'll still need to build a mingw compiler and look into the auto-import warning and I'm not sure when I'll get around to it, so I haven't assigned the bug yet in case someone else can easily test it. Cheers, David
When the target is mingw32, it seems that libobjc is only built as a static library. This isn't a bad idea after all, because I guess no win32 user has a libobjc.so installed somewhere, so you would need to ship that file with every binary produced from ObjC-sources. I heard from the GNUstep guys that they had the same problem until they linked libobjc dynamically. But IMO, this is only a workaround - it should also work if libobjc is linked statically.
Well, consider me a "GNUstep guy" yet I'm definitely not a "GNUstep on MinGW32 guy". (Or anything on MinGW32... which is why this a bit difficult, yet I'm trying to help maintain libobjc so I'll see what I can do.) Could you please add a link to that discussion? It seems that I missed it. I've found a few mingw32 discussions searching the archive but nothing recent wrt static linking. In the meantime I'm learning how to setup a cross tool chain... please be patient.
It would be hard to link to that discussion as that was IRL on FOSDEM in the GNUstep Dev Room :). I reported that bug once on the mingw32 list, but they wouldn't really care about it. After speaking to Nicola Pero on FOSDEM, I decided that it'd be best to file a bug for libobjc - and so I did :). For building mingw32 with gcc 4, you could have a look at these Port files I wrote: https://webkeks.org/hg/crux_ports/file/6062794869e8/mingw32-api https://webkeks.org/hg/crux_ports/file/6062794869e8/mingw32-binutils https://webkeks.org/hg/crux_ports/file/6062794869e8/mingw32-gcc https://webkeks.org/hg/crux_ports/file/6062794869e8/mingw32-runtime
I've played a bit with creating a trivial static library and linking into an dynamic library and into an executable. After tweaking back and forth it seems that at least on GNU/Linux the static version linked into the executable actually replaces the version that was linked into the dynamic library... not sure what would happen if the version linked in last doesn't satisfy all the requirements needed by the dynamic library. All very intriguing , yet I believe it has nothing to do with your issue. Since I wasn't able to get a cross tool chain running (and www.mingw.org doesn't seem to support that with the current gcc versions) I went ahead and updated an old Windows VM, installed all kinds of updates... and then installed MinGW/MSYS natively. First I reproduced you issue successfully and then went about installing GNUstep. Note that GNUstep's MinGW HOWTO explicitly states: "It's a good idea to remove the libobjc.a and libobjc.la and include/objc headers that come with gcc (gcc -v for location) so that they are not accidentally found instead of the libobjc DLL that you will compile below. ..." After installing the GNUstep packages, I was able to build and execute applications. Now GNUstep uses it's own build environment (gnustep-make) to hide all the fancy stuff that needs to be done on windows. I was hoping to see something with messages=yes to give me an indication of what you need to do. Yet I had no luck in identifying anything interesting. Well except that GNUstep is using a shared libobjc. I'm going to throw in the towel here, but I don't believe your issue has to do with libobjc. I think your missing some flag or extra processing that gnustep-make might do for you dll or the program. But I also believe that statically linking (potentially different versions) of libobjc into different modules is error prone. I guess it would be OK, if you only have a single executable, but the constellation of the dll linking one version and the executable potentially linking another scares me... even if that itself is most likely not your issue either.
> Since I wasn't able to get a cross tool chain running (and www.mingw.org > doesn't seem to support that with the current gcc versions) Please have a look at the Portfiles I gave you a link to, they include all the stuff you need to know to build mingw32 with gccc 4.3 as a crosscompiler ;). > "It's a good idea to remove the libobjc.a and libobjc.la and > include/objc headers that come with gcc (gcc -v for location) so that > they are not accidentally found instead of the libobjc DLL that you > will compile below. ..." Yeah, that's exactly what Nicola Pero told me. The default is that there's only a libobjc.a on Win32, but that doesn't work. So GNUstep lets you compile a libobjc.dll and if you use that instead, it works. > Well except that > GNUstep is using a shared libobjc. Yeah, that should already do the trick. > I'm going to throw in the towel here, but I don't believe your issue has to do > with libobjc. I think your missing some flag or extra processing that > gnustep-make might do for you dll or the program. That's what I thought first, too. But after talking to several GNUstep developers on FOSDEM, none of them was aware of any extra flags. They said all they did was recompile libobjc as a DLL and then it would work. I haven't seen any DllMain() in libobjc yet (though I have to admit I haven't really looked for it, only had a few libobjc sources open in the editor for various reasons, but never to look for DllMain), but it might be possible that there is some initialization code in DllMain() of libobjc.dll that does some initializing stuff that fixes it. > But I also believe that statically linking (potentially different versions) of > libobjc into different modules is error prone. I guess it would be OK, if you > only have a single executable, but the constellation of the dll linking one > version and the executable potentially linking another scares me... even if > that itself is most likely not your issue either. I think the DLLs don't link to the static version of libobjc - at least, I hope so, as that'd be useless.
Any news on this? Any way how I could compile libobjc as a shared library? Specifying --enable-shared breaks basically every library that gcc ships and I haven't found a way to only enable it for libobjc.
I'm sorry, I'm simply not familiar with cygwin/mingw environments and cross builds. But I'm surprised that --enable-shared doesn't work. Is that a native build?
What exactly do you mean by native build? Do you mean if I build a compiler to run on Linux and not on win32, but which targets win32? If so, yes.
With 'native' I meant mingw := build=host=target so no... it's not native in the sense that I was talking about.
Any news? I even tried this now, which still produced an .a file: ../gcc-4.3.0-20080502/configure -v --prefix=/usr --libexecdir=/usr/lib \ --program-prefix=mingw32- --target=mingw32 --with-headers=/usr/mingw32/include --disable-nls --enable-shared --enable-languages=objc make configure-target-libobjc make all-target-libobjc make install-target-libobjc Note the --enable-shared, which is _DEFINITELY_ being passed to configure (quoting Makefile in builddir): maybe-configure-target-libobjc: configure-target-libobjc configure-target-libobjc: @: $(MAKE); $(unstage) @r=`${PWD_COMMAND}`; export r; \ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ echo "Checking multilib configuration for libobjc..."; \ $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libobjc ; \ $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libobjc/multilib.tmp 2> /dev/null ; \ if test -r $(TARGET_SUBDIR)/libobjc/multilib.out; then \ if cmp -s $(TARGET_SUBDIR)/libobjc/multilib.tmp $(TARGET_SUBDIR)/libobjc/multilib.out; then \ rm -f $(TARGET_SUBDIR)/libobjc/multilib.tmp; \ else \ rm -f $(TARGET_SUBDIR)/libobjc/Makefile; \ mv $(TARGET_SUBDIR)/libobjc/multilib.tmp $(TARGET_SUBDIR)/libobjc/multilib.out; \ fi; \ else \ mv $(TARGET_SUBDIR)/libobjc/multilib.tmp $(TARGET_SUBDIR)/libobjc/multilib.out; \ fi; \ test ! -f $(TARGET_SUBDIR)/libobjc/Makefile || exit 0; \ $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libobjc ; \ $(NORMAL_TARGET_EXPORTS) \ echo Configuring in $(TARGET_SUBDIR)/libobjc; \ cd "$(TARGET_SUBDIR)/libobjc" || exit 1; \ case $(srcdir) in \ /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ *) topdir=`echo $(TARGET_SUBDIR)/libobjc/ | \ sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ esac; \ srcdiroption="--srcdir=$${topdir}/libobjc"; \ libsrcdir="$$s/libobjc"; \ rm -f no-such-file || : ; \ CONFIG_SITE=no-such-file $(SHELL) $${libsrcdir}/configure \ $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ --target=${target_alias} $${srcdiroption} \ || exit 1 And TARGET_CONFIGARS is: TARGET_CONFIGARGS = --cache-file=./config.cache --enable-multilib --with-cross-host=i686-pc-linux-gnu '-v' '--prefix=/usr' '--libexecdir=/usr/lib' '--with-headers=/usr/mingw32/include' '--disable-nls' '--enable-shared' '--enable-languages=c,objc' --program-transform-name='s,^,mingw32-,' --with-target-subdir="$(TARGET_SUBDIR)" As you can see, --enable-shared is listed there, so libobjc's configure is simply ignoring --enable-shared it seems.
Oh, for the record: cygwin now has gcc4 imported and they have libobjc as a shared .dll file. Using their dll, it works. So this means libobjc works with dll files if it is a dll file itself. But unfortunately, it's not possible to build it as a dll for mingw32 it seems. Still, I think there should be either both (.dll and .a) or the .a file should be able to load other dlls. Having only a .dll would mean that every app depends on libobjc.dll, which most likely no windows user will have. That's as if every C++ app would require gcc's libstdc++.dll on Windows.
Any comments? This is still very annoying and completely killing the ability to have plugins/bundles on win32.
After looking some more at the code, I might have an idea what's causing the issue: __objc_gnu_init calls __objc_exec_class on _OBJC_MODULES. Is it possible that this call is not made for some reason if you link your lib as a dll? That would mean the classes are never loaded into the runtime.
(In reply to comment #15) > After looking some more at the code, I might have an idea what's causing the > issue: > __objc_gnu_init calls __objc_exec_class on _OBJC_MODULES. Is it possible that > this call is not made for some reason if you link your lib as a dll? That would > mean the classes are never loaded into the runtime. I did recently some bugfix for libobjc (shared) for the version in gcc's source tree. Issue was that the DLL generation was pretty broken in different ways, which lead then to the issue that no function was exported by it. This should be fixed on 4.6 version and initial tests are showing it works for me now. But in general it is wise to use - if building shared libraries for win32 targets - to use instead of the dllexport/dllimport mechanism the linker option --export-all-symbols. The issue for obj-c is, that class can't have dllimport/dllexport attributes, which cause then that their names can't be found. I hope it helps, Kai
JFTR, libtool will not create a shared library on w32 systems unless you pass the -no-undefined flag at link time. That seems to me the reason why libobjc is created as static only. Whether you need to make other adjustments for shared libobjc to actually work, I cannot tell without more details.