컴파일
C++ 프로젝트 전체에 /clr 컴파일 옵션을 주지 않고도 파일(.cpp) 별로 컴파일 옵션을 설정하는 것이 가능하다.
/clr 옵션은 ‘/Yu: 미리 컴파일된 헤더 사용’, ‘/Gy: 함수 수준 링크 사용’ 등의 몇몇 컴파일 옵션과 호환되지 않으므로 이전보다 빌드 속도가 떨어진다.
Mixed-mode로 작성된 C++/CLI 참조 문제
다른 CLR 언어에서 참조하고 싶다면 반드시 DLL로 빌드하라.
C++/CLI로 Mixed-mode로 실행파일(.exe)를 작성하면, C# 코드가 해당 실행파일이 제공하는 관리되는 자원을 사용할 수 없다. C# 프로젝트에서 해당 실행파일을 참조로 삼아도 기껏해야 런타임 오류가 난다.
처리되지 않은 예외: System.IO.FileLoadException: 픽스업이 있는 확인할 수 없는 실행 파일을 로드하려고 했습니다(섹션이 3개 이상인 IAT 또는 TLS 섹션). (예외가 발생한 HRESULT: 0x80131019)
error RA0000 : Attempt to load an unverifiable executable with fixups (IAT with more than 2 sections or a TLS section.) (Exception from HRESULT: 0x80131019)
해당 실행파일을 DLL로 다시 컴파일해서 참조하면 아무런 문제가 없다. 재미있는 것은 Reflector와 같은 도구를 사용하면 C++/CLI로 작성된 관리되는 자원을 확인할 수 있다는 점이다. 이 문제를 명확히 설명한 자료는 찾기 어려웠다. 컴파일러가 코드를 최적화하면서 이런 문제가 발생한다는 사람도 있었지만, 어디까지 믿어야 할지 알 수 없는 노릇이다.
이 골치 아픈 문제를 회피하는 가장 쉬운 방법은 역시 실행파일엔 애플리케이션을 구동하는 데 필요한 최소한의 코드만 두고, 나머지 자원을 별도의 라이브러리로 빼내는 것이 아닐까?
혼합된 메써드 시그니처는 보이지 않는다.
ref class ManagedObj { public: void ManagedSayHello(System::String msg) { ...... } void NativeSayHello(std::string msg) { ...... } };
이 경우에 C#로 작성한 코드는 NativeSayHello를 제외하고 ManagedSayHello만 사용할 수 있다.
Visual Studio 2008 ‘Orcas’
마샬링 라이브러리를 사용하여 작업 간소화
템플릿 라이브러리 형태로 마샬링 루틴을 제공한다. 기존에는 .NET Framework의 라이브러리를 호출하거나, Orcas가 제공하는 것과 유사한 템플릿 라이브러리를 직접 만들어서 사용했다.
#include <msclr/marshal.h> void myfunc (String^ s) { msclr::interop::marshal_context ctx; char *s2 = ctx.marshal_as<char*> (s); //... }
CLR 형식에서 STL/CLR 사용
Some Notes about Mixed Types 중 Why native native classes, including PODs, should not be on the garbage collected heap를 읽어보면, 이런 말이 있다.
For the most part, all existing STL algorithms can be made to work for managed code by simply replacing & with %. If managed classes exposed iterators, the STL algorithms can work.
기존 C++/CLI에서도 STL을 활용할 수는 있었지만, Orcas에선 더 쉬워졌다고 보면 된다.
#include <cliext/hash_map> void myfunc () { cliext::hash_map<Int32, String^> m; m.insert (cliext::make_pair(5, L"five")); cliext::hash_map<Int32, String^>::iterator i = m.find(5); Console::WriteLine("map[{0}] == {1}", i->first, i->second); }
사실 Stan Lippman이 STL.NET Primer을 통해 Visual Studio 2005에 포함된다고 소개했던 STL.NET이 이제서야 STL/CLR이란 이름으로 포함되게 된 것이다.
참고 문헌
-
STL.NET Primer. 변역된 글을 읽고 싶다면, Anyflow.net으로 가서 키워드 ‘STL’로 검색하면 된다.
% (Tracking Reference)
C++의 참조(reference)와 같은 역할을 한다. 예제를 보면 이해하기 쉽다.
ref class MyClass { public: int i; }; int main() { MyClass ^ x = gcnew MyClass; MyClass ^ y = x; // tracking reference handle to reference object }
C# 프로그래머가 착각하기 딱 좋은 코드다. C#이라면 x와 y가 동일한 인스턴스를 가리킬 것이다. 하지만 C++/CLI는 C++의 언어적 특성을 따른다. MyClass ^ y = x; 는 순수 C++로 표현하자면, MyClass y = x 정도가 된다. 다시 말해 복사생성자가 호출된다. 그러니 y와 x는 서로 다른 인스턴스를 가리킨다.
C#에서의 MyClass y = x 효과를 내려면 %가 필요하다.
int main() { MyClass ^ x = gcnew MyClass; MyClass ^% y = x; // tracking reference handle to reference object }
디버거로 확인해보면 알겠지만 y와 x가 동일한 주소를 가리킨다.