얼그레이 – 빌드 도구

  • Post author:
  • Post category:칼럼
  • Post comments:0 Comments
  • Post last modified:February 8, 2020

Introduction

Earlgrey has now two kinds of build tools.

  • Third-party tools
  • Custom tools

Third-party tools

Build tools developed by other open source communities are now placed in /trunk/vendor path. We are currently using MSBuild Community Tasks to provide extensive functionalities to MSBuild scripts. CruiseControl .NET is also being used to automate build processes and to get rapid feedbacks.

Custom tools

MSBuild.Earlgrey.Tasks

The name of MSBuild Earlgrey.Tasks describes itself. It provides some useful functionalities to MSBuild scripts, just as MSBuild Community Tasks does. Actually, some features of this library are based on MSBuild Community Tasks. Of course, MSBuild.Earlgrey has improved other open source communities\’ efforts.

How to build MSBuild.Earlgrey.Tasks
Very simple way
D:earlgrey> cd trunksrc
D:earlgreytrunksrc> MSBuild_Win32.bat BuildToolsmsbuild-deploy.xml

That\’s it! All the files you need will be put into trunksrcBuildToolsAny CPU-ReleaseMSBuildExtension.

Change deployment directory
D:earlgreytrunksrc> MSBuild_Win32.bat BuildToolsmsbuild-deploy.xml /p:DeploymentDir="D:earlgrey.tasks"

Now, files will be placed in D:earlgrey.tasks.

If you need \’DEBUG\’ version of files
D:earlgreytrunksrc> MSBuild_Win32.bat BuildToolsmsbuild-deploy.xml /p:Configuration=Debug

That\’s it! Isn\’t it easy?

How to Use MSBuild.Earlgrey.Tasks

Every step is described in the following sample code.

<?xml version="1.0" encoding="utf-8" ?>

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <RootDir>$(MSBuildProjectDirectory)</RootDir>
        
        <!-- 
        First thing you need to do is to define $(MSBuildEarlgreyTasksPath),
        which represents deployment directory path of MSBuild.Earlgrey.Tasks. 
        -->
        <MSBuildEarlgreyTasksPath>BuildToolsAny CPU-ReleaseMSBuildExtension</MSBuildEarlgreyTasksPath>
    </PropertyGroup>

    <!-- Second, import MSBuild.Earlgrey.Tasks. -->
    <Import Project="$(MSBuildEarlgreyTasksPath)MSBuild.Earlgrey.Tasks.Targets"/>

    <!-- Usage example of MSBuild.Earlgrey.Tasks.IO.BetterRoboCopy -->
    <Target Name="RoboCopyUsageExample">
        <BetterRoboCopy
            SourceFolder="$(RootDir)MSBuildExtension"
            DestinationFolder="$(RootDir)"
            SourceFiles="FILE_NOT_EXISTS.txt"
        />
        
        <!-- You can also use the full name of a task -->
        <MSBuild.Earlgrey.Tasks.IO.BetterRoboCopy
            SourceFolder="$(RootDir)MSBuildExtension"
            DestinationFolder="$(RootDir)"
            SourceFiles="FILE_NOT_EXISTS.txt"
        />
    </Target>
</Project>

Earlgrey.UnityBuild

This library is still under development, and not ready to be released.

UnityBuild 란? 1
UnitBuild 사용법
빌드하기

우선 Earlgrey.BuildTools.sln 에 포함된 UnityBuild.ConsoleUi 프로젝트를 빌드한다. 빌드하는 법 장을 참고하면 빌드하는 데 문제는 없을 것이다. 이렇게 빌드하고 나면 출력 폴더에 UnityBuild.ConsoleUi.exe 바이너리 파일이 생성된다. 이 파일을 명령 줄에서 실행하면 기본적인 사용법이 화면에 출력되니 참고로 삼는다.

C:WorkspacetrunksrcBuildToolsAny CPU-Debugbin>UnityBuild.ConsoleUi.exe
How to use!
 -i, --input (Required)
   Solution file path.
 -e, --exclude (Not Required)
   Visual C++ project names you want to exclude. Separated by a ';'. For instanc
e, -e"Earlgrey";"Earlgrey.Test"
 -c, --copy (Not Required)
   Copy the solution/projects and use them.
 -o, --optimization (Not Required)
   Possible values are 'Normal' and 'Best'.
 -v, --verbose (Not Required)
   Print details during execution.

C:>
솔루션 변환하기

