是否可以拥有一个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”,我只是不确定调用项目中需要哪些配置。即。如果调用的预测需要知道它是否使用了C ++,或者可能是无知的,并认为它是一个纯粹的C库。
似乎我不能,我必须在ObjectiveC类上使用(.mm)文件。
答案 0 :(得分:34)
在评论中这样做太难了,所以我只是想快速向你展示你所拥有的链接问题。当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 ++,您的问题将得到解决。
答案 1 :(得分:2)
您应该声明要显示的功能extern "C"
。他们的签名需要是C兼容的,但内容不是(例如,你可以访问C ++对象,但你不能直接传递它们;指针是可以的)。然后,符号将对任何C兼容环境可见。
编辑:并将其编译为C ++源文件,C没有语言链接的概念。还有一些其他问题与语言链接(例如,所有具有相同名称的extern "C"
函数都是相同的函数,无论命名空间如何)。
EDIT2:在标题中,您可以检查宏__cplusplus
,并分别使用它来设置C ++和其他语言(因为C ++需要extern "C"
声明,其他语言也可能抱怨他们。)
答案 2 :(得分:1)
基本上,当您使用C ++编译器编译C函数时,它会破坏函数名称并使用C ++ ABI。
当您使用* .cpp或* .mm扩展名时,您正在使用C ++编译器。
你想要做的是强制编译器使用un-mangles名称生成C函数并使用C ABI。
您可以通过以下方式执行此操作:
设置头文件的最佳方式是,可以从C和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
答案 3 :(得分:1)
谢谢你们这么好的讨论。
我做的是:
1)我使用cocaotouch static lib选项创建了一个静态库。在那我有c / c ++ / obj-c所有混合。但是,我的出口只是obj-c类。 事实上,我使用objc-to c to C ++。
2)然后我在X-code proj中创建了iphone应用程序。 我添加了其他链接标志我的lib名称(-lxyz)//我的lib名称是libxyz.a 我添加了lib搜索路径,标题搜索路径
3)然后我编译了。我有错误。 说oeprator new,operator delete not found。
3)然后分开我的appdelegate,查看控制器,我补充说 虚拟cpp(.h,.cpp)...... atestdummy.h atestdummy.cpp
4)然后我再次建造......
这是有效的。所以 - 我之前提出的任何建议都是为我工作的。 基本原因,除非你的应用程序看到带有cpp代码的.cpp文件.mm文件, 链接不会使用g ++。
谢谢大家。 我已经阅读了上述内容并解决了我的问题。
你们很高兴分享。