2014. 1. 29. 15:00

흠....

제목이 좀 이상한데.... 엄밀히 말하자면 닷넷(.NET)을 이용하여 닷넷을 컴파일하는 것을 말합니다.

일종의 컴파일러를 만드는 것을 의미합니다.

다행히도 닷넷에서는 컴파일을 위한 API를 제공하기 때문에 손쉽게 이런 컴파일러를 만들 수 있죠.

 

그럼 이런 컴파일러를 왜 만들어야 하는가?

라는 질문을 하게 되는데.... 

이건 이 포스팅의 마지막에 다루겠습니다.

 

 

1. 'CodeDom'을 이용하기

MSDN에 설명이 잘 나와 있습니다만.... 이 기능은 소스 코드를 빌드하기 위한 기능입니다.

(참고 : MSDN - CodeDOM 사용)

 

그러니 우리는 'CodeDom'을 이용하여 동적으로 코드를 컴파일 할 수 있다는 것입니다.

 

 

2. 샘플 만들기

샘플을 간단하게 윈폼(WinForm)에서 만들겠습니다.

버튼을 누르면 빌드되고 빌드 결과를 텍스트 박스에 출력하는 형식입니다.

 

2-1. 디자인

윈폼(WinForm)프로젝트를 만듭니다.

버튼 한 개와 텍스트 박스를 넣고

텍스트 박스의 'Multilne'속성을 'True'로 바꿉니다.

 

2-2. 코드 넣기

using System.CodeDom.Compiler;

을 해주신 후 버튼의 클릭 이벤트에 다음과 같이 코드를 넣습니다.

public partial class Form1 : Form
{
	public Form1()
	{
		InitializeComponent();
	}


	private void button1_Click(object sender, EventArgs e)
	{

		string sCode = @"
using System;
 
namespace Zmeun.CodeDom
{
class CodeDomTest
{
    static void Main(string[] args)
    {
        System.Console.WriteLine(""Hello World!"");
        System.Console.WriteLine(""Press the Enter key to continue."");
        System.Console.ReadLine();
    }
}
}";

		CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider("c#");
		CompilerParameters compilerParameters = new CompilerParameters();

		//.GenerateExecutable 이값을 'false'로 하면 dll로 출력됨
		compilerParameters.GenerateExecutable = true;
		compilerParameters.OutputAssembly = @"c:\test.exe";
		CompilerResults compilerResults = codeDomProvider.CompileAssemblyFromSource(compilerParameters, sCode);

		if (compilerResults.Errors.Count > 0)
		{
			textBox1.Text = compilerResults.Errors[0].ToString();
		}
		else
		{
			textBox1.Text = "성공";
		}
	}	
}

 

- 12번 줄 : 빌드에 사용할 코드입니다.

문자열을 빌드하는 것이라 문자열로 선언했습니다.

 

- 28번 줄 : 'CodeDomProvider.CreateProvider("c#");'

를 통해 컴파일할 언어를 지정합니다.

닷넷 언어들은 다 쓸 수 있다고 보시면 됩니다.

(참고 : MSDN - CodeDomProvider.CreateProvider 메서드 (String))

 

자세한 내용은 아래 링크dml 63라인부터 보시면 각언어의 프로바인더 정보가 나와있습니다.

(참고 : Microsoft Reference Source - CodeDomCompilationConfiguration)

 

- 32번 줄 : compilerParameters.GenerateExecutable = true;

'GenerateExecutable'이 속성을 'true'로 하면 실행파일(.exe)로 만들어집니다.

'dll'로 만들고 싶으시면 'false'를 합니다.

 

- 33번 줄 : compilerParameters.OutputAssembly = @"c:\test.exe";

출력 위치 및 파일이름입니다.

 

- 34번 줄 : CompilerResults compilerResults = codeDomProvider.CompileAssemblyFromSource(compilerParameters, sCode);

컴파일을 진행합니다.

컴파일하는 동안 에러가 발생하면 'compilerResults.Errors'에 에러가 쌓입니다.

 

 

3. 테스트

이제 테스트해봅시다.

헉!!! 이런 이런...

 

비주얼 스튜디오를 관리자 권한으로 열지 않으면 이런 에러가 발생합니다.

비주얼 스튜디오를 관리자 권한으로 열고 다시 해봅시다.

잘되네요 ㅋ

 

 

마무리

프로젝트의 샘플입니다.

CodeDom.zip
다운로드

 

 

이렇게 우리는 닷넷 컴파일러를 만들었습니다. ㅡ.ㅡ

왜 이런 짓을 하느냐....

 

UI의 재구성이라던가 프로그램의 재구성을 하는데 코어 프로그램을 재컴파일하지 않고 해야 하는 경우가 있습니다.

보안 목적이라던가 사용자나 디자이너의 커스텀을 쉽게 하려는 목적일 수도 있습니다.

이런 경우 사용하는 것이 스크립트(script)입니다.

 

스크립트을 구현하기 위해서 인터프리터(interpreter)를 만들 수도 있고 이미 구현된 스크립트 언어들을 쓸 수도 있습니다.

그리고 보통은 스크립트는 실행마다 컴파일과 비슷한 과정을 거치게 됩니다.

 

그런데 닷넷의 경우 API가 제공되므로 손쉽게 'C#'이나 'VB.Net'같은 닷넷 언어로 만들어진 소스 자체를 스크립트처럼 사용할 수 있다는 장점이 있습니다.

다른 스크립트 언어와 다르게 컴파일하면 '.exe'파일이나 '.dll'로 출력이 됩니다.

덕분에 컴파일만 끝나면 재컴파일 없이도 참조만으로 사용할 수 있기 때문에 실행 속도가 빠릅니다.

(dll을 동적으로 로드하여 사용합니다.)

 

문제는 만들어진 닷넷 스크립트는 코어 프로그램에 맞먹는 동작이 가능하다는 점입니다.

(저도 이 기능을 많이 사용해보지 않아서 잘 모르겠지만 동작을 어느 정도 제한하는 것이 가능할 것으로 예상되네요.) 

장점이자 단점이기도 하죠 ㅎㅎㅎㅎ

 

이 기능을 프로그램 시작 전 런처 프로그램 등을 이용하여 'dll'을 생성한 후 참조할 수도 있고

프로그램실행 중에 생성하여 동적 참조를 할 수도 있습니다.

(참고 : [.Net] DLL을 동적으로 로드하기)

 

다른 테스트 프로그램

DynamicCompile 0.1 - C#, VB.Net, javascript, c++ 컴파일러