[.net] Visual Studio에서 빌드 할 때 조건부로 32/64 비트 참조 사용

32/64 비트로 빌드되고 해당 32/64 비트 종속성이있는 프로젝트가 있습니다. 구성을 전환하고 올바른 참조를 사용하고 싶지만 Visual Studio에 아키텍처에 적합한 종속성을 사용하도록 지시하는 방법을 모르겠습니다.

아마도 나는 이것에 대해 잘못된 방식으로 가고 있지만 구성 드롭 다운에서 x86과 x64 사이를 전환 할 수 있고 참조 된 DLL이 올바른 비트가되도록하고 싶습니다.



답변

다음은 .csproj 파일의 수동 버전이 필요한 이전 프로젝트에서 수행 한 작업입니다. 또한 서로 다른 바이너리, 이상적으로는 서로의 형제 및 대상 플랫폼과 동일한 이름에 대한 별도의 디렉토리가 필요합니다.

프로젝트에 단일 플랫폼의 참조를 추가 한 후 텍스트 편집기에서 .csproj를 엽니 다. <ItemGroup>요소 내의 첫 번째 요소 앞에 <Project>다음 코드를 추가하면 실행 (및 빌드)중인 플랫폼을 결정하는 데 도움이됩니다.

<!-- Properties group for Determining 64bit Architecture -->
<PropertyGroup>
  <CurrentPlatform>x86</CurrentPlatform>
  <CurrentPlatform Condition="'$(PROCESSOR_ARCHITECTURE)'=='AMD64' or '$(PROCESSOR_ARCHITEW6432)'=='AMD64'">AMD64</CurrentPlatform>
</PropertyGroup>

그런 다음 플랫폼 별 참조에 대해 다음과 같이 변경합니다.

<ItemGroup>
  <Reference Include="Leadtools, Version=16.5.0.0, Culture=neutral, PublicKeyToken=9cf889f53ea9b907, processorArchitecture=x86">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>..\..\Lib\Leadtools\$(CurrentPlatform)\Leadtools.dll</HintPath>
  </Reference>
  <Reference Include="Leadtools.Codecs, Version=16.5.0.0, Culture=neutral, PublicKeyToken=9cf889f53ea9b907, processorArchitecture=x86">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>..\..\Lib\Leadtools\$(CurrentPlatform)\Leadtools.Codecs.dll</HintPath>
  </Reference>
  <Reference Include="Leadtools.ImageProcessing.Core, Version=16.5.0.0, Culture=neutral, PublicKeyToken=9cf889f53ea9b907, processorArchitecture=x86">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>..\..\Lib\Leadtools\$(CurrentPlatform)\Leadtools.ImageProcessing.Core.dll</HintPath>
  </Reference>
  <Reference Include="System" />
  <Reference Include="System.Core" />
  <Reference Include="System.Data.Entity" />
  <!--  Other project references -->
</ItemGroup>

$(CurrentPlatform)위에서 정의한 속성 의 사용에 유의하십시오 . 대신 어떤 어셈블리를 어떤 플랫폼에 포함할지 조건문을 사용할 수 있습니다. 다음을 수행해야 할 수도 있습니다.

  • 프로젝트의 대상 플랫폼 만 고려 하려면 $(PROCESSOR_ARCHITEW6432)$(PROCESSOR_ARCHITECTURE)로 교체하십시오.$(Platform)
  • 현재 시스템에 적합하도록 플랫폼 결정 논리를 변경하여 32 비트 플랫폼에서 실행하기 위해 64 비트 바이너리를 빌드 / 참조하지 않도록합니다.

이 글은 원래 내부 Wiki 용으로 작성되었지만 자세한 단계별 지침에 관심이 있다면 수정하여 전체 프로세스를 내 블로그에 게시했습니다 .


답변

AFAIK, 프로젝트에 32 비트 또는 64 비트 특정 참조 (예 : COM-interop 어셈블리)가 필요하고 .csproj 파일을 수동으로 편집하는 데 관심이없는 경우 별도의 32 비트 및 64 비트를 만들어야합니다. 64 비트 프로젝트.

