Bug 39465 - libobjc does not find classes of DLLs
Summary: libobjc does not find classes of DLLs
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: libobjc (show other bugs)
Version: 3.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-03-15 15:34 UTC by js-gcc
Modified: 2021-09-12 08:00 UTC (History)
5 users (show)

See Also:
Host:
Target: i686-mingw32
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description js-gcc 2009-03-15 15:34:22 UTC
	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
Comment 1 js-gcc 2009-03-15 15:34:22 UTC
Fix:
	I guess some change to libobjc is needed so it can find classes inside
	DLLs.
Comment 2 ayers 2009-03-16 07:27:21 UTC
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
Comment 3 js-gcc 2009-03-16 11:24:32 UTC
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.
Comment 4 ayers 2009-03-16 11:41:16 UTC
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.
Comment 5 js-gcc 2009-03-16 11:46:36 UTC
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
Comment 6 ayers 2009-03-16 23:51:21 UTC
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.
Comment 7 js-gcc 2009-03-17 14:05:30 UTC
> 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.
Comment 8 js-gcc 2009-04-06 19:41:28 UTC
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.
Comment 9 ayers 2009-04-06 21:22:12 UTC
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?
Comment 10 js-gcc 2009-04-06 21:39:13 UTC
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.
Comment 11 ayers 2009-04-06 21:59:36 UTC
With 'native' I meant mingw := build=host=target so no... it's not native in the sense that I was talking about.
Comment 12 js-gcc 2009-06-09 19:17:36 UTC
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.
Comment 13 js-gcc 2009-06-09 19:27:36 UTC
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.
Comment 14 js-gcc 2009-07-16 21:16:05 UTC
Any comments? This is still very annoying and completely killing the ability to have plugins/bundles on win32.
Comment 15 js-gcc 2009-12-20 00:31:27 UTC
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.
Comment 16 Kai Tietz 2010-10-29 14:12:26 UTC
(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
Comment 17 Ralf Wildenhues 2010-11-03 17:11:18 UTC
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.