정의 상수를 이용한 크로스 플랫폼 코드 작성하기

현재는 Microsoft .NET Framework와 Ximian (Novell) Mono Framework 두 종류로 구분된 플랫폼이 존재합니다. 이 두 플랫폼을 모두 지원할 수 있는 방법은 Operating System의 정보와 Framework의 정보를 코드 상으로 구분하여 처리하거나 (중계 언어의 호환성이 있기에 가능합니다.) 정의 상수를 이용하는 방법이 있습니다. 저는 개인적으로 중계 언어의 호환성도 좋지만 정의 상수를 활용하는 방법을 개인적으로 선호합니다. 정의 상수라는 표현을 쓰긴 했으나 C와 C++에서 지원하던 매크로의 의미보다 “축소” 되었지만 사용 용도는 비슷하게 쓰일 수 있다고 봅니다.


C와 C++에서 이와 같이 크로스 플랫폼을 지원하기 위하여 사용하는 정의 상수는 사실 “아무런 값도 포함하지 않는” 비어있는 정의 상수입니다. (0 또는 NULL이 아닙니다!) 이 정의 상수를 MAKEFILE에서 지정하여 컴파일러에게 전달하도록 스크립트를 작성하고, 컴파일러는 소스 코드 상에서 정의된 상수에 관한 코드만을 선택적으로 컴파일합니다. 이것을 응용하여 종류가 매우 다양한 각종 컴파일러와 그 컴파일러 시리즈 각각의 버전을 구분하고 운영 체제의 종류와 그 운영 체제 시리즈 각각의 버전에 호환되는 바이너리를 작성할 수 있습니다. 대표적으로 Mono와 Rotor, 그리고 wxWindows가 그에 해당되는 좋은 예라고 할 수 있습니다. C#에서도 이와 마찬가지의 용도로 정의 상수를 사용할 수 있습니다.


C# 컴파일러에는 다음과 같은 옵션이 있습니다.


/define:arg1;arg2;arg3;~~~;arg[n]


이것은 프로그래밍 코드에 직접 서술하여 정의 상수를 정의하는 #define의 역할을 컴파일러가 대신 수행해줌을 의미합니다. 즉, 여기서 선언한 정의 상수는 “코드” 상에서 비록 선언되어있다고 하지 않을지라도 유효하게 됩니다. 만약 여기서 선언하지 않았다면 적어도 “코드” 상에는 #define으로 선언이 되어있어야 유효한 것입니다. 바로 C# 컴파일러의 이 옵션을 활용하여 크로스 플랫폼 코드를 구현할 수 있을 것입니다.


가령, Microsoft .NET Framework임을 코드에게 알려주고자 한다면 아래와 같이 프로그래머가 식별할 수 있는 정의 상수를 주면 됩니다. (프로그래머가 Microsoft .NET Framework에 해당하는 특정한 기호를 정의하고 사용하므로 어떤 기호를 써도 무방합니다. 하지만 의미는 정확히 구분되어야 합니다.)


csc test.cs /define:MSDOTNET


만약 Rotor Framework, Mono Framework, DotGNU Framework임을 각각 코드에게 알려주고자 한다면 아래와 같이 사용자 정의하면 됩니다.



    csc test.cs /define:MSROTOR


    csc test.cs /define:XIMIANMONO


    csc test.cs /define:GNU


코드 상에서는 아래와 같이 정의하면 선택적으로 컴파일이 이루어질 것입니다.



    public void Selection()


    {


    #ifdef MSDOTNET


    // Microsoft .NET Framework에서 유효한 코드 작성


    #elif MSROTOR


    // Microsoft Rotor Framework에서 유효한 코드 작성


    #elif XIMIANMONO


    // Ximian (Novell) Mono Framework에서 유효한 코드 작성


    #elif GNU


    // DotGNU Framework에서 유효한 코드 작성


    #else


    #error Please specific single valid constants in MSDOTNET, MSROTOR, XIMIANMONO, GNU.


    #endif


    }


위와 같은 방법을 사용하여 각 Framework에서 아직 덜 구현되었거나 Framework의 성격상 지원하지 않는 부분은 가려내어 효율적으로 프로그래밍할 수 있습니다. 그리고 Framework를 구별하는 용도가 아니더라도 Windows에서 사용할 코드, Linux에서 사용할 코드, Unix에서 사용할 코드, Mac OS X에서 사용할 코드로 가려내어 처리할 수도 있습니다.


만약 여러 개의 상수를 정의한다면 세미 콜론을 사용하여 끊어서 입력하시면 됩니다. 그리고 코드 상에서는 중첩해서 정의 상수를 검사해도 좋지만 Short-Circuit (여러 중첩 if문을 인라인에 서술하는 표기법) 형식으로 축약해도 됩니다. 다음의 예를 살펴보지요.



    public void SelectionSecond()


    {


    #if MSDOTNET && MSROTOR


    // Microsoft .NET Framework와 Microsoft Rotor 프레임워크가 공동으로 지원하는 기능을 코딩


    #elif !XIMIANMONO || !GNU


    // Mono 또는 DotGNU 프레임워크 상수가 정의되지 않았을 때의 기능을 코딩


    #endif


    }


이런 형태로 컴파일러 상수를 얼마든지 다룰 수 있습니다.


여기까지가 간단히 컴파일러 상수를 사용하는 방법의 소개였습니다. 이와 같은 방식으로 컴파일할 때에는 가급적 MAKEFILE과 같은 스크립트를 사용하여 컴파일 하는 것이 좋습니다. MAKEFILE이 아니라면 별도의 Compliation 프로그램을 사용하거나 셸 스크립트, 펄, PHP 등의 타 인터프리터 언어를 사용하는 것도 한 방법입니다.


도움이 되셨기를 바랍니다.

댓글 남기기