【问题标题】:Wrapping a C++ library in Objective-C is not hiding the C++ symbols在 Objective-C 中包装 C++ 库不会隐藏 C++ 符号
【发布时间】:2011-07-15 19:09:30
【问题描述】:

我正在尝试使用 Objective-C 包装一个 C++ 库(用于 Sybase Ultralite),以便可以将该库导入 MonoTouch。我创建了一个 Objective-C 库,并将编译后的 C++ 库包含在这个项目中,libulrt.a。为了让我的项目能够编译,我将路径设置为 User Header Search Path 以指向 C++ 头文件所在的目录。然后我不得不将 compile source as 设置为 Objective-C++

现在的问题是,虽然包装库编译正确,但一旦我将它包含在另一个 Xcode 项目中,我必须再次compile source as 设置为 Objective-C++ 否则使用我的包装库的项目会出现链接错误。我不明白为什么会这样,因为我的包装库的头文件只包含 Objective-C 代码,根本不包含 C++ 代码。 C++ 代码只能在包装库的实现(*.mm 文件)中找到。我需要做什么才能使 C++ 实现对使用包装库的项目完全透明?换句话说,我希望能够包含我的包装库并使用 compile source as 设置为 Objective-C 进行编译。任何人有任何想法如何做到这一点?

编译使用我的包装器的项目时遇到的链接错误如下: (我已经删减了错误列表,因为它很长!)

"operator delete(void*)", referenced from:
zc3db40339fee::~zc3db40339fee()in libUltralite.a(ee39bf4763.o)
zb4297ee7d543::~zb4297ee7d543()in libUltralite.a(747e80fdad.o)
z33836a0a6f46::~z33836a0a6f46()in libUltralite.a(f240efda30.o)
"___cxa_pure_virtual", referenced from:
vtable for ze78b0ec59364in libUltralite.a(2c50e8e8ff.o)
vtable for ze78b0ec59364in libUltralite.a(2c50e8e8ff.o)
vtable for ze78b0ec59364in libUltralite.a(2c50e8e8ff.o)

我的包装库的头文件如下:

#import <Foundation/Foundation.h>

@interface DataAccess : NSObject {}

// Release objects.
- (void)dealloc;

// Singleton instance of the DataAccess class. 
+ (DataAccess*)sharedInstance; 

// Finalize the Database Manager when done with the DB.
+ (void)fini;

// Adds the given name to the database. 
- (void)addName:(NSString *)name;
@end 

任何人都知道如何将其编译为 Objective-C++,但仍有使用该库的项目将其视为 Objective-C?

【问题讨论】:

    标签: iphone c++ objective-c xcode xamarin.ios


    【解决方案1】:

    @Mark Bessey 在这里是正确的,但他认为设置语言和添加 C++ 库之间几乎没有区别是不正确的。添加 C++ 库既便宜又需要(一种或另一种方式)。更改语言的成本很高,因为 ObjC++ 编译器速度较慢,而且根据我的经验,通过 Xcode 在 gdb 中处理生成的代码有点痛苦。

    您只需将 -lstdc++ 添加到您的消费项目中的 LD_FLAGS(其他链接器标志)。请确保将“C++ 标准库类型”设置为动态。

    【讨论】:

    • 我删除了第一段,因为它措辞不好。鉴于布鲁斯希望有一个库而不是对 libstdc++ 的悬空引用,他需要使用静态版本。查看我编辑的回复。
    • 我不相信他想链接静态 C++ 库。我很确定他想与动态 C++ 库链接。这只需要在最后的链接步骤中完成,而不是在库构建中。静态库不能与任何东西链接(静态库基本上只是一堆 .o 连接在一起)。
    • 谢谢。这正是我需要的信息。我需要做的是让 MonoTouch 项目使用我的包装库,而在 MonoTouch 中,没有选项可以选择 compile souces asObjective-C++。这就是为什么我需要使用 ObjC 编译器编译的消费项目。我首先在 Xcode 中对此进行了测试,发现它有效。然后,因为 MonoTouch 还有一个用于额外链接器标志的项目选项,所以我在该选项中添加了 -lstdc++ 并编译了我的 MonoTouch 项目。 :) 感谢您对此的帮助。
    • 汗水。因将 C++ 库包装得足够整齐以至于 C++ 标准库从窗口中消失而受到惩罚并不好玩。感谢您的提示。
    【解决方案2】:

    您必须将包装器构建为共享对象,而不是静态库。静态库未链接,函数解析(特别是您包装的代码使用的 C++ 标准库函数)发生在链接时。

    【讨论】:

    • 这是 iPhone,所以他不能使用共享库。在 Mac 上,他只不应该不使用共享库。捆绑包中的共享库带来了很多麻烦并增加了捆绑包的大小(因为您不能删除死代码)。根据我的经验,如果您实际上并没有在程序之间共享代码,那么静态库是首选。
    • @Rob:嗯,除非 Mac 与其他类型的 BSD 有很大不同,否则所需的函数根本不会成为他的静态包装库的一部分,因为它还没有被链接。所以客户需要提供它们。在 Visual C++ 中,我可以通过 #pragma comment(lib, "libname") 自动链接必备库,Apple 编译器有类似的吗?
    • 在 Mac(和 BSD)上,静态库只是 .o 的捆绑包。因此,您需要在应用程序的最终链接中列出所有其他库(与动态库不同,动态库可以包含对其自身依赖项的引用)。在这种情况下,您可以通过传递 -lstdc++ 来实现。不幸的是,没有与您列出的#pragma 等价物。不过,问题是关于 iPhone,它在任何情况下都不支持 3rdparty 共享库。
    • @Rob:动态库是通过链接创建的,所以它们通常不会“包含对自己依赖项的引用”,它们会合并依赖项(除非依赖项本身是共享库,但这里的每个人正在谈论静态 libstdc++)。我只是要向你在 iPhone 上的专业知识低头......我没有,不要为一个而开发,我只是尝试根据 Apple 当前操作系统的 BSD 传统来推断行为。
    • 而“只是一堆目标文件”很好地描述了所有主要平台上的静态库。此外,为了链接器的效率,通常还有一个符号目录,但这并不会从根本上改变行为。
    【解决方案3】:

    似乎您需要将 C++ 运行时库与包装库静态链接才能真正解决这个问题。我认为如果该库的客户端使用 Objective-C++,您可能会遇到问题,并且您最终在同一个程序中使用了两个版本的 C++ 标准库。


    对 MacOS 项目的快速测试似乎表明您需要将 C++ 库类型设置为“静态”,并且可能还设置“默认隐藏符号”。

    【讨论】:

    • 嗨,马克。感谢您的回答。您所说的需要静态排列 C++ 运行时库似乎是有道理的。只是我对 Objective C 和 Xcode 还很陌生,不知道要向 linker flags 添加什么标志来完成此操作。如果你可以请让我知道我将如何去做,我会试一试。使用 Objective-C++ 的客户端的问题根本不是问题,因为在我的情况下,客户端将是 MonoTouch btouch 工具,它只适用于 Objective-C。
    • 默认情况下设置隐藏符号通常是很好的卫生习惯,但我不认为这是解决这个问题的一部分。他的问题是他找不到符号,而不是可见的符号太多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-11
    • 2013-07-27
    • 2016-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多