Not sure how to export Objective-C classes. Undefined symbols for architecture i386

♀尐吖头ヾ 提交于 2020-05-15 05:39:48

问题


I'm trying to do some work on GTK+ on OSX and I'm having a little trouble because, to be honest, I'm not all that familiar with Objective-C. I have enough programming experience that I quickly got up to speed on the basic syntax, and I can look up what I need in documentation. But the problems I'm having are related to linking the library and exposing the classes to the program I'm linking to.

GTK+ is a C library, but the OSX backend includes a couple Objective-C classes. They're not exposed as public API, they're only used internally; but for something I'm working on I'd like to try to expose these classes publicly.

For reference, here is one of the classes:

https://github.com/GNOME/gtk/blob/gtk-2-24/gdk/quartz/GdkQuartzWindow.h https://github.com/GNOME/gtk/blob/gtk-2-24/gdk/quartz/GdkQuartzWindow.c

I've changed the build system so that it installs the header files. I have another source file (outside the gtk+ build system) that does something like:

GdkQuartzWindow *win = [[GdkQuartzWindow alloc] /* other messages... */ ];

When I try to compile I get a linker error:

Undefined symbols for architecture i386:
  ".objc_class_name_GdkQuartzWindow", referenced from:
  pointer-to-literal-objc-class-name in main-a8d029.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I'm not very familiar with how Objective-C compiler/linker works and having trouble understanding how I can (or if I can) solve this.

When I run nm libgdk-quartz-2.0.dylib | grep GdkQuartzWindow I see a lot of messages on this class:

00057120 t -[GdkQuartzWindow beginManualMove]
000575c0 t -[GdkQuartzWindow beginManualResize]
00056c50 t -[GdkQuartzWindow canBecomeKeyWindow]
... (many more) ...
000b2030 s .objc_class_name_GdkQuartzWindow

At the bottom of that list, you see the thing that the linker is complaining doesn't exist. But if I use nm -g instead of nm then nothing is shown, so something is not being exported correctly.

For normal C symbols, the build process builds an alias file that includes

Apple's docs give me the impression that this shouldn't be a problem when my target is i386 (which it currently is). They say:

In a 32-bit OS X project, these visibility controls apply only to the C or C++ subset of your code. They do not apply to Objective-C classes and methods. Objective-C class and message names are bound by the Objective-C runtime, not by the linker, so the notion of visibility does not apply to them. There is no mechanism for hiding an Objective-C class or method defined in a dynamic library from the clients of that library.

But, I am receiving an error saying I have undefined symbols, so my error seems to contradict this. If I change this line so that it's allocating an NSWindow instead, everything works fine; so it's importing the AppKit stuff correctly. It just seems that I'm doing something wrong with trying to expose the classes and their methods.

Any chance someone can point me in the right direction?


回答1:


As a temporary workaround, you could replace references to the class symbol in your code with calls to NSClassFromString passing the class name as an argument. For example:

GdkQuartzWindow *win = [[NSClassFromString(@"GdkQuartzWindow") alloc] /* other messages... */ ];

This has long-term maintainability issues, though, as it depends on the name of the class remaining unchanged. I suspect that the Apple doc may be out of date or wrong for current compilers. Perhaps check to see if the value being substituted in gdk/quartz/Makefile.in for $(GDK_HIDDEN_VISIBILITY_CFLAGS) indeed is the empty string on your platform, and if not, changing that may be a more viable long term solution for your needs.




回答2:


I would suggest making sure you are using the -ObjC flag when linking to GTK+. You can add it under "Other linker flags" in your target Build Settings. If this does not work, you might try adding -all_load linker flag.

This will affect how the library is loaded and make sure all the symbols are recognised. This is actually useful when linking a library containing Objective C classes, since there are some optimisations that are done by the linker (i.e., when a static library defines a category but does not use it directly), but maybe it will help in your case as well.

See this for an explanation.




回答3:


I had a similar problem in a library with mixed C/C++ code and an ObjectiveC wrapper. In this situation I was compiling the whole library with -fvisibility=hidden gcc/clang flag. This has an immediate effect of also hiding all ObjectiveC class symbols. A not so known/used technique is to also decorate classes with visibility attributes. This widely used for C/C++, but it will also work for ObjectiveC declared types. Let's first create a OBJC_MYLIBRARY_API macro that will enable visibility on compilation units in a libdefs.h file:

#pragma once

#if defined(OBJC_MYLIBRARY_SHARED) || !defined(OBJC_MYLIBRARY_STATIC)

#ifdef OBJC_MYLIBRARY_EXPORT
    #define OBJC_MYLIBRARY_API __attribute__ ((visibility ("default")))
#else
    #define OBJC_MYLIBRARY_IMPORT
    #define OBJC_MYLIBRARY_API
#endif

#else
    #define OBJC_MYLIBRARY_API
    #ifndef OBJC_MYLIBRARY_EXPORT
        #define OBJC_MYLIBRARY_IMPORT
    #endif
#endif

Then you declare an Objective C class with the public API macro in the header:

#pragma once

#import "cboclibdefs.h"

OBJC_MYLIBRARY_API
@interface MyClass : NSObject
- (id)init;
@end

Then in the implementation just ensure the symbols will be exported defining the OBJC_MYLIBRARY_MACRO:

#define OBJC_CODEBINDER_EXPORT
#import "MyClass.h"

@implementation MyClass

- (id)init
{
    return [super init];
}

@end

This way MyClass symbols will be available in the generated shared library.



来源:https://stackoverflow.com/questions/23849485/not-sure-how-to-export-objective-c-classes-undefined-symbols-for-architecture-i

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!