다음 솔루션은 테스트되지 않았지만 작동해야합니다. .csproj 파일을 수동으로 편집하려는 경우 단일 프로젝트로 원하는 결과를 얻을 수 있어야합니다. .csproj 파일은 MSBuild 스크립트 일 뿐이므로 전체 참조는 여기를 참조 하십시오 . 편집기에서 .csproj 파일을 열면 <Reference>요소를 찾습니다 . 이러한 요소를 플랫폼 별이 아닌 참조, x86 별 참조 및 x64 별 참조의 3 가지 개별 항목 그룹 으로 분할 할 수 있어야합니다 .

다음은 프로젝트가 “x86″및 “x64″라는 대상 플랫폼으로 구성되었다고 가정하는 예입니다.

<!-- this group contains references that are not platform specific -->
<ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <!-- any other references that aren't platform specific -->
</ItemGroup>

<!-- x86 specific references -->
<ItemGroup Condition=" '$(Platform)' == 'x86' ">
    <Reference Include="MyComAssembly.Interop">
        <HintPath>..\..\lib\x86\MyComAssembly.Interop.dll</HintPath>
    </Reference>

    <!-- any additional x86 specific references -->
</ItemGroup>

<!-- x64 specific referneces -->
<ItemGroup Condition=" '$(Platform)' == 'x64' ">
    <Reference Include="MyComAssembly.Interop">
        <HintPath>..\..\lib\x64\MyComAssembly.Interop.dll</HintPath>
    </Reference>

    <!-- any additional x64 specific references -->
</ItemGroup>

이제 x86 또는 x64 플랫폼을 대상으로하는 프로젝트 / 솔루션 빌드 구성을 설정할 때 각 경우에 적절한 참조를 포함해야합니다. 물론 <Reference>요소 를 가지고 놀아야 합니다. x86 및 x64 참조를 추가하는 더미 프로젝트를 설정 한 다음 <Reference>해당 더미 프로젝트 파일에서 필요한 요소를 “실제”프로젝트 파일로 복사 할 수도 있습니다.

편집 1
다음은 원래 게시물에서 실수로 생략 한 일반적인 MSBuild 프로젝트 항목에 대한 링크입니다. http://msdn.microsoft.com/en-us/library/bb629388.aspx


답변

프로젝트 파일의 dll 참조에 대해 ItemGroup 에 조건을 사용할 수 있습니다 .
이렇게하면 활성 구성을 변경할 때마다 Visual Studio에서 조건과 참조를 다시 확인합니다.
각 구성에 대한 조건을 추가하기 만하면됩니다.

예:

 <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <Reference Include="DLLName">
      <HintPath>..\DLLName.dll</HintPath>
    </Reference>
    <ProjectReference Include="..\MyOtherProject.vcxproj">
      <Project>{AAAAAA-000000-BBBB-CCCC-TTTTTTTTTT}</Project>
      <Name>MyOtherProject</Name>
    </ProjectReference>
  </ItemGroup>


답변

내 프로젝트에서 예를 들어 \ component \ v3_NET4에있는 x86 DLL을 참조하고 있습니다. x86 / x64 용 특정 DLL은 “x86″및 “x64″resp라는 하위 폴더에 있습니다.

그런 다음 $ (PlatformName)을 기반으로 적절한 DLL (x86 / x64)을 참조 된 폴더에 복사하는 사전 빌드 스크립트를 사용하고 있습니다.

xcopy /s /e /y "$(SolutionDir)..\component\v3_NET4\$(PlatformName)\*" "$(SolutionDir)..\component\v3_NET4"

나를 위해 작동합니다.


답변

x86 / x64 종속성이있는 하나의 .Net 빌드

다른 모든 답변은 플랫폼에 따라 다른 빌드를 만드는 솔루션을 제공하지만 “AnyCPU”구성 만 사용하고 x86 및 x64 dll과 함께 작동하는 빌드를 만드는 옵션을 제공합니다.

