【问题标题】:Using C/C++ static libraries from iPhone ObjectiveC Apps使用 iPhone ObjectiveC Apps 中的 C/C++ 静态库
【发布时间】:2008-12-18 05:20:45
【问题描述】:

是否有可能有一个 C 静态库 API,它在内部使用 C++ 并对库的用户隐藏它?

我编写了一个可移植的 C++ 库,希望静态链接到 iPhone 应用程序。

我使用 Max OS X 的“静态库”模板创建了一个 Xcode 项目,并复制了源代码,并使用 (extern "C") 编写了一个 C wapper(处理异常)。

我正在尝试在另一个 Cocoa iPhone 应用程序中使用生成的库(.a 文件)。

如果我在调用的 ObjectiveC 文件上使用 (.mm) 扩展名并在库中的实现类上使用 (.cpp) 扩展名,那么一切正常。

但是当我尝试将包装文件更改为 (.c) 扩展名时,我在链接时得到未解析的符号,即使所有包装函数文件都只是 C 函数。

仅仅因为 C++ 在库内部使用,是否意味着在外部它仍然必须被视为 C++ 程序。反正没有强制执行这种抽象吗?

编辑:感谢您的回复,

我一直在使用 extern "C",我只是不确定调用项目中需要哪些配置。 IE。如果调用投影需要知道它是否使用 C++ 或者可能是无知的并认为它是一个纯粹的 C 库。

看来我做不到,我必须在我的 ObjectiveC 类中使用 (.mm) 文件。

【问题讨论】:

  • 您是否使用 extern "C" 声明您的 C 库函数?
  • Akusete,你的问题真的不是关于 Objective-C 的……而是关于 C/C++ 和工具的问题。我认为您的问题是您没有获得链接的 C++ 运行时支持,因为您正在链接 C 应用程序的 Xcode 东西。如果 Q 中没有关于 Obj-C 的具体内容,请不要使用 Obj-C 标记
  • 我的错,我没有意识到你已经删除了它。

标签: c++ c


【解决方案1】:

在 cmets 中执行此操作太难了,因此我将快速为您演示一下您遇到的链接问题。当 Xcode 遇到文件时,它使用基于后缀的构建规则来决定使用哪个编译器。默认情况下,gcc 将文件链接到标准 C 库,但不链接到标准 C++ 库。存档文件(静态库)根本没有完成链接解析。它们基本上是需要链接的目标文件的存档。由于您的项目中没有 .mm 或 .cpp 文件,因此永远不会调用 g++ 并且您的文件永远不会链接到标准库。要更正此问题,只需将标准 C++ 库添加到 Xcode 项目中的其他链接器标志,或者只需将它们添加到预定义的其他标志选项 -l(例如 -lstdc++)。

这是一个快速演示:

stw.h:

#ifdef __cplusplus
extern "C"
#endif
void show_the_world(void);

stw.cpp:

#include <iostream>
#include "stw.h"
using namespace std;

extern "C" void show_the_world() {
  cout << "Hello, world!\n";
}

构建库:

$ g++ -c stw.cpp -o stw.cpp -O0 -g
$ ar rcs stw.a stw.o

使用 C 应用程序中的库:

myapp.c:

#include "stw.h"

int main() {
  show_the_world();
  return 0;
}

构建 C 应用程序:

$ gcc -o myapp myapp.c stw.a -lstdc++ -g -O0
$ ./myapp
Hello, world!
$

如果您尝试在没有 -lstdc++ 的情况下进行编译,您将得到所有未解决的问题,因为 C 编译器完全不知道它应该链接到 C++ 运行时(为什么会这样,对吧!?!?)所以你有手动添加。您的另一个选择是更改项目的构建规则...而不是让 Xcode 使用 gcc 来构建 .c 和 .m 文件,告诉它使用 g++,您的问题将得到解决。

【讨论】:

  • 感谢您的帮助,我很抱歉让您感到恼火。我对 C++ 运行时的运行方式有些无知,之前一直在使用 g++ 或 VC++。
  • 啊,你一点也不烦人 :) 只是在 300 个字符的 cmets 中做所有事情就是......
  • 在将 FMOD 库引入我的直接 Objective-C 项目时,这节省了我的培根。必须包含 -lstdc++ 才能消除链接错误。
【解决方案2】:

您应该声明您希望可见的函数extern "C"。它们的签名需要与 C 兼容,但内容不兼容(例如,您可以访问 C++ 对象,但不能直接传递它们;指针可以)。然后,这些符号将在任何 C 兼容环境中可见。

编辑:并将其编译为 C++ 源文件,C 没有语言链接的概念。语言链接还有一些其他问题(例如,所有具有相同名称的 extern "C" 函数都是相同的函数,而与命名空间无关)。

EDIT2:在标题中,您可以检查宏 __cplusplus,并使用它分别为 C++ 和其他语言设置(因为 C++ 将需要 extern "C" 声明,而其他语言可能会抱怨它们) .

【讨论】:

  • 谢谢,“将它编译为 C++ 源文件”意味着我仍然需要一个 (.mm) 目标 C 文件才能使用它,对吗? 'C 没有语言链接的概念' 我想这意味着如果我在库中的任何地方都有 C++,那么整个东西都必须编译为 C++。
【解决方案3】:

基本上,当您使用 C++ 编译器编译 C 函数时,它会破坏函数名称并使用 C++ ABI。

当您使用 *.cpp 或 *.mm 扩展名时,您正在使用 C++ 编译器。

您想要做的是强制编译器生成具有 un-mangles 名称并使用 C ABI 的 C 函数。

您可以通过以下方式做到这一点:

  • 使用 C 编译器进行编译。
  • 使用 C++ 编译器进行编译,但确保在函数声明前加上 extern "C"

设置头文件的一种常用方法是:

#ifndef HEADER_GUARD_1_H
#define HEADER_GUARD_1_H

#ifdef __cplusplus
extern "C" {
#endif

// Declare C function interface here.
int myFunc(int x,char*);

#ifdef __cplusplus
}
#endif

#endif 

【讨论】:

  • 谢谢,我了解 extern "C" 的使用,该库目前在 win32 windowsCE 和 linux 平台上适用于 C/C++/C#(使用 pinvoke)。但是,如果我的界面是 C,我不确定是否需要在 ObjectiveC 代码中使用 (.mm)。
  • .mm 只是强制它使用 C++ 编译器而不是 C 编译器。 Objective C 只是这些语言之上的一个包装器(我不是字面意思)。
【解决方案4】:

谢谢,这么好的讨论。

我所做的是:

1) 我使用 cocaotouch 静态库选项创建了一个静态库。在那我有 c/c++/obj-c 所有混合。但是,我的导出只是 obj-c 类。 事实上,我使用 objc- to c to C++。

2) 然后我在 X-code proj 中创建了 iphone 应用程序。 我添加了其他链接标志我的库名称(-lxyz)//我的库名称是 libxyz.a 我添加了lib搜索路径,header搜索路径

3) 然后我编译了。我有错误。 说 operator new,operator delete not found。

3) 然后除了我的 appdelegate,视图控制器,我添加了 虚拟 cpp(.h, .cpp)... atestdummy.h attestdummy.cpp

4) 然后我再次构建...

它成功了。

所以 - 我之前提出的任何建议都对我有用。 基本原因,除非您的应用程序看到带有 cpp 代码的 .cpp 文件 .mm 文件, 链接不会使用 g++。

谢谢大家。 我已阅读上述内容并解决了我的问题。

你们很高兴分享。

【讨论】:

    猜你喜欢
    • 2012-09-30
    • 1970-01-01
    • 1970-01-01
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多