성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Roll A Lisp In C - Reading ; https...
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - 바이너리 출력 디렉터리와 연관된 csproj 설정</h1> <p> C# Console 응용 프로그램을 기본 생성하면 다음과 같은 구성을 갖고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> </Project> </pre> <br /> 빌드하면, "프로젝트" 파일이 있는 위치를 기준으로 출력 디렉터리가 구성돼 결과물이 아래와 같이 모입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp\ConsoleApp1\ConsoleApp1\<span style='color: blue; font-weight: bold'>bin\Debug\net7.0</span>\ConsoleApp1.dll </pre> <br /> 이 상태에서 "net7.0"은 csproj의 TargetFramework에 지정된,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <TargetFramework><span style='color: blue; font-weight: bold'>net7.0</span></TargetFramework> </pre> <br /> 값을 따르는데요, 만약 이 경로를 없애고 싶다면 AppendTargetFrameworkToOutputPath 옵션을 false로 설정하시면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <TargetFramework>net7.0</TargetFramework> <span style='color: blue; font-weight: bold'><AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath></span> </pre> <br /> 이후 빌드하면 출력 디렉터리가 다음과 같이 바뀝니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp\ConsoleApp1\ConsoleApp1\<span style='color: blue; font-weight: bold'>bin\Debug</span>\ConsoleApp1.dll </pre> <br /> <hr style='width: 50%' /><br /> <br /> 자, 그럼 여기서 bin 디렉터리도 지워볼까요? ^^ 이를 위해 BaseOutputPath를 지정할 수 있습니다. (이 값은 비주얼 스튜디오의 프로젝트 속성창을 통해서도 설정할 수 있습니다.)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <TargetFramework>net7.0</TargetFramework> <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <span style='color: blue; font-weight: bold'><BaseOutputPath>.\</BaseOutputPath></span> </pre> <br /> 빌드하면 다음과 같이 출력 디렉터리가 생기는데요,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp\ConsoleApp1\ConsoleApp1\<span style='color: blue; font-weight: bold'>Debug</span>\ConsoleApp1.dll </pre> <br /> 대신 부작용이 하나 있습니다. 빌드하자마자 현재 프로젝트 경로의 하위에 Debug 폴더가 생성되고 Visual Studio의 Solution Explorer에는 다음과 같이 "Debug" 디렉터리가 나오게 됩니다.<br /> <br /> <img alt='output_path_option_1.png' src='/SysWebRes/bbs/output_path_option_1.png' /><br /> <br /> 그래서 이 디렉터리를 없애기 위해 별도의 ItemGroup을 포함시켜야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <span style='color: blue; font-weight: bold'><BaseOutputPath>.\</BaseOutputPath></span> </PropertyGroup> <span style='color: blue; font-weight: bold'><ItemGroup> <Compile Remove="Debug\**" /> <EmbeddedResource Remove="Debug\**" /> <None Remove="Debug\**" /> </ItemGroup></span> </Project> </pre> <br /> <hr style='width: 50%' /><br /> <br /> 혹시 "Debug"도 제거할 수 있을까요? 아쉽게도 제가 아는 범위 내에서는 그런 옵션은 없습니다. 단지, 아예 Output 경로를 완전히 새롭게 지정하는 방법이 있는데요, 바로 OutputPath를 지정하는 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <span style='color: blue; font-weight: bold'><OutputPath>.\</OutputPath></span> </PropertyGroup> </Project> </pre> <br /> 이렇게 되면 현재 프로젝트와 동일한 경로에 출력 파일들이 함께 놓이므로,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp\ConsoleApp1\ConsoleApp1> <span style='color: blue; font-weight: bold'>dir /b</span> ConsoleApp1.csproj <span style='color: blue; font-weight: bold'>ConsoleApp1.deps.json ConsoleApp1.dll ConsoleApp1.exe ConsoleApp1.pdb ConsoleApp1.runtimeconfig.json</span> obj Program.cs </pre> <br /> 번잡해지는 단점이 있습니다. 물론, 사실 저런 식으로 쓰는 경우는 거의 없을 것입니다. 그보다는 절대 경로를 지정해 출력하는 경우 편리하게 사용할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <OutputPath><span style='color: blue; font-weight: bold'>c:\tools</span></OutputPath> </pre> <br /> 저렇게 되면 bin 디렉터리와 Debug/Release와 연관된 디렉터리 설정을 모두 무시하게 되는데요, 만약 그것을 살리고 싶다면 관련 속성을 추가해 제어할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // c:\temp\bin\Debug 또는 c:\temp\bin\Release <OutputPath>c:\temp\bin\<span style='color: blue; font-weight: bold'>$(Configuration)</span></OutputPath> </pre> <br /> <hr style='width: 50%' /><br /> <br /> 이 외에도, 아래의 문서를 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > How to: Change the build output directory ; <a target='tab' href='https://learn.microsoft.com/en-us/visualstudio/ide/how-to-change-the-build-output-directory'>https://learn.microsoft.com/en-us/visualstudio/ide/how-to-change-the-build-output-directory</a> </pre> <br /> AppendRuntimeIdentifierToOutputPath, UseCommonOutputDirectory, IntermediateOutputPath 3가지 옵션이 나옵니다. 하나씩 알아볼까요? ^^<br /> <br /> 우선 AppendRuntimeIdentifierToOutputPath 옵션 먼저 보겠습니다. 실습을 위해 기본 C# Console 응용 프로그램에 다음이 옵션을 추가합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <span style='color: blue; font-weight: bold'><RuntimeIdentifier>linux-x64</RuntimeIdentifier></span> </PropertyGroup> </Project> </pre> <br /> 이후 해당 프로젝트를 빌드하면 "bin/Debug/net7.0" 뿐만 아니라 추가로 "linux-x64"가 출력 디렉터리에 따라붙게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp\ConsoleApp1\ConsoleApp1\<span style='color: blue; font-weight: bold'>bin\Debug\net7.0\linux-x64</span>\ConsoleApp1.dll </pre> <br /> 바로 저 "linux-x64", 즉 RuntimeIdentifier 옵션이 지정돼 붙게 되는 경로를 무시할 수 있는 옵션이 바로,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <RuntimeIdentifier>linux-x64</RuntimeIdentifier> <span style='color: blue; font-weight: bold'><AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath></span> </pre> <br /> AppendRuntimeIdentifierToOutputPath가 되겠습니다. 따라서 위의 설정에서 빌드를 하게 되면 linux-x64 디렉터리가 없어집니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp\ConsoleApp1\ConsoleApp1\<span style='color: blue; font-weight: bold'>bin\Debug\net7.0</span>\ConsoleApp1.dll </pre> <br /> <hr style='width: 50%' /><br /> <br /> UseCommonOutputDirectory는 이름이 다소 혼란스럽습니다. 그냥 그 옵션만 설정하면 솔루션 파일이 위치한 디렉터리를 기준으로 포함된 프로젝트들의 출력을 모두 모아줄 것 같은데, 사실은 그런 기능과 아무런 상관이 없습니다.<br /> <br /> 이 옵션이 하는 역할은, 단지 빌드 시스템에게 해당 프로젝트들이 출력 디렉터리를 공유할 것이라고 알려주는 것에 불과합니다. 그렇다면, 왜 이게 필요한 것일까요?<br /> <br /> 예를 들어, 다음과 같은 식으로 솔루션/프로젝트를 구성하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .\ConsoleApp1.sln \ConsoleApp1\ConsoleApp1.csproj \ClassLibrary1\ClassLibrary1.csproj </pre> <br /> 이때 ConsoleApp1 프로젝트가 ClassLibrary1 프로젝트를 참조한다고 가정해 보겠습니다. 이 상태에서 Console 프로젝트를 빌드하면 당연히 출력 디렉터리에 라이브러리 DLL이 함께 출력이 됩니다.<br /> <br /> 하지만, 만약에 이런 상태에서 2개의 프로젝트가 아래처럼 같은 Output 디렉터리로 출력하라고 지정했다면 어떻게 될까요?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <span style='color: blue; font-weight: bold'><AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <OutputPath>c:\temp\$(Configuration)</OutputPath></span> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj" /> </ItemGroup> </Project> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <span style='color: blue; font-weight: bold'><AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <OutputPath>c:\temp\$(Configuration)</OutputPath></span> </PropertyGroup> </Project> </pre> <br /> 그럼 2개의 프로젝트 빌드 결과가 c:\temp\Debug 디렉터리에 모이게 되는데요, 문제는 이런 상황에서 비주얼 스튜디오는 ClassLibrary1 프로젝트가 빌드됐을 때 온전히 c:\temp\Debug 디렉터리에 출력이 모였음에도 불구하고, 이어서 ConsoleApp1 프로젝트가 빌드되면서 다시 프로젝트를 c:\temp\Debug로 복사하는 시도를 한다는 것입니다.<br /> <br /> 사실 필요 없는 절차이지만, 게다가 워낙 복사 과정이 빠르기 때문에 굳이 신경 쓰지 않아도 되지만 이런 과정을 생략하도록 지정할 수 있는 옵션이 UseCommonOutputDirectory입니다. 이 옵션을 2개의 프로젝트 모두에 설정해 주면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <UseCommonOutputDirectory>true</UseCommonOutputDirectory> </pre> <br /> 이후 빌드에서는 ConsoleApp1 프로젝트가 ClassLibrary1 프로젝트의 출력 결과물을 복사해 오는 과정을 (빌드 시스템이 알고 있으므로) 생략하게 됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 마지막으로 IntermediateOutputPath 옵션은 직접적인 출력 디렉터리와는 상관없고 단지 중간 출력 결과물의 생성 경로를 바꿀 수 있습니다. 이 옵션이 없다면 ./obj 디렉터리 하위에 Debug(또는 Release) 디렉터리가 생겨 중간 출력물을 그곳에 생성하는데, IntermediateOutputPath를 지정하게 되면 Debug(또는 Release) 디렉터리를 없애고 새롭게 설정하는 것이 가능합니다.<br /> <br /> <a target='tab' href='https://learn.microsoft.com/en-us/visualstudio/ide/how-to-change-the-build-output-directory'>문서</a>에 보면, <br /> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> Visual Studio still creates the obj folder under the project folder when you build, but it's empty. <br /> </div><br /> <br /> IntermediateOutputPath를 지정한 경우, ./obj 디렉터리는 (비어 있지만) 그래도 생성된다고 합니다. 그런데, .NET 7 환경에서 테스트하면 obj 디렉터리에는 다음의 파일들이 출력됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp\ConsoleApp1\ConsoleApp1\obj> <span style='color: blue; font-weight: bold'>dir /b</span> ConsoleApp1.csproj.nuget.dgspec.json ConsoleApp1.csproj.nuget.g.props ConsoleApp1.csproj.nuget.g.targets project.assets.json project.nuget.cache </pre> <br /> 즉, 비어 있지도 않으므로 현재로서는 어떻게 해도 저 ./obj 디렉터리를 옵션으로 지울 수 있는 방법은 없습니다. 단지, 문서에도 언급하듯이 PostBuildEvent를 설정해 삭제하는 식으로 우회할 수는 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <PostBuildEvent>rd "$(MSBuildProjectDirectory)\obj" /s /q</PostBuildEvent> </pre> <br /> 참고로, ".NET SDK 6.0.200"부터는 <a target='tab' href='https://www.sysnet.pe.kr/2/0/11520'>참조 어셈블리</a>도 IntermediateOutputPath 하위에 복사되도록 바뀌었습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Write reference assemblies to intermediate output ; <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/6.0/write-reference-assemblies-to-obj'>https://learn.microsoft.com/en-us/dotnet/core/compatibility/sdk/6.0/write-reference-assemblies-to-obj</a> </pre> <br /> 그래서 ./obj/Debug 하위에 ref, refint 디렉터리가 함께 생성되고 그 안에 Reference assembly가 생성됩니다. 이유는 알 수 없지만, ref와 refint에 포함된 참조 어셈블리는 동일한 파일인데요, ref 디렉터리는 .NET 5.0 이하에서 쓰던 디렉터리 이름인 반면 "refint"는 IntermediateOutputPath 경로로 바뀌면서 변경된 이름입니다.<br /> <br /> 참조 어셈블리가 굳이 필요하지 않다면 ProduceReferenceAssembly를 설정해,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <ProduceReferenceAssembly>false</ProduceReferenceAssembly> </pre> <br /> ref, refint 디렉터리 모두 없앨 수 있습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 개인적으로 위의 내용에서 한 가지 사용처를 하나 발견했습니다. 제 경우에, ^^ 보통 블로그를 쓸 때, 백업을 위해 dropbox 디렉터리에서 프로젝트를 생성하게 되는데요, 문제는 빌드 때마다 쓸데없는 파일들이 모두 동기화된다는 점입니다.<br /> <br /> 그래서, 앞으로는 다음과 같이 구성해 두려고 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <span style='color: blue; font-weight: bold'><AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <BaseOutputPath>c:\temp\prj\$(MSBuildProjectName)</BaseOutputPath> <IntermediateOutputPath>$(BaseOutputPath)\obj</IntermediateOutputPath> <PostBuildEvent>rd "$(MSBuildProjectDirectory)\obj" /s /q</PostBuildEvent></span> </PropertyGroup> </Project> </pre> <br /> 위의 설정으로 빌드하는 경우 /obj 디렉터리는 삭제되고, /bin 디렉터리는 c:\temp\prj 디렉터리로 모이게 됩니다. 따라서 프로젝트 디렉터리에는 다음과 같이 최소한의 파일만 남게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp\ConsoleApp1\ConsoleApp1> <span style='color: blue; font-weight: bold'>dir /b</span> ConsoleApp1.csproj Program.cs </pre> <br /> 깔끔하죠? ^^ 이제 해당 디렉터리만 바로 압축해 블로그의 글에 첨부하면 됩니다.<br /> <br /> 끝으로, 위의 구성으로 "<a target='tab' href='https://www.sysnet.pe.kr/2/0/13335#export_template'>프로젝트 템플릿</a>"을 하나 만들어 재활용하면 되겠습니다. ^^<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1369
(왼쪽의 숫자를 입력해야 합니다.)