C++/CLI 프로젝트를 도입한 이래로 괴상한 문제에 시달리게 됐다. 특히 멀쩡한 줄 알았던 빌드가 실제론 엄청난 오류에 시달리고 있다는 사실을 뒤늦게 깨닫는 바람에 문제의 원인을 파악해서 고치는 데 시간이 꽤 걸렸다. 빌드 서버를 잘못 설정하는 바람에 빌드가 깨졌는데도, ‘잘 되고 있으니 걱정말라’는 메시지를 전달받고 있었던 탓이다.
끝까지 속을 태웠던 문제는 유독 x64 빌드 때에만 발생했다.
c:\windows\microsoft.net\framework\v2.0.50727\system.dll (,): warning C4945: ‘DescriptionAttribute’ : cannot import symbol from ‘c:\windows\microsoft.net\framework\v2.0.50727\system.dll’: as ‘System::ComponentModel::DescriptionAttribute’ has already been imported from another assembly ‘System’
WIN32 빌드 때는 전혀 발생하지 않는 문제이고, x64 빌드일지라도 Visual Studio를 통해 빌드하면 마찬가지로 문제가 없다. 하지만 64비트 MSBuild 바이너리를 통해 비주얼 스튜디오 솔루션 파일(.sln)을 빌드하려 하면 저런 오류가 나온다.
왜 이런 차이가 발생하는지는 알 수 없다. 단지 MSBuild의 버그가 아닐까 추측해볼 뿐이다. 그렇다고 문제를 방치할 수도 없어 별 수 없이 오류 메시지를 보고 해결책을 모색해봤다.
결국 문제를 해결했는데, 방법은 아주 간단하다. 해당 C++/CLI 프로젝트에서 System.dll에 대한 참조를 없애면 그만이다. 이 문제는 각 프로젝트의 참조가 다음과 같이 구성되어 있을 때 발생한다.
CommonLibrary : C# 프로젝트 - System.dll MyApp : C++/CLI 프로젝트 - System.dll - CommonLibrary.dll
대시(-) 옆에 붙은 파일은 해당 프로젝트가 참조하는 어셈블리를 말한다.
MyApp가 C# 프로젝트였다면 이런 구성이 올바를 뿐더러, System.dll 참조를 뺀다면 되려 컴파일 자체가 안 될지도 모른다. C++/CLI 프로젝트라도 비주얼 스튜디오로 빌드하면 이런 구성이 맞다. 하지만 MSBuild로 MyApp 프로젝트를 빌드하려면 System.dll에 대한 참조는 빼야한다. MyApp가 참조하는 CommonLibrary.dll이 이미 System.dll을 참고했기 때문이다. 다행스럽게도 System.dll을 참조 목록에서 빼더라도 비주얼 스튜디오는 아무런 불평도 하지 않는다. 이렇게 하면 비주얼 스튜디오와 MSBuild 모두가 만족한다.
[…] 안타깝게도 MSBuild 바이너리는C++ 프로젝트는 빌드하지 못한다. 단 별도의MSBuild 스크립트를 만들면 방법이 있다. MSBuild엔 <msbuild>란 태스크가 있는데, 여기에 솔루션 파일 이름을 적어주면 대부분 빌드가 된다. 한데 msbuild 태스크는 비주얼 스튜디오 바이너리(devenv.exe)를 호출하지 않고, VCBuild 바이너리를 호출한다. 이는 IDE 종속성을 제거한다는 측면에서 바람직하지만, 안타깝게도 devenv와 VCBuild가 항상 똑같은 방식으로 작동하는 건 아니다. 특히 C++/CLI 기술을 쓰는 경우엔 비주얼 스튜디오로는 빌드가 되던 솔루션을MSBuild로 빌드하려면 실패하는 일이 잦다(참고. https://andromedarabbit.net/cplusplus_cli_and_x64_and_msbuild/). […]