명령 창에 나타난 주요 옵션을 살펴보자. 그러나 그 전에 변환할 솔루션 파일(.sln)과 그 솔루션 파일에 종속된 프로젝트 파일(.vcproj 등)을 백업해둔다. UnityBuild.ConsoleUi.exe는 솔루션 파일과 Visual C++ 프로젝트 파일을 분석하고 변환한다. 그러므로 원본 파일이 필요하다면 백업부터 받아두는 편이 안전하다. 물론 구글 코드 저장소에서 Checkout 한 경우라면 Revert 가능하므로 크게 걱정할 필요는 없다.

-i 는 UnityBuild.ConsoleUi.exe 의 가장 중요한 필수 옵션이다. -i 스위치는 변환할 솔루션 파일을 입력 받을 때 사용한다.

C:WorkspacetrunksrcBuildToolsAny CPU-Debugbin>UnityBuild.ConsoleUi.exe -i "......Earlgrey.sln"
working ...
done!

C:>

위와 같이 Earlgrey.sln 파일을 대상 파일로 지정한 후 trunk 폴더를 살펴보면 다음과 같은 모습일 것이다(TortoiseSVN이 설치된 상태라는 가정에서).

UnityBuild.ConsoleUi.exe

가만 살펴보면 Earlgrey.sln 파일과 이 솔루션 파일에 포함된 Visual C++ 프로젝트 파일(.vcproj)만 변환됐음을 짐작할 수 있다. Earlgrey.sln 에는 C# 프로젝트(.csproj)도 포함됐다. 그러나 UnityBuild는 C++ 컴파일러에만 적용되는 이론이기 때문에 다른 프로그래밍 언어와는 무관하다. 더군다나 C# 과 같은 VM(Virtual Machine) 기반의 언어는 일반적으로 빌드 속도가 C++에 비해 무지하게 빠르기 때문에 UnityBuild 같은 괜한 수고는 들이지 않아도 된다.

-e 스위치는 대상 솔루션에 포함된 프로젝트 중에 변환하고 싶지 않은 Visual C++ 프로젝트를 지정할 때 쓴다. Earlgrey.sln 에는 외부 프로젝트가 몇 개 포함되었다. 대표적인 것인 gtest(Google Test)와 StackWalker_VC9(StackWalker)이다. 보통 외부 프로젝트는 함부로 건드리지 않고 그대로 놔두는 게 좋은데 이런 경우라면 -e 스위치가 도움이 된다.

C:WorkspacetrunksrcBuildToolsAny CPU-Debugbin>UnityBuild.ConsoleUi.exe -i "......Earlgrey.sln" -e "gtest;StackWalker_VC9"
working ...
done!

C:>

이렇게 -e 스위치로 vendor 프로젝트에 속한 두 프로젝트를 UnityBuild에서 제외해본다. 변환이 완료된 후에 vendor 폴더와 src 폴더을 살펴보면 아래의 스크린샷에서 보듯 -e 스위치로 지정한 프로젝트는 바뀐 게 없이 그대로이다.

UnityBuild.ConsoleUi.exe

-c 스위치가 하는 일은 단순하다. 이 스위치를 주면 Earlgrey.sln 과 솔루션에 포함된 모든 프로젝트를 복사해 새 솔루션 파일과 프로젝트 파일을 만든다. 그러고 나서 복사본을 이용해 UnityBuild 를 수행한다. 원본 파일을 그대로 두고 싶을 때 유용하다.

-o 스위치는 최적화 옵션이다. 사용 가능한 옵션 값과 그 옵션 값이 수행하는 작업 내용은 언제 어떻게 변할지 모른다. 그러므로 자세한 설명은 하지 않기로 한다. 직접 부딪히며 그 차이를 알아보기를 권한다.

# 요약
스위치 필수 여부 설명
-i 필수 -iC:Earlgrey.sln 변환할 솔루션 파일의 경로를 지정한다.
-e 미필수 -egtest;Earlgrey.Tests UnityBuild 에서 제외할 프로젝트 목록을 지정한다.
-c 미필수 -c -i 스위치로 지정한 솔루션 파일과 그 종속 프로젝트를 복사한다. 그러고 나서 복사본을 이용해 UnityBuild 를 수행한다.
-o 미필수 -oNormal 최적화 정도를 결정한다.
솔루션 열기

변환을 마쳤으면 Earlgrey.sln 파일을 비주얼 스튜디오에서 연다. 먼저 구성 관리자를 열어서 UnityBuild 용 구성 플랫폼 (Configuration|Platform) 값이 생성되었는지 확인한다.

UnityBuild

이 스크린샷에선 Release|x64 빌드에 대응 값인 Release-UnityBuild|x64 빌드의 구성 값을 보여준다. -e 스위치로 제외한 gtest 와 StackWalker_VC9 은 구성 플랫폼 값이 원래 그대로이다. 그 외의 .vcproj 는 원래 구성 플랫폼 값에 -UnityBuild 가 붙은 새로운 구성 값을 갖게 됐다. 이 스크린샷에선 보이지 않지만 원래 구성인 Release|x64 는 전혀 변한 것 없이 그대로 보존된다.