런타임시 올바른 x86 / x64-dll 해결

단계 :

  1. csproj에서 AnyCPU 사용
  2. csprojs에서 x86 또는 x64 dll 만 참조할지 결정합니다. UnitTests 설정을 선택한 아키텍처 설정에 적용하십시오. VisualStudio 내에서 테스트를 디버깅 / 실행하는 데 중요합니다.
  3. Reference-Properties에서 Copy Local & Specific Versionfalse로 설정하십시오.
  4. x86 / x64를 참조하는 모든 csproj 파일 의 첫 번째 PropertyGroup 에 다음 줄을 추가하여 아키텍처 경고를 제거 합니다.
    <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. 이 빌드 후 스크립트를 시작 프로젝트에 추가하고이 스크립트의 경로를 사용 및 수정하여 빌드 bin \ x86 \ bin \ x64 \의 해당 하위 폴더에있는 모든 x86 / x64 dll을 복사합니다.

    xcopy /E /H /R /Y /I /D $(SolutionDir)\YourPathToX86Dlls $(TargetDir)\x86
    xcopy /E /H /R /Y /I /D $(SolutionDir)\YourPathToX64Dlls $(TargetDir)\x64

    -> 지금 애플리케이션을 시작하면 어셈블리를 찾을 수 없다는 예외가 발생합니다.

  6. 애플리케이션 진입 점의 시작 부분에 AssemblyResolve 이벤트를 등록합니다.

    AppDomain.CurrentDomain.AssemblyResolve += TryResolveArchitectureDependency;

    이 방법으로 :

    /// <summary>
    /// Event Handler for AppDomain.CurrentDomain.AssemblyResolve
    /// </summary>
    /// <param name="sender">The app domain</param>
    /// <param name="resolveEventArgs">The resolve event args</param>
    /// <returns>The architecture dependent assembly</returns>
    public static Assembly TryResolveArchitectureDependency(object sender, ResolveEventArgs resolveEventArgs)
    {
        var dllName = resolveEventArgs.Name.Substring(0, resolveEventArgs.Name.IndexOf(","));
    
        var anyCpuAssemblyPath = $".\\{dllName}.dll";
    
        var architectureName = System.Environment.Is64BitProcess ? "x64" : "x86";
    
        var assemblyPath = $".\\{architectureName}\\{dllName}.dll";
    
        if (File.Exists(assemblyPath))
        {
            return Assembly.LoadFrom(assemblyPath);
        }
    
        return null;
    }
  7. 단위 테스트가있는 경우 AssemblyInitializeAttribute가있는 메서드로 TestClass를 만들고 위의 TryResolveArchitectureDependency-Handler도 등록합니다. (Visual Studio 내에서 단일 테스트를 실행하는 경우 가끔 실행되지 않을 것입니다. 참조는 UnitTest bin에서 확인되지 않습니다. 따라서 2 단계의 결정이 중요합니다.)

혜택:

  • 두 플랫폼 모두에 대해 하나의 설치 / 빌드

단점 :-x86 / x64 dll이 일치하지 않을 때 컴파일 타임에 오류가 없습니다. -두 모드 모두에서 테스트를 실행해야합니다!

선택적으로 postbuild 스크립트에서 Corflags.exe를 사용하여 x64 아키텍처 전용 두 번째 실행 파일을 만듭니다.

시도해 볼 다른 변형 :-시작시 dll이 바이너리 폴더에 복사되도록 보장하는 경우 AssemblyResolve 이벤트 처리기가 필요하지 않습니다 (프로세스 아키텍처 평가-> 해당 dll을 x64 / x86에서 bin 폴더로 이동했다가 뒤로 이동). -설치 프로그램에서 아키텍처를 평가하고 잘못된 아키텍처에 대한 바이너리를 삭제하고 올바른 항목을 bin 폴더로 이동합니다.


답변

