链接目标c ++

时间:2010-01-03 16:59:27

标签: c++ objective-c linker gnustep

我试图找出为什么当我将main.m文件转换为main.mm文件时,它不再能正常链接。

我已将问题缩减为以下示例代码:

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
int main( int argc, const char ** argv ) {
return NSApplicationMain( argc, argv);
}

我正在使用gnustep和linux。我输入以下命令,一切都按预期工作:

g ++ -g -c main.m -I / usr / GNUstep / Local / Library / Headers -I / usr / GNUstep / System / Library / Headers

g ++ -g -o test main.o -L / usr / GNUstep / Local / Library / Libraries -L / usr / GNUstep / System / Library / Libraries -lgnustep-base -lgnustep-gui

现在如果我将main.m重命名为main.mm并使用这两个命令(同样exept main.m now main.mm):

g ++ -g -c main.mm -I / usr / GNUstep / Local / Library / Headers -I / usr / GNUstep / System / Library / Headers

g ++ -g -o test main.o -L / usr / GNUstep / Local / Library / Libraries -L / usr / GNUstep / System / Library / Libraries -lgnustep-base -lgnustep-gui

我收到以下错误: main.mm:7:未定义引用`NSApplicationMain(int,char const **)'

有人可以找到我做错的事吗?我不明白为什么它现在无法链接。

我正在尝试将一些C ++类添加到目标c程序中,这使我无法继续。

感谢您提供任何帮助。

2 个答案:

答案 0 :(得分:9)

问题在于,当你将它编译为C ++时,符号NSApplicationMain的编译器mangles the name,因此无法找到它,因为它正在寻找像__Z17NSApplicationMainiPPKc这样的东西。您可以使用nm程序(来自binutils)查看目标文件引用的符号:

$ # When compiled as Objective-C:
$ nm main.o | grep NSApplicationMain
                 U NSApplicationMain
$ # When compiled as Objective-C++:
$ nm main.o | grep NSApplicationMain
                 U _Z17NSApplicationMainiPPKc

为了避免这个问题,需要使用extern "C"修饰符声明C函数,以告诉编译器不要破坏名称。查看<AppKit/NSApplication.h>,声明NSApplicationMain的头文件,我看到了:

APPKIT_EXPORT int
NSApplicationMain(int argc, const char **argv);

唉,APPKIT_EXPORT被定义为extern__declspec(dllexport)extern __declspec(dllexport)中的一个,或<AppKit/AppKitDefines.h>中的任何内容。因为它也用于全局变量声明,所以我们无法通过将其重新定义为extern "C"来解决这个问题(无论如何这将非常hacky和kludgy)。 AppKit头文件似乎根本不包含任何extern "C"声明,但我确实在Foundation/GNUStepBase/下的各种头文件中看到它们。

那你能做什么?解决方案是使用extern "C"包装您的包含:

extern "C"
{
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
}

int main( int argc, const char ** argv ) {
  return NSApplicationMain( argc, argv);
}

这将为这些头文件中定义的函数提供正确的链接,并且它将全部解决。但你不应该这样做 - 我会用GNUstep提交一个bug报告,告诉他们在头文件中添加正确的extern "C"声明。

答案 1 :(得分:4)

问题是名称修改c ++编译器通常用于在链接阶段启用函数重载。

C ++定义了一个extern "C"指令,强制它为函数使用C兼容名称。

您可以在C ++文件中使用它,如下所示: -

  // this makes func use a C compatible linkage
  extern "C" void func(int a)
  {

在C和C ++包含的头文件中,必须保护C中的extern“C”声明,并且C编译器不会支持它。

#ifndef EXTERN_C
#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C
#endif
#endif
// Use it like this to declare a Function with C linkage
EXTERN_C void func(int a);
// If you have a lot of functions and declarations that need to be C compatible
#ifdef __cplusplus
extern "C" {
#endif
//functions with C linkage
void func(int a);
...
#ifdef __cplusplus
}
#endif

现在,这对您的问题有何帮助?好吧,main.mm表示Foundation.h和AppKit.h文件正在编译为C ++。为什么Apple没有使用外部“C”指令来保护NSApplicationMain我无法猜测,但它显然没有受到保护。

一个简单的,如果是残酷的修复,就是改变你的#imports,如下所示:

extern "C" {
// All declarations inside this block will use C linkage
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
}

int main( int argc, const char ** argv ) {
  return NSApplicationMain( argc, argv);
}