UnityBuild

이제 솔루션 탐색기에서 소스 파일(.cpp)이 어떻게 변했나 확인한다. 기존 소스 파일엔 붉은 색 아이콘이 붙었는데 이는 빌드에서 제외됨을 뜻한다. UnityBuild용 소스 파일(UnityBuild-00010.cpp)만 빌드하는데, 이 파일을 열면 System 필터에 포함된 모든 소스 파일을 포함한다. 오해의 여지가 있어 부연하자면 소스 파일을 묶을 때 필터만 기준으로 삼아 묶지는 않는다. 세부 구현은 언제나 변하기 마련이라 여기선 자세히 다루지 않겠다.

기존 소스 파일은 빌드에서 제외하는데 예외도 있다. 미리 컴파일된 헤더(보통 stdafx.h)를 생성하는 소스 파일(컴파일 옵션 /Yc)은 그대로 둔다. Earlgrey.sln을 기준으로 성능을 측정해보니 UnityBuild를 적용하지 않고 미리 컴파일된 헤더는 적용한 경우가 UnitBuild를 적용하고 미리 컴파일된 헤더를 적용하지 않은 경우보다 빌드가 빨랐다. 물론 둘 다 적용했을 때가 가장 빨랐기 때문에 UnityBuild 는 미리 컴파일된 헤더와 관련된 옵션은 바꾸지 않고 그대로 승계 받는다.

솔루션, 프로젝트, 그리고 소스 파일이 어떻게 변환됐는지 간략하게 살펴보았다. 이제 할 일은 실제로 빌드를 돌리는 것 뿐.

원하는 구성 플랫폼을 선택하고 실행하면 위의 스크린샷에서 보는 바와 같이 빌드가 성공한다.

빌드가 실패할 때

UnitBuild 로 변환한 후에 빌드가 실패할 때가 있다. 레가시 코드라면 99%는 실패한다. 이렇게 빌드가 실패하는 것은 대체로

  • 원래 문제가 있는 코드였으나 운 좋게 발견되지 않았거나
  • 하드코딩된 프로젝트 구성 값이 있거나
  • UnitBuild 에서 아직 지원하지 않는 구성을 취하는

등의 이유 때문이다. 역사가 오래된 레가시 코드일수록 코드 베이스의 규모가 크고 돌아가기 때문에 미처 잠재적인 문제로 인식하지 못한 채 여기저기서 반복해 사용하는 코드가 많이 때문에 수천 개의 오류를 내뱉기도 한다. 그나마 다행이라면 대부분의 오류가 동일한 이유로 발생하기 때문에 하나만 분석해 해결하면 수십 개가 따라 해결된다는 것이다.

# error C2011
\'identifier\' : \'type\' 형식 재정의
\'identifier\' : \'type\' type redefinition 

헤더 파일의 최상단에 #pragma once이 붙어있나 확인한다.

# error C4430
형식 지정자가 없습니다. int로 가정합니다. 참고: C++에서는 기본 int를 지원하지 않습니다.
missing type specifier - int assumed. Note: C++ does not support default-int 

형식 지정자가 없다는 곳으로 가면 분명히 사용자 정의 타입으로 선언됐을 것이다. 해당 타입을 선언한 헤더 파일을 찾아서 소스 파일에 추가한다.

참고 자료
송창규, “unity build로 빌드타임 반토막내기”

2010년 5월 넥슨 개발자 컨퍼런스에서 발표한 자료이다. 실증적인 실험 자료를 내세워 UnitBuild의 도입 필요성을 제시하고 실제 적용 방법까지 간략하게 보여준다. 그럼에도 딱딱하지 않고 위트가 넘친다. NDC 현장에 없었다는 사실이 안타깝게 느껴질 정도이다.

The Magic of Unity Builds

Unity Build를 언급하는 웹 문서 대부분이 참고 문헌으로 내세우는 자료이다. 영어로 제법 길게 쓴 글이라 따라가기 힘들 수도 있지만 따라하기 식 동영상 자료가 있기 때문에 그 개념과 적용 방법을 어렵지 않게 습득 가능하다.


  1. UnityBuild의 이론을 정리해서 써야 한다. 
Author Details
Kubernetes, DevSecOps, AWS, 클라우드 보안, 클라우드 비용관리, SaaS 의 활용과 내재화 등 소프트웨어 개발 전반에 도움이 필요하다면 도움을 요청하세요. 지인이라면 가볍게 도와드리겠습니다. 전문적인 도움이 필요하다면 저의 현업에 방해가 되지 않는 선에서 협의가능합니다.
0 0 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments