MSBuild로 suffix rule 흉내내기
Microsoft VisualStudio 2005 / .net Framework 2.0과 함께 배포되기 시작한 빌드 유틸리티로 MSBuild란 녀석이 있다. MS의 악명높은(…) 커맨드라인 빌드 유틸리티인 nmake를 대체하려는 목적도 포함한 녀석이다.
뭐 이 얘기를 다 하려는 것은 아니고 내가 프로그래밍을 시작했던 *nix환경에는 make라는 command-line 툴로 대부분의 빌드 작업이 이루어진다. 그 기능 중에 하나가 suffix rule이란 건데, 파일 확장자를 보고 일련의 법칙을 따라 자동으로 빌드를 수행하는 녀석이다.
간단하게 C source코드를 컴파일하는 규칙1은 이런 식이다.2
.SUFFIXES : .o .c .s
.c.o :
$(CC) $(CFLAGS) -c $<
.s.o :
$(AS) $(ASFLAGS) -o $@ $<
C compiler와 assembler를 써서 컴파일 하게 된다.3
nmake에서도 되긴하지만(물론 make수준은 아님), nmake자체가 좀 부족한게 많고 MS 에서도 MSBuild를 권장하는지라 — 사실 nmake는 뭔가 제대로 된 빌드툴이 아니다. MSBuild 쯤은 되야 _현대적인 빌드툴_이 아닐까 make따라잡는데 너무 오래 걸렸다 — MSBuild로 비슷한 구현을 해봤다.
MSBuild에는 batching이란 개념이 있는데, 그 중 가장 간단한 구현으로, 다음과 같은게 가능하다.
<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
<ItemGroup>
<TextFile Include='*.py'/>
</ItemGroup>
<Target Name='All'>
<MSBuild Projects='build.xml' Targets='Reverse'/>
</Target>
<Target Name='Reverse' Inputs='@(TextFile)'
Outputs='%(TextFile.Filename).rev'>
<Exec Comand='python reverse.py @(TextFile)'/>
</Target>
</Project>
오늘 회사에서 쓰는 코드 생성기 수정하다 나온 스크립트…의 변형판인데. 입력->출력으로 가면서 .py를 .rev로 바꾸고, 내용이 수정되는 그런 의미로 썼다. .suffix rule이라면 .py .rev 정도의 모양이 될 것이다.
그리고 .suffix rule 처럼 모든 python파일에 대해 동작하도록, ItemGroup과 Include문에 wildcard (*
)를 사용했다.4 그리고 Targets에 Inputs/Outputs attributed을 지정해 주고(batching), 이름이 바뀌는 규칙을 부여했다. 그리곤 실행해주면 끝.
실제 사용되는 빌드 스크립트는 원래 nmake기반이었는데, 경로 관리, 출력파일에 대한 의존성 정리같은게 너무 복잡해져서 (입력보다 출력이 좀 많아서), 아예 python코드에 make의 시간 비교 기능을 넣어버리고 MSBuild의 batching5 으로 Exec task를 만들고, 이걸로 python을 실행하게 했다..
Python 코드에 make의 기능 일부가 중복되서 들어간건, 출력이 더 많아서였는데(덕분에 nmake가 너저분한 코드로), 이걸 python에 살짝 떠 넘기고, suffix 규칙 비슷한걸 흉내내서 상당히 간단하게(위 xml 설정이랑 거의 똑같음) 만들어낼 수 있었다.
MSBuild는 올해 초에야 제대로 쓰기 시작한 거 같은데, 이 작업으로 nmake기반의 빌드는 다 없어진듯… 다만 문서화는 아직 .bat인데, 이건 아직 안복잡(?)하니 천천히 신경써야지;