두 마리 토끼를 잡기 위한 
C++ - C# 혼합 멀티플랫폼 
게임 아키텍처 설계 
㈜이노스파크 
Technical Director 
김성균
목차 
1. 개요 
2. C# (.NET) 실행환경 
3. 언어 간 인터페이스 결합 자동화 
4. 언어 간 개체 결합 
5. 결론 
6. 부록
동기 
 빠른 성능 
 구현의 자유성 
 높은 이식성 
− 코딩의 실수는 치명적 
− 낮은 생산성 
 높은 생산성 (문법, OOP …) 
 적절한 성능 
 C++와 유사한 문법 
− 저수준 제어 어려움 
− 다른 환경과 연동 어려움
목표 
언어간 코드 연동을 위한 작업량 최소화 
코드를 다른 언어로 손쉽게 변환 
• 성능이 중요한 기능 
• 저수준 제어 
• 외부 라이브러리 연동 
• 빠른 구현과 잦은 변경이 필 
요한 상위 수준의 기능들 
• 성능이 중요하지 않은 코드
Native 
Code 
Script 
Lib
구성 요소 
C# 런타임 
언어 간 인터페이 
스 자동화 
언어 간 개체 결합
C# (.NET) 실행환경
Mono™ = Microsoft .NET의 포팅 
≈ 오픈소스, 공짜 아님
각 플랫폼용 Mono 빌드 
소스코드 
mono 
Runtime 
(.a .so .lib .dll) 
make 
make 
configure 
Compiler
App 
Embedded Mono 
Native Runtime 
.NET Assembly 
로드 & JIT 컴파일 
컴 
파 
일 
JIT / AOT Binary 
Mono Runtime 
실행 
.NET Compiler 
Objective-C 
Runtime 
Java VM
임베딩을 위한 C# 코드 처리 
.NET Compiler 
monolinker 
mono 
Reduced Assembly 
.NET Assembly 
Stripped Assembly 
mov … 
push … 
call … 
Assembly Code 
.NET Libraries 
AOT 컴파일
Embedded Mono 유의사항 
Ahead-of-Time 컴파일 
– Just-in-Time 실행을 지원하지 않는 OS를 위함 
– 실행될 CPU/OS 마다 별도의 Mono 컴파일러와 런타임 필요 
– 실행파일 크기 문제 
– 리소스 업데이트로 C# 코드 업데이트 불가능 
디버깅 
– Custom Command Soft Debugger 사용 필요 
– 디버깅 대상이 client, MonoDevelop이 server로 작동 
– 쓰레드에서 Mono 코드를 실행하지 않으면 중단점 작동 안됨 
sgen GC 사용시 MonoObject* 대신 gc_handle 에 의존 
mono_trace_set_level_string 사용 추천
언어 간 인터페이스 결합 자동화
목표: 언어간 혼용의 자유도 
class Character 
{ 
void SetPosition( float ); 
float position; 
}; 
class Character 
{ 
void Touched() … 
void UpdateUI() … 
int health; 
}
목표: 언어간 혼용의 자유도 
void Character::Touched() 
{ 
SetPosition( position + 1 ); 
} 
class Character 
{ 
void SetPosition( float ); 
float position; 
};
목표: 언어간 혼용의 자유도 
void Character::SetPosition( float position ) 
{ 
… 
health = … 
UpdateUI(); 
} 
class Character 
{ 
void Touched() … 
void UpdateUI() … 
int health; 
}
목표: 언어간 혼용의 자유도 
• 구현의 특성에 가장 적합한 언어에서 코딩 
• C# 모듈을 C++ 처럼, C++ 모듈을 C# 처럼 사용 
• 인터페이스용 코드 필요 
– 각 타입에 대한 메타정보 등록 코드 
– 호출 언어를 위해 정의된 선언(declaration) 코드 
• 언어 간 인터페이스를 자동화 한다면?!
언어간 인터페이스 자동생성 
C++ 소 
스코드 
(.h) 
C# 소스 
코드 
C++ 인 
터페이스 
C# 코드 
C# 인터 
페이스 
C++ 코 
드 
2 
3 
4 
1 
CppSharp 
CXXI 
…
C#을 위한 C++ 인터페이스 자동생성 
CppSharp 
CXXI 
+ Clang 
1. C++ 헤더파일들을 파싱(!)하여 인터페이스들 분석 
2. (C++ 인터페이스를 Mono에 노출하는 C++ 코드)와 
이를 호출할 수 있는 C# 코드 생성 
3. C# 코드에서 인터페이스 코드를 호출 
4. C# 코드 컴파일시 인터페이스 코드를 함께 컴파일
C++ 파싱 - Clang 
 LLVM 컴파일러의 C/C++ 파서 
 상용 제품 수준 
 Visual C++ 구문들도 인식 
 불완전한 구문에 의해 파싱이 실패하지 않음 
 libclang을 이용하여 스크립트 언어에서도 사용 가능, 
