2013年3月9日土曜日

Objective-C から C++

iOSやMac OS アプリケーションを作っている時, 主要な部分をObjective-C で書き, C, C++ ライブラリや, 過去の資産のコードを使いたいというケースがあるはずです。

実は, C, C++ なんかのデバッグは, XCode でやればいいのではと最近思うようになりました(Eclipse + CDTよりも)

こういったケースでは, Objective-C のコードから, C, C++ を呼び出すわけです。Cは特に問題ありませんがC++ にはちょっとした工夫が必要です。

Objective-C は C です

これさえわかっていれば, 実はどうってことないわけですが...

さくっと解決策は, 2つです

1. extern C を使って, C 関数として呼び出す
2. Objective-C++ (.mm) を使って, C++ のコードとしてObjective-Cを扱う


ちょっとした例をあげながら確認していきましょう

Objective-C から C を呼び出す
 test.c(C source), test.h(C header), CWrapper.h(C header), CWrapper.m(Objective-C source)

というソースを用意しました

ex) test.c

#include "test.h"
#include<stdio.h>
void testFunc()
{
   printf("Hello C\n");
}

ex)test.h
#ifndef AudoSamples_testc_h
#define AudoSamples_testc_h
void testFunc();
#endif

ex)CWrapper.h
#include "test.h"
@interface CWrapper : NSObject
+(void)callC;
@end

ex)CWrapper.m
#import "CWrapper.h"
@implementation CWrapper
+(void)callC
{
   testFunc();
}
@end

How to use
[CWrapper callC];


このコードは問題なく動作します.

・Objective-CからC++を呼び出す

ex) testcp.cpp(C++ source), testcp.h(C++ header)
をさらに追加しました


ex) testcp.h
#ifdef __AudioSamples__File__
#define __AudioSamples__File__

void testCpp();

#endif

これを, C++ のヘッダーに変えましょう。XCode の、Inspector で変更します

ex) testcp.cpp


#include "testcp.h"
void testCpp()
{
   std::cout << "Hello cpp" << std::endl;
}


先ほどの, CWapper.h を変更します

ex) CWapper.h
#include "test.h"
#include "testcp.h"
@interface CWrapper : NSObject
+(void)callC;
+(void)callCpp;
@end



先ほどの, CWrapper.mを変更します

ex) CWrapper.m


#import "CWrapper.h"
@implementation CWrapper
+(void)callC
{
   testFunc();
}

+(void)callCpp
{
   testCpp();
}

@end


このソースはコンパイルはできますが, リンクができません。

Apple Match-O Linker Error Undefined symbols for architecture i386:

といったように, C++ で作った関数 testCpp がないというのです, コンパイルできてるのに, みつからないだと...




実際 testcp.o というObject ファイルは生成されているようです。ですが中身が, C++ の関数になっているので うまくリンクできません。
UNIX コマンド nm で確認してみるとよくわかります

nm testcp.o

これはおいておいて, 解決策にまいりましょう


1. extern C を使って, C 関数として呼び出す

定義部分のところで, Cの関数として呼び出すように変更します

testcp.h を変更します
ex)

#ifdef __AudioSamples__File__
#define __AudioSamples__File__

#ifdef __cplusplus
#extern "C" {
#endif
void testCpp();
#ifdef __cplusplus
}
#endif
#endif

これで, Objective-C から, C++ を呼び出せるようになりました

2. Objective-C++ (.mm) を使って, C++ のコードとしてObjective-Cを扱う

こちらは, Objective-C++ というのを使って, Objective-CをC++ としてしまいます

例を変えて説明しましょう


ex) pure.cpp(C++), pure.h(C++), CpWrapper.h(C++), CpWrapper.mm(Objective-C++)

ex) pure.h

#ifndef __AudioSamples__pure__
#define __AudioSamples__pure__
void pureCpp();
#endif


ex) pure.cpp
#include "pure.h"
#include <iostream>

void pureCpp()
{
   std::cout << "I am CP9" << std::endl;
}

ex) CpWrapper.h
#import <Foundation/Foundation.h>
#include "pure.h"
@interface CpWrapper : NSObject
@end

ex) CpWrapper.mm
#import "CpWrapper.h"
@implementation CpWrapper
void pureCppCall()
{
   pureCpp();
}
@end










0 件のコメント:

コメントを投稿