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


124

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

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


매우 불분명합니다. 이것은 어떤 언어입니까? 솔루션에 DLL 프로젝트가 있습니까?
Hans Passant

죄송합니다. 이것은 .NET입니다. 저는 C #으로 작성하고 있습니다.
Jonathan Yee

4
좋아, 나는 멍청한 해결책으로 그것을 해결했다. x64 DLL만을 참조하는 추가 csproj 파일을 만들었다 (그리고 csproj에서 x86 구성을 제거했다). 작동하지만 추가 csproj를 포함하지 않는 더 우아한 솔루션이 있다면보고 싶습니다.
Jonathan Yee

답변:


99

다음은 .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 용으로 작성되었지만 자세한 단계별 지침에 관심이 있다면 수정하여 전체 프로세스를 내 블로그에 게시했습니다 .


1
좋은. 아래 제안에 따라 ItemGroup에 조건부를 사용했지만 여기와 같은 조건에 $ (PROCESSOR_ARCHITEW6432) 및 $ (PROCESSOR_ARCHITECTURE)를 사용했습니다. 참고로 $ (PROCESSOR_ARCHITECTURE)는 32 비트 및 64 비트 플랫폼 모두에서 x86을 반환하지만 $ (PROCESSOR_ARCHITEW6432)는 64 비트에서만 AMD64를 반환합니다. x86을 테스트하려고 할 때주의해야 할 사항 (AMD64는 x86에서 파생 된 것으로 가정하기 때문입니다).
tjmoore 2013-01-31

정보 @tjmoore 주셔서 감사합니다. 어떤 O / S에서 이것을 눈치 챘습니까? 방금 다시 확인하고 (Win7SP1) $ (PROCESSOR_ARCHITECTURE)에 대해 AMD64라고 말했지만 가능한 한 완전하고 철저한 정보를 원합니다.
Hugo

7
웃기게도 검색 결과가 여기로 오는데 LeadTools도 사용하고 있기 때문에이 항목 만 필요합니다 ... +1
Ed S.

솔루션은 기본 구성에서 작동하지만 Visual Studio (내 경우 2012) 솔루션 구성 드롭 다운 목록의 구성에서 구성을 변경 한 경우에는 내 테스트가 아닙니다.
Sarah Weinberger

$ (PROCESSOR_ARCHITEW6432)를 사용하는 대신 $ (PROCESSOR_ARCHITEW6432)가 작동하지 않는 이유로 $ (Platform)을 사용했습니다.
Dzyann 2014

60

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


훌륭한 답변 !! 내 하루를 구했습니다! 감사합니다.
hellodear

20

프로젝트 파일의 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>

1
감사합니다! 이것은 확실히 받아 들여지는 해결책이어야합니다!
ManicBlowfish

진지하게,이 대답은 받아 들여진 대답보다 훨씬 더 좋고 간단합니다.
Yandros

1
이 작업을 수행 한 후 참조에 중복 항목이있는 것이 정상입니까?
natenho

7

내 프로젝트에서 예를 들어 \ 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"

나를 위해 작동합니다.


3

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 폴더로 이동합니다.


2

나는 같은 문제에 직면했고 괜찮은 해결책을 찾기 위해 꽤 오랜 시간을 보냈다. 대부분의 사람들은 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 버전에서 변경 될 수 있습니다. 누군가 다른 버전을 사용해 볼 경우 경험을 공유하십시오.


-1

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.