2010-01-03 3 views
3

Я пытаюсь понять, почему, когда я конвертирую файл main.m в файл main.mm, он больше не будет правильно связываться.linking object C++

У меня есть задача сводится к следующему примеру кода:

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

Я использую GNUstep и Linux. Я введите следующие команды и все работает, как ожидалось:

г ++ -g -c main.m -I/USR/GNUstep/Local/Библиотека/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 to main.mm и использовать эти две команды (то же самое, кроме main.m now main.mm):

g ++ -g -c main.mm -I/usr/GNUstep/Local/Library/Headers -I/usr/GNUstep/Система/Библиотека/Заголовки

г ++ -g -o тест main.o -L/USR/GNUstep/Local/Library/Библиотеки -L/USR/GNUstep/System/Library/Библиотеки -lgnustep база -lgnustep-гуй

Я получаю следующая ошибка: main.mm:7: неопределенная ссылка на `NSApplicationMain (int, char const **) '

Может ли кто-нибудь найти то, что я делаю неправильно? Я не понимаю, почему сейчас он не связан.

Я пытаюсь добавить некоторые классы C++ к объектной программе c, и это мешает мне продолжать.

Благодарим за помощь, которую вы можете предоставить.

ответ

9

Проблема заключается в том, что при компиляции в C++, компилятор mangles the name символа NSApplicationMain, поэтому он может Не находите, так как он ищет что-то вроде __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 

Для того, чтобы избежать этой проблемы, функции C должны быть объявлены с extern "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" (что было бы очень хаки и 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, сообщив им добавить правильные объявления extern "C" в свои файлы заголовков.

4

Проблема заключается в том, что компиляторы с именем mangling C++ обычно используют для включения перегрузки функций на этапе ссылки.

C++ определяет директиву extern "C", которая заставляет ее использовать C-совместимое имя для функции.

Вы можете использовать его в C++ файл следующим образом: -

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

В заголовочном файле, который включен на C и C++ необходимо защитить Экстерн «C» заявление от 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 не защитила NSApplicationMain с внешней директивой «C», о которой я не могу догадаться, но она явно не охраняется.

Простой, если брутальный, исправить бы изменить ваши #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); 
}