나는 같은 문제에 직면했고 괜찮은 해결책을 찾기 위해 꽤 오랜 시간을 보냈다. 대부분의 사람들은 Visual Studio 솔루션 파일의 수동 편집을 제공하는데, 이는 나중에 Visual Studio GUI에서 이러한 편집 된 파일을 탐색 할 때 매우 지루하고 오류가 발생하기 쉬우 며 혼란스러운 작업입니다. 이미 포기했을 때 해결책이 나왔습니다. Micke가 위의 답변에서 권장하는 것과 매우 유사합니다.

계정 관리자에서 평소와 같이 x86 및 x64 플랫폼에 대해 두 개의 별도 빌드 대상을 만들었습니다. 다음으로 x86 어셈블리에 대한 참조를 프로젝트에 추가했습니다. 이 시점에서 저는 위의 Hugo가 제안한대로 수동으로 편집하지 않는 한 프로젝트가 x86 빌드 전용으로 구성되고 x64 구성으로 빌드되지 않을 것이라고 믿었습니다.

잠시 후 결국 제한을 잊어 버리고 실수로 x64 빌드를 시작했습니다. 물론 빌드는 실패했습니다. 그러나 중요한 것은 내가받은 오류 메시지였습니다. 오류 메시지는 참조 된 x86 어셈블리와 정확히 일치하는 어셈블리가 솔루션의 x64 빌드 대상으로 의도 된 폴더에 누락되어 있음을 알려줍니다.

이것을 발견하고 적절한 x64 어셈블리를이 디렉터리에 수동으로 복사했습니다. 영광! 내 x64 빌드는 적절한 어셈블리를 발견하고 암시 적으로 연결하여 기적적으로 성공했습니다. x64 어셈블리의 빌드 대상 디렉터리를이 폴더에 설정하도록 솔루션을 수정하는 데 몇 분 밖에 걸리지 않았습니다. 이 단계 후에 솔루션은 MSBuild 파일을 수동으로 편집하지 않고도 x86 및 x64 모두에 대해 자동으로 빌드됩니다.

요약하자면 :

  1. 단일 프로젝트에서 x86 및 x64 대상 만들기
  2. x86 어셈블리에 모든 적절한 프로젝트 참조 추가
  3. 모든 x64 어셈블리에 대해 하나의 공통 빌드 대상 디렉터리 설정
  4. 준비된 x64 어셈블리가있는 경우 x64 빌드 대상 디렉터리에 한 번만 복사합니다.

이 단계를 완료하면 솔루션이 x86 및 x64 구성 모두에 대해 올바르게 빌드됩니다.

이것은 Visual Studio 2010 .NET 4.0 C # 프로젝트에서 저에게 효과적이었습니다. 분명히 이것은 Visual Studio의 문서화되지 않은 내부 동작이며 2012, 2013 및 2015 버전에서 변경 될 수 있습니다. 누군가 다른 버전을 사용해 볼 경우 경험을 공유하십시오.


답변

나는 Micke의 반전과 같은 더 쉬운 해결책이라고 생각하는 것을 사용했습니다. 프로젝트는 x86 및 x64 대상이있는 C # 양식 앱인 Visual Studio 2015입니다. .NET 어셈블리 중 하나를 참조했고 32 비트 어셈블리를 사용했습니다. 참조 속성에서 “Copy Local”을 false로 설정했습니다. 그런 다음 각 대상 디렉터리에 적절한 (32 비트 또는 64 비트) .Net 어셈블리를 수동으로 넣습니다. 실제 참조 비트는 외부 인터페이스를 정의하는 것이므로 동일한 기능이 있다고 가정하면 관련이 없습니다. 멋지게 만들고 싶다면 포스트 빌드 복사 단계를 넣을 수도 있습니다. 이 프로젝트에도 COM 참조가 있으며 동일한 작업이 작동합니다. 참조는 개체 / 인터페이스를 정의하므로 참조 DLL의 비트는 관련이 없습니다. 32 비트 및 64 비트 COM DLL이 모두 등록 된 경우 앱은 레지스트리의 적절한 위치를 찾고 올바른 32 비트 또는 64 비트 COM 개체를 만듭니다. 나를 위해 작동합니다!