Python 모듈 기본 제공 – AST 생성 
− libclang은 clang의 극히 일부의 기능만을 노출하므 
로 커스터마이제이션 필요
C++ 인터페이스 생성 예제 (CppSharp) 
// C++ 소스코드 
class Foo 
{ 
int variable; 
int DoSomething ( int arg1, std::string arg2 ); 
}; 
// 자동 생성된 C#용 인터페이스 코드 
class Foo 
{ 
// C++의 메모리 레이아웃 선언 
struct Internal { … } 
// 사용자를 위한 편리한 인터페이스 
int variable { 
get { return _Instance.ToPointer()->variable; } 
set { _Instance.ToPointer()->variable = value; } 
} 
int DoSomething( int arg1, string arg2 ) 
{ return Internal.DoSomething( _Instance, arg1, arg2 ); } 
}
C++ 인터페이스 생성 예제 (Embedded) 
// C++ 소스코드 
#define EXPORT __attribute__((annotate(“ExportToMono”))) 
class EXPORT Foo 
{ 
int variable; 
int DoSomething ( int arg1, std::string arg2 ); 
}; 
+ Clang 
// 자동 생성된 클래스 등록 코드 
RegisterNativeClass<Foo>(); 
RegisterNativeClassVariable<Foo,int>( “variable”, offsetof(Foo, variable) ); 
RegisterNativeClassMethod<Foo,int,int,std::string>( “DoSomething”, &Foo::DoSomething );
C++ 인터페이스 생성 예제 (Embedded) 
// 자동 생성된 클래스 등록 코드에 의한 실제 내부 작동 
RegisterNativeClass<Foo>(); 
// Foo 타입에 대한 RTTI등 각종 기본 정보들 등록 
RegisterNativeClassVariable<Foo,int>( “variable”, offsetof(Foo, variable) ); 
// C#에서 호출할 accessor 메소드 등록 
int NativeGetInt( void* nativeObject, int offset ); 
mono_add_internal_call( “NativeGetInt”, &NativeGetInt ); 
void NativeSetInt( void* nativeObject, int offset, int value ); 
mono_add_internal_call( “NativeSetInt”, &NativeSetInt ); 
RegisterNativeClassMethod<Foo,int,int,std::string>( “DoSomething”, &Foo::DoSomething ); 
// C#에서 호출할 메소드 등록 
static int Foo_DoSomething( Foo* nativeObject, int arg1, std::string arg2 ) 
{ nativeObject->DoSomething( arg1, arg2 ); } 
mono_add_internal_call( “Foo.NativeCall_DoSomething”, &Foo_DoSomething );
C++ 인터페이스 생성 예제 (Embedded) 
// 자동 생성된 C#용 인터페이스 코드 
class Foo 
{ 
// C++의 메소드들 등록 
[MethodImplAttribute(MethodImplOptions.InternalCall)] 
extern int NativeCall_DoSomething( IntPtr nativeObject, int arg1, string arg2 ); 
// 사용자를 위한 편리한 인터페이스 
int variable { 
get { return NativeGetInt( nativeObject, 4 ); } 
set { NativeSetInt( nativeObject, 4 ); } 
} 
int DoSomething( int arg1, string arg2 ) 
{ return NativeCall_DoSomething( nativeObject, arg1, arg2 ); } 
}
C++를 위한 C# 인터페이스 자동생성 
1. .NET reflection을 사용하여 DLL 안의 인터페이스 
들 추적 
2. DLL 인터페이스를 호출할 수 있는 C++ 코드 생성 
3. C++ 게임코드에서 인터페이스 코드를 통해 DLL의 
코드를 C++ 처럼 호출 
4. C++ 게임코드 컴파일시 인터페이스 코드를 함께 
컴파일
C# 인터페이스 생성 예제 (Delegate) 
// 자동 생성된 C# 인터페이스 코드 
partial class Foo 
{ 
void ExposeToNative() { 
RegisterMonoMethod( 0, () => { return variable; } ); // Get_variable 
RegisterMonoMethod( 1, (int value) => { variable = value; } ); // Set_variable 
RegisterMonoMethod( 2, DoSomething ); // DoSomething 
} 
} 
// 자동 생성된 C++ 인터페이스 코드 
class Foo 
{ 
int Get_variable() { monoMethods[0](); } 
void Set_variable( int value ) { return monoMethods[1]( value ); } 
int DoSomething( int arg1, std::string arg2 ) 
{ return monoMethods[2]( arg1, arg2 ); } 
}; 
delegate를 native 함수 포인터로 전달 
RegisterMonoMethod에 의해 등록된 함수 포인터
C# 인터페이스 생성 예제 (Embedded) 
// C# 소스코드 
[Export] 
class Foo 
{ 
// 자동 생성된 C++용 인터페이스 코드 
class Foo 
{ 
int variable; 
int DoSomething( int arg1, string arg2 ) { … } 
} 
int Get_variable() { 
void* ret = mono_runtime_invoke( monoClass, monoObject, “get_variable” ); 
return *(int*)ret; 
} 
void Set_variable( int value ) { 
mono_runtime_invoke( monoClass, monoObject, “set_variable”, [&value] ); 
} 
int DoSomething( int arg1, std::string arg2 ) { 
void* ret = mono_runtime_invoke( monoClass, monoObject, “DoSomething”, 
[&arg1, mono_string_new_wrapper(arg2)] ); 
return *(int*)ret; 
} 
};
언어 간 개체 결합
언어 간 결합의 깊이 
모듈 간 결합 다른 객체 간 결합 객체 수준 결합 
C++ Class 
C++ variables 
C++ methods 
C# Class 
C# variables 
C# methods 
Hybrid Class 
C++ variables 
C# variables 
C++ methods 
C# methods 
오브젝트 참조 
클래스 형 변환 
C++ 기능 모듈 
표준 호출 
단순 타입 
C# 기능 모듈 
개체 생명주기 관리
객체 수준 결합 
단일 메모리의 구역 분할 
• C# 클래스 선언에서 C++ 클래스의 
영역 미리 선언 필요 
• 개체의 수명은 C#에 의해서만 관 
리되어야 함 
• C++ new/delete 사용 불가
객체 수준 결합 
개체 분할, 논리적 결합 
• 독립적인 C++개체와 C#개체 
• 필요할 때에만 상대개체 생성 가 
능 
• 자동생성된 소스코드 빌드에 유리 
(partial class) 
• 개체 수명관리가 핵심
Garbage Collection vs new/delete 
C++ 개체가 소유자 
mono_gchandle_new 
mono_gchandle_free 
C# 개체가 소유자 상호 참조 
new / delete 
gchandle refcount
상대 개체 동적생성 예제 
// 자동생성된 C++용 인터페이스 코드 
class FooProxy 
{ 
FooProxy( Foo* nativeObject ) 
{ // C#측의 Foo 개체가 없으면 생성 } 
int DoInCS( int arg ) 
{ // C#측의 Foo.DoInCS 호출 } 
}; 
// C# 소스코드 
class Foo : public NativeBound 
{ 
int DoInCS( int arg ) { … } 
} 
// C++ 소스코드 
class Foo : public MonoBound 
{ 
int DoInCPP( int arg ) 
{ 
return FooProxy(this).DoInCS(arg); 
} 
}; 
성능 주의
삭제 - Garbage Collector 연동 
살아있는 쌍 GC 활성화 Native 삭제 
GC handle 
3 1 
Mono GC에 의 
해 제거 가능 
Mono GC에 의 
해 제거 방지 
Mono 
GC 
Native 
GC 
0 
Mono GC에 의해 
제거됨 
삭제됨 
참조 카운트 
GC handle 삭제
최종 형태 
Data Engine 
부분 최적화 
과거의 
게임코드
결론 
Roslyn 
.NET Native, IL2CPP 
CppSharp, Script# 
거의 모든 플랫폼에서 .NET과 C# 사용 가능 
언어간 혼합의 자동화 → 더욱 높은 생산성과 이식성 
.NET과 C#은 여전히 진화중
Q&A 
감사합니다
부록
참고자료 
.NET 
– Reflection: http://msdn.microsoft.com/en-us/library/f7ykdhsy(v=vs.110).aspx 
– Garbage Collection: http://msdn.microsoft.com/en-us/library/0xy59wtx(v=vs.110).aspx 
Mono 
– http://www.mono-project.com 
– Compiling Mono: http://www.mono-project.com/docs/compiling-mono/compiling-from-git/ 
– Embedding Mono: http://www.mono-project.com/docs/advanced/embedding/ 
– InterOp with Native: http://www.mono-project.com/docs/advanced/pinvoke/ 
– CppSharp: https://github.com/mono/CppSharp 
– CXXI: http://tirania.org/blog/archive/2011/Dec-19.html 
– Mono for Unreal Engine: http://mono-ue.github.io/ 
Clang 
– http://clang.llvm.org 
– Python with Clang: http://eli.thegreenplace.net/2011/07/03/parsing-c-in-python-with-clang
iOS 시뮬레이터용 Mono 런타임 configure 
• --build=i386-apple-darwin13.0.0 
• CC, CXX=<Xcode 
configure 
path>/Contents/Developer/Platforms/iPhoneSimulator.p 
latform/Developer/usr/bin 안의 gcc와 g++ 
• CFLAGS, CXXFLAGS 
– -arch i386 –miphoneos-version-min=<최소지원버전> 
– -isysroot=<Xcode 
path>/Contents/Developer/Platforms/iPhoneSimulator.platform/Deve 
loper/SDKs/iPhoneSimulator<버전>.sdk 
• LD, AS, AR, LIBTOOL, STRIP, 
RANLIB=<iPhoneSimulator SDK>/usr/bin 안에 있는 툴들 
사용
iOS 기기용 Mono 런타임 configure 
• --host=arm-apple-darwin10 
• --target=arm-apple-darwin10 
• CC, CXX=<Xcode 
Mono 3.2의 경우 XCode 4.x를 configure 
사용해야 함 
path>/Contents/Developer/Toolchains/XcodeDefault.xctoolc 
hain/usr/bin 안의 clang과 clang++ 
• CFLAGS, CXXFLAGS 
– -arch armv7 
– -isysroot=<Xcode 
path>/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SD 
Ks/iPhoneOS???.sdk 
• LD, AS, AR, LIBTOOL, STRIP, RANLIB=<Xcode 
path>/Contents/Developer/Platforms/iPhoneOS.platform/Dev 
eloper/usr/bin 안에 있는 툴들 사용
Android 기기용 Mono 런타임 configure 
• --host=arm-linux-androideabi 
• --target=arm-linux-androideabi 
• CC, CXX=<Xcode 
path>/Contents/Developer/Toolchains/XcodeDefault.xctoolc 
hain/usr/bin 안의 clang과 clang++ 
• CFLAGS, CXXFLAGS 
– -march=armv7-a 
– -mfloat-abi=softfp 
– -mfpu=neon 
– --sysroot=<NDK_ROOT>/platforms/android-<version>/arch-arm 
• LD, AS, AR, LIBTOOL, STRIP, RANLIB 설정 불필요 
• --libdir <NDK_ROOT>/platforms/android-<version>/arch-arm/ 
usr/lib 
configure
C++ → Lua 예제 
// 자동 생성된 클래스 등록 코드에 의한 실제 내부 작동 
RegisterNativeClass<Foo>(); 
// 클래스를 lua table로 생성 
lua_createtable( “Foo” ); 
RegisterNativeClassVariable<Foo,int>( “variable”, offsetof(Foo, variable) ); 
// lua table에 getter/setter 멤버 함수들 등록 
lua_pushcclosure( “Get_variable”, &NativeGetInt ); 
lua_pushcclosure( “Set_variable”, &NativeSetInt ); 
RegisterNativeClassMethod<Foo,int,int,std::string>( “DoSomething”, &Foo::DoSomething ); 
// lua table에 멤버 함수 호출자 등록 
lua_pushcclosure( “DoSomething”, &Foo_DoSomething ); 
// 자동 생성된 lua용 인터페이스 코드 - 주석 또는 Lua Checker 용도 외에는 필요 없음 
Foo = { 
Get_variable = function(), 
Set_variable = function( int_value ), 
DoSomething = function( int_arg1, string_arg2 ) 
} 
명시적 accessor 대신 __index, 
__newindex로 구현 가능
Lua → C++ 예제 
// lua 소스코드 
Foo = { 
variable = 0, 
int_DoSomething = function( int_arg1, string_arg2 ) 
… 
end 
// 자동 생성된 C++용 인터페이스 코드 
} 
class Foo 
{ 
int Get_variable() { return lua_tointeger( “variable” ); } 
void Set_variable( int value ) { lua_pushinteger( “variable”, value ); } 
int DoSomething( int arg1, std::string arg2 ) 
{ 
lua_pushinteger( arg1 ); 
lua_pushstring( arg2 ); 
lua_pcall( “DoSomething” ); 
return lua_tointeger( STACK_TOP ); 
} 
};

[KGC2014] 두 마리 토끼를 잡기 위한 C++ - C# 혼합 멀티플랫폼 게임 아키텍처 설계

  • 1.
    두 마리 토끼를잡기 위한 C++ - C# 혼합 멀티플랫폼 게임 아키텍처 설계 ㈜이노스파크 Technical Director 김성균
  • 2.
    목차 1. 개요 2. C# (.NET) 실행환경 3. 언어 간 인터페이스 결합 자동화 4. 언어 간 개체 결합 5. 결론 6. 부록
  • 5.
    동기  빠른성능  구현의 자유성  높은 이식성 − 코딩의 실수는 치명적 − 낮은 생산성  높은 생산성 (문법, OOP …)  적절한 성능  C++와 유사한 문법 − 저수준 제어 어려움 − 다른 환경과 연동 어려움
  • 7.
    목표 언어간 코드연동을 위한 작업량 최소화 코드를 다른 언어로 손쉽게 변환 • 성능이 중요한 기능 • 저수준 제어 • 외부 라이브러리 연동 • 빠른 구현과 잦은 변경이 필 요한 상위 수준의 기능들 • 성능이 중요하지 않은 코드
  • 9.
  • 10.
    구성 요소 C#런타임 언어 간 인터페이 스 자동화 언어 간 개체 결합
  • 11.
  • 12.
    Mono™ = Microsoft.NET의 포팅 ≈ 오픈소스, 공짜 아님
  • 13.
    각 플랫폼용 Mono빌드 소스코드 mono Runtime (.a .so .lib .dll) make make configure Compiler
  • 14.
    App Embedded Mono Native Runtime .NET Assembly 로드 & JIT 컴파일 컴 파 일 JIT / AOT Binary Mono Runtime 실행 .NET Compiler Objective-C Runtime Java VM
  • 15.
    임베딩을 위한 C#코드 처리 .NET Compiler monolinker mono Reduced Assembly .NET Assembly Stripped Assembly mov … push … call … Assembly Code .NET Libraries AOT 컴파일
  • 16.
    Embedded Mono 유의사항 Ahead-of-Time 컴파일 – Just-in-Time 실행을 지원하지 않는 OS를 위함 – 실행될 CPU/OS 마다 별도의 Mono 컴파일러와 런타임 필요 – 실행파일 크기 문제 – 리소스 업데이트로 C# 코드 업데이트 불가능 디버깅 – Custom Command Soft Debugger 사용 필요 – 디버깅 대상이 client, MonoDevelop이 server로 작동 – 쓰레드에서 Mono 코드를 실행하지 않으면 중단점 작동 안됨 sgen GC 사용시 MonoObject* 대신 gc_handle 에 의존 mono_trace_set_level_string 사용 추천
  • 17.
  • 18.
    목표: 언어간 혼용의자유도 class Character { void SetPosition( float ); float position; }; class Character { void Touched() … void UpdateUI() … int health; }
  • 19.
    목표: 언어간 혼용의자유도 void Character::Touched() { SetPosition( position + 1 ); } class Character { void SetPosition( float ); float position; };
  • 20.
    목표: 언어간 혼용의자유도 void Character::SetPosition( float position ) { … health = … UpdateUI(); } class Character { void Touched() … void UpdateUI() … int health; }
  • 21.
    목표: 언어간 혼용의자유도 • 구현의 특성에 가장 적합한 언어에서 코딩 • C# 모듈을 C++ 처럼, C++ 모듈을 C# 처럼 사용 • 인터페이스용 코드 필요 – 각 타입에 대한 메타정보 등록 코드 – 호출 언어를 위해 정의된 선언(declaration) 코드 • 언어 간 인터페이스를 자동화 한다면?!
  • 22.
    언어간 인터페이스 자동생성 C++ 소 스코드 (.h) C# 소스 코드 C++ 인 터페이스 C# 코드 C# 인터 페이스 C++ 코 드 2 3 4 1 CppSharp CXXI …
  • 23.
    C#을 위한 C++인터페이스 자동생성 CppSharp CXXI + Clang 1. C++ 헤더파일들을 파싱(!)하여 인터페이스들 분석 2. (C++ 인터페이스를 Mono에 노출하는 C++ 코드)와 이를 호출할 수 있는 C# 코드 생성 3. C# 코드에서 인터페이스 코드를 호출 4. C# 코드 컴파일시 인터페이스 코드를 함께 컴파일
  • 24.
    C++ 파싱 -Clang  LLVM 컴파일러의 C/C++ 파서  상용 제품 수준  Visual C++ 구문들도 인식  불완전한 구문에 의해 파싱이 실패하지 않음  libclang을 이용하여 스크립트 언어에서도 사용 가능, Python 모듈 기본 제공 – AST 생성 − libclang은 clang의 극히 일부의 기능만을 노출하므 로 커스터마이제이션 필요
  • 25.
    C++ 인터페이스 생성예제 (CppSharp) // C++ 소스코드 class Foo { int variable; int DoSomething ( int arg1, std::string arg2 ); }; // 자동 생성된 C#용 인터페이스 코드 class Foo { // C++의 메모리 레이아웃 선언 struct Internal { … } // 사용자를 위한 편리한 인터페이스 int variable { get { return _Instance.ToPointer()->variable; } set { _Instance.ToPointer()->variable = value; } } int DoSomething( int arg1, string arg2 ) { return Internal.DoSomething( _Instance, arg1, arg2 ); } }
  • 26.
    C++ 인터페이스 생성예제 (Embedded) // C++ 소스코드 #define EXPORT __attribute__((annotate(“ExportToMono”))) class EXPORT Foo { int variable; int DoSomething ( int arg1, std::string arg2 ); }; + Clang // 자동 생성된 클래스 등록 코드 RegisterNativeClass<Foo>(); RegisterNativeClassVariable<Foo,int>( “variable”, offsetof(Foo, variable) ); RegisterNativeClassMethod<Foo,int,int,std::string>( “DoSomething”, &Foo::DoSomething );
  • 27.
    C++ 인터페이스 생성예제 (Embedded) // 자동 생성된 클래스 등록 코드에 의한 실제 내부 작동 RegisterNativeClass<Foo>(); // Foo 타입에 대한 RTTI등 각종 기본 정보들 등록 RegisterNativeClassVariable<Foo,int>( “variable”, offsetof(Foo, variable) ); // C#에서 호출할 accessor 메소드 등록 int NativeGetInt( void* nativeObject, int offset ); mono_add_internal_call( “NativeGetInt”, &NativeGetInt ); void NativeSetInt( void* nativeObject, int offset, int value ); mono_add_internal_call( “NativeSetInt”, &NativeSetInt ); RegisterNativeClassMethod<Foo,int,int,std::string>( “DoSomething”, &Foo::DoSomething ); // C#에서 호출할 메소드 등록 static int Foo_DoSomething( Foo* nativeObject, int arg1, std::string arg2 ) { nativeObject->DoSomething( arg1, arg2 ); } mono_add_internal_call( “Foo.NativeCall_DoSomething”, &Foo_DoSomething );
  • 28.
    C++ 인터페이스 생성예제 (Embedded) // 자동 생성된 C#용 인터페이스 코드 class Foo { // C++의 메소드들 등록 [MethodImplAttribute(MethodImplOptions.InternalCall)] extern int NativeCall_DoSomething( IntPtr nativeObject, int arg1, string arg2 ); // 사용자를 위한 편리한 인터페이스 int variable { get { return NativeGetInt( nativeObject, 4 ); } set { NativeSetInt( nativeObject, 4 ); } } int DoSomething( int arg1, string arg2 ) { return NativeCall_DoSomething( nativeObject, arg1, arg2 ); } }
  • 29.
    C++를 위한 C#인터페이스 자동생성 1. .NET reflection을 사용하여 DLL 안의 인터페이스 들 추적 2. DLL 인터페이스를 호출할 수 있는 C++ 코드 생성 3. C++ 게임코드에서 인터페이스 코드를 통해 DLL의 코드를 C++ 처럼 호출 4. C++ 게임코드 컴파일시 인터페이스 코드를 함께 컴파일
  • 30.
    C# 인터페이스 생성예제 (Delegate) // 자동 생성된 C# 인터페이스 코드 partial class Foo { void ExposeToNative() { RegisterMonoMethod( 0, () => { return variable; } ); // Get_variable RegisterMonoMethod( 1, (int value) => { variable = value; } ); // Set_variable RegisterMonoMethod( 2, DoSomething ); // DoSomething } } // 자동 생성된 C++ 인터페이스 코드 class Foo { int Get_variable() { monoMethods[0](); } void Set_variable( int value ) { return monoMethods[1]( value ); } int DoSomething( int arg1, std::string arg2 ) { return monoMethods[2]( arg1, arg2 ); } }; delegate를 native 함수 포인터로 전달 RegisterMonoMethod에 의해 등록된 함수 포인터
  • 31.
    C# 인터페이스 생성예제 (Embedded) // C# 소스코드 [Export] class Foo { // 자동 생성된 C++용 인터페이스 코드 class Foo { int variable; int DoSomething( int arg1, string arg2 ) { … } } int Get_variable() { void* ret = mono_runtime_invoke( monoClass, monoObject, “get_variable” ); return *(int*)ret; } void Set_variable( int value ) { mono_runtime_invoke( monoClass, monoObject, “set_variable”, [&value] ); } int DoSomething( int arg1, std::string arg2 ) { void* ret = mono_runtime_invoke( monoClass, monoObject, “DoSomething”, [&arg1, mono_string_new_wrapper(arg2)] ); return *(int*)ret; } };
  • 32.
  • 33.
    언어 간 결합의깊이 모듈 간 결합 다른 객체 간 결합 객체 수준 결합 C++ Class C++ variables C++ methods C# Class C# variables C# methods Hybrid Class C++ variables C# variables C++ methods C# methods 오브젝트 참조 클래스 형 변환 C++ 기능 모듈 표준 호출 단순 타입 C# 기능 모듈 개체 생명주기 관리
  • 34.
    객체 수준 결합 단일 메모리의 구역 분할 • C# 클래스 선언에서 C++ 클래스의 영역 미리 선언 필요 • 개체의 수명은 C#에 의해서만 관 리되어야 함 • C++ new/delete 사용 불가
  • 35.
    객체 수준 결합 개체 분할, 논리적 결합 • 독립적인 C++개체와 C#개체 • 필요할 때에만 상대개체 생성 가 능 • 자동생성된 소스코드 빌드에 유리 (partial class) • 개체 수명관리가 핵심
  • 36.
    Garbage Collection vsnew/delete C++ 개체가 소유자 mono_gchandle_new mono_gchandle_free C# 개체가 소유자 상호 참조 new / delete gchandle refcount
  • 37.
    상대 개체 동적생성예제 // 자동생성된 C++용 인터페이스 코드 class FooProxy { FooProxy( Foo* nativeObject ) { // C#측의 Foo 개체가 없으면 생성 } int DoInCS( int arg ) { // C#측의 Foo.DoInCS 호출 } }; // C# 소스코드 class Foo : public NativeBound { int DoInCS( int arg ) { … } } // C++ 소스코드 class Foo : public MonoBound { int DoInCPP( int arg ) { return FooProxy(this).DoInCS(arg); } }; 성능 주의
  • 38.
    삭제 - GarbageCollector 연동 살아있는 쌍 GC 활성화 Native 삭제 GC handle 3 1 Mono GC에 의 해 제거 가능 Mono GC에 의 해 제거 방지 Mono GC Native GC 0 Mono GC에 의해 제거됨 삭제됨 참조 카운트 GC handle 삭제
  • 39.
    최종 형태 DataEngine 부분 최적화 과거의 게임코드
  • 40.
    결론 Roslyn .NETNative, IL2CPP CppSharp, Script# 거의 모든 플랫폼에서 .NET과 C# 사용 가능 언어간 혼합의 자동화 → 더욱 높은 생산성과 이식성 .NET과 C#은 여전히 진화중
  • 41.
  • 42.
  • 43.
    참고자료 .NET –Reflection: http://msdn.microsoft.com/en-us/library/f7ykdhsy(v=vs.110).aspx – Garbage Collection: http://msdn.microsoft.com/en-us/library/0xy59wtx(v=vs.110).aspx Mono – http://www.mono-project.com – Compiling Mono: http://www.mono-project.com/docs/compiling-mono/compiling-from-git/ – Embedding Mono: http://www.mono-project.com/docs/advanced/embedding/ – InterOp with Native: http://www.mono-project.com/docs/advanced/pinvoke/ – CppSharp: https://github.com/mono/CppSharp – CXXI: http://tirania.org/blog/archive/2011/Dec-19.html – Mono for Unreal Engine: http://mono-ue.github.io/ Clang – http://clang.llvm.org – Python with Clang: http://eli.thegreenplace.net/2011/07/03/parsing-c-in-python-with-clang
  • 44.
    iOS 시뮬레이터용 Mono런타임 configure • --build=i386-apple-darwin13.0.0 • CC, CXX=<Xcode configure path>/Contents/Developer/Platforms/iPhoneSimulator.p latform/Developer/usr/bin 안의 gcc와 g++ • CFLAGS, CXXFLAGS – -arch i386 –miphoneos-version-min=<최소지원버전> – -isysroot=<Xcode path>/Contents/Developer/Platforms/iPhoneSimulator.platform/Deve loper/SDKs/iPhoneSimulator<버전>.sdk • LD, AS, AR, LIBTOOL, STRIP, RANLIB=<iPhoneSimulator SDK>/usr/bin 안에 있는 툴들 사용
  • 45.
    iOS 기기용 Mono런타임 configure • --host=arm-apple-darwin10 • --target=arm-apple-darwin10 • CC, CXX=<Xcode Mono 3.2의 경우 XCode 4.x를 configure 사용해야 함 path>/Contents/Developer/Toolchains/XcodeDefault.xctoolc hain/usr/bin 안의 clang과 clang++ • CFLAGS, CXXFLAGS – -arch armv7 – -isysroot=<Xcode path>/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SD Ks/iPhoneOS???.sdk • LD, AS, AR, LIBTOOL, STRIP, RANLIB=<Xcode path>/Contents/Developer/Platforms/iPhoneOS.platform/Dev eloper/usr/bin 안에 있는 툴들 사용
  • 46.
    Android 기기용 Mono런타임 configure • --host=arm-linux-androideabi • --target=arm-linux-androideabi • CC, CXX=<Xcode path>/Contents/Developer/Toolchains/XcodeDefault.xctoolc hain/usr/bin 안의 clang과 clang++ • CFLAGS, CXXFLAGS – -march=armv7-a – -mfloat-abi=softfp – -mfpu=neon – --sysroot=<NDK_ROOT>/platforms/android-<version>/arch-arm • LD, AS, AR, LIBTOOL, STRIP, RANLIB 설정 불필요 • --libdir <NDK_ROOT>/platforms/android-<version>/arch-arm/ usr/lib configure
  • 47.
    C++ → Lua예제 // 자동 생성된 클래스 등록 코드에 의한 실제 내부 작동 RegisterNativeClass<Foo>(); // 클래스를 lua table로 생성 lua_createtable( “Foo” ); RegisterNativeClassVariable<Foo,int>( “variable”, offsetof(Foo, variable) ); // lua table에 getter/setter 멤버 함수들 등록 lua_pushcclosure( “Get_variable”, &NativeGetInt ); lua_pushcclosure( “Set_variable”, &NativeSetInt ); RegisterNativeClassMethod<Foo,int,int,std::string>( “DoSomething”, &Foo::DoSomething ); // lua table에 멤버 함수 호출자 등록 lua_pushcclosure( “DoSomething”, &Foo_DoSomething ); // 자동 생성된 lua용 인터페이스 코드 - 주석 또는 Lua Checker 용도 외에는 필요 없음 Foo = { Get_variable = function(), Set_variable = function( int_value ), DoSomething = function( int_arg1, string_arg2 ) } 명시적 accessor 대신 __index, __newindex로 구현 가능
  • 48.
    Lua → C++예제 // lua 소스코드 Foo = { variable = 0, int_DoSomething = function( int_arg1, string_arg2 ) … end // 자동 생성된 C++용 인터페이스 코드 } class Foo { int Get_variable() { return lua_tointeger( “variable” ); } void Set_variable( int value ) { lua_pushinteger( “variable”, value ); } int DoSomething( int arg1, std::string arg2 ) { lua_pushinteger( arg1 ); lua_pushstring( arg2 ); lua_pcall( “DoSomething” ); return lua_tointeger( STACK_TOP ); } };