동일한 솔루션 / 프로젝트에서 Visual Studio로 32 비트 및 64 비트를 모두 대상으로 지정


111

다중 타겟팅을 위해 비주얼 스튜디오 빌드를 설정하는 방법에 대해 약간의 딜레마가 있습니다.

배경 : 설치 프로젝트가있는 타사 32 비트 DLL, SQL compact v3.5 SP1로 p / 호출하는 c # .NET v2.0. 현재 플랫폼 대상은 x86으로 설정되어 있으므로 Windows x64에서 실행할 수 있습니다.

제 3 자 회사는 방금 DLL의 64 비트 버전을 출시했으며 전용 64 비트 프로그램을 만들고 싶습니다.

이것은 내가 아직 답을 얻지 못한 몇 가지 질문을 제기합니다. 똑같은 코드 기반을 원합니다. 32 비트 DLL 또는 64 비트 DLL에 대한 참조로 빌드해야합니다. (타사 및 SQL Server Compact 모두)

2 개의 새로운 구성 세트 (Debug64 및 Release64)로이 문제를 해결할 수 있습니까?

2 개의 개별 설정 프로젝트 (표준 Visual Studio 프로젝트, Wix 또는 기타 유틸리티 없음)를 만들어야합니까, 아니면 동일한 .msi 내에서 해결할 수 있습니까?

모든 아이디어 및 / 또는 권장 사항을 환영합니다.


@Magnus Johansson : 두 가지 구성을 사용하여 목표의 절반을 달성 할 수 있습니다. MSI는 조금 더 어렵습니다.
user7116

답변:


83

예, 동일한 프로젝트에서 동일한 코드 기반으로 x86 및 x64를 모두 대상으로 지정할 수 있습니다. 일반적으로 VS.NET에서 올바른 솔루션 구성을 만들면 문제가 해결됩니다 (비 관리 DLL에 대한 P / Invoke에는 대부분 조건부 코드가 필요할 가능성이 높음). 특별한주의가 필요한 항목은 다음과 같습니다.

  • 이름은 같지만 고유 한 비트를 가진 외부 관리 어셈블리에 대한 참조 (COM interop 어셈블리에도 적용됨)
  • MSI 패키지 (이미 언급했듯이 x86 또는 x64를 대상으로해야 함)
  • MSI 패키지의 모든 사용자 지정 .NET 설치 관리자 클래스 기반 작업

어셈블리 참조 문제는 지정된 이름의 참조를 프로젝트에 한 번만 추가 할 수 있으므로 VS.NET 내에서 완전히 해결할 수 없습니다. 이 문제를 해결하려면 프로젝트 파일을 수동으로 편집하십시오 (VS에서 솔루션 탐색기에서 프로젝트 파일을 마우스 오른쪽 단추로 클릭하고 프로젝트 언로드를 선택한 다음 다시 마우스 오른쪽 단추를 클릭하고 편집을 선택하십시오). x86 버전의 어셈블리에 대한 참조를 추가하면 프로젝트 파일에 다음과 같은 내용이 포함됩니다.

<Reference Include="Filename, ..., processorArchitecture=x86">
  <HintPath>C:\path\to\x86\DLL</HintPath>
</Reference>

적용되는 솔루션 구성을 나타내는 ItemGroup 태그 안에 Reference 태그를 래핑합니다. 예 :

<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
   <Reference ...>....</Reference>
</ItemGroup>

그런 다음 전체 ItemGroup 태그를 복사하여 붙여넣고 64 비트 DLL의 세부 정보를 포함하도록 편집합니다. 예 :

<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
  <Reference Include="Filename, ..., processorArchitecture=AMD64">
     <HintPath>C:\path\to\x64\DLL</HintPath>
   </Reference>
</ItemGroup>

VS.NET에서 프로젝트를 다시로드 한 후 어셈블리 참조 대화 상자가 이러한 변경 사항으로 인해 약간 혼란스럽고 잘못된 대상 프로세서가있는 어셈블리에 대한 경고가 발생할 수 있지만 모든 빌드는 정상적으로 작동합니다.

MSI 문제를 해결하는 것은 다음 단계이며, 안타깝게도 비 VS.NET 도구 필요합니다. 저는 Caphyon의 고급 설치 프로그램 이 관련된 기본 트릭을 끌어 내기 때문에 해당 목적을 위해 선호합니다 (일반 MSI 및 32 비트 생성 그리고 64 비트 특정 MSI를 사용하고 .EXE 설치 실행기를 사용하여 올바른 버전을 추출하고 런타임에 필요한 수정을 수행합니다.)

다른 도구 나 Windows Installer XML (WiX) 도구 집합을 사용하여 동일한 결과를 얻을 수 있지만 고급 설치 프로그램을 사용하면 작업이 너무 쉬워지고 비용도 저렴하여 실제로 대안을 살펴본 적이 없습니다.

고급 설치 프로그램을 사용하는 경우에도 여전히 WiX가 필요할 수있는 한 가지는 .NET 설치 프로그램 클래스 사용자 지정 작업입니다. 특정 플랫폼에서만 실행되어야하는 특정 작업 (각각 VersionNT64 및 NOT VersionNT64 실행 조건 사용)을 지정하는 것은 간단하지만 기본 제공 AI 사용자 지정 작업은 64 비트 컴퓨터에서도 32 비트 프레임 워크를 사용하여 실행됩니다. .

이 문제는 향후 릴리스에서 수정 될 수 있지만 현재 (또는 다른 도구를 사용하여 동일한 문제가있는 MSI를 만드는 경우) WiX 3.0의 관리되는 사용자 지정 작업 지원을 사용하여 적절한 비트로 작업 DLL을 만들 수 있습니다. 해당 프레임 워크를 사용하여 실행됩니다.


편집 : 버전 8.1.2부터 고급 설치 프로그램은 64 비트 사용자 지정 작업을 올바르게 지원합니다. 내 원래 대답 이후로, 불행히도 InstallShield 및 ilk와 비교할 때 여전히 매우 좋은 가치이지만 가격이 상당히 상승했습니다 ...


편집 : DLL이 GAC에 등록 된 경우 다음과 같이 표준 참조 태그를 사용할 수도 있습니다 (예 : SQLite).

<ItemGroup Condition="'$(Platform)' == 'x86'">
    <Reference Include="System.Data.SQLite, Version=1.0.80.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=x86" />
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'x64'">
    <Reference Include="System.Data.SQLite, Version=1.0.80.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=AMD64" />
</ItemGroup>

조건은 또한 모든 빌드 유형, 릴리스 또는 디버그로 축소되며 프로세서 아키텍처 만 지정합니다.


Visual Studio 2008에서 <ItemGroup>이 중첩 될 수 없음을 발견했습니다. 이 솔루션은 그룹 아래의 새 <ItemGroup>을 나머지 <Reference>로 만들면 제대로 작동했습니다. 또한 x86을 내 특정 프로젝트의 역사와 관련된 AnyCPU로 변경해야했습니다.
Oliver Bock

그 고급 설치 프로그램은 꽤 멋져 보입니다.
Pat

이것은 어리석은 질문 일 수 있지만 파일을 수동으로 편집하려면 어떻게해야합니까?
hrh

1
VS 내에서 파일을 편집하려면 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 "프로젝트 언로드"를 찾습니다. 프로젝트가 언로드되면 다시 마우스 오른쪽 버튼으로 클릭하고 "<프로젝트 파일 이름> 편집"을 클릭합니다. 프로젝트 파일을 편집 한 후 저장하고 프로젝트 파일을 다시 마우스 오른쪽 버튼으로 클릭하고로드합니다. 오타 나 오류가 없으면 다시로드됩니다. 그렇지 않은 경우 VS는 파일의 문제가 무엇인지 거의 알려줍니다. 도움이 되었기를 바랍니다.
John Baughman

좋은 대답입니다! 감사합니다!
John Baughman

27

두 플랫폼 모두에 대해 빌드 된 DLL이 있고 다음 위치에 있다고 가정 해 보겠습니다.

C:\whatever\x86\whatever.dll
C:\whatever\x64\whatever.dll

다음에서 .csproj 파일을 편집하기 만하면됩니다.

<HintPath>C:\whatever\x86\whatever.dll</HintPath>

이에:

<HintPath>C:\whatever\$(Platform)\whatever.dll</HintPath>

그런 다음 두 플랫폼을 모두 대상으로하는 프로젝트를 빌드 할 수 있어야하며 MSBuild는 선택한 플랫폼에 대한 올바른 디렉터리를 찾습니다.


이것이 효과가 있다면 훌륭 할 것이지만 그렇지 않습니다. 적어도 나를 위해.
John Sheehan

10
그게 아니야 : <HintPath> C : \ whatever \ $ (Platform) \ whatever.dll </ HintPath>
Andreas

나를 위해 Visual Studio 2008에서 정상적으로 작동했지만 일반 <Reference>처럼 DLL을 빌드 대상 디렉터리에 자동으로 복사하지 않았습니다. mdb의 솔루션이 더 잘 작동했습니다.
Oliver Bock

1

질문에 대한 전체 답변은 확실하지 않지만 SQL Compact 3.5 SP1 다운로드 페이지 의 추가 정보 섹션 에서 x64를보고 있다는 의견을 지적 할 것이라고 생각 했습니다. 도움이 되었기를 바랍니다.

SQL Server Compact SP1의 변경 사항과 추가 64 비트 버전 지원으로 인해 32 비트 버전의 SQL Server Compact 3.5 및 64 비트 버전의 SQL Server Compact 3.5 SP1의 중앙 설치 및 혼합 모드 환경에서 간헐적으로 보이는 항목이 생성 될 수 있습니다. 문제. 충돌 가능성을 최소화하고 관리되는 클라이언트 응용 프로그램의 플랫폼 중립적 배포를 활성화하려면 Windows Installer (MSI) 파일을 사용하여 64 비트 버전의 SQL Server Compact 3.5 SP1을 중앙에서 설치하려면 32 비트 버전의 SQL Server도 설치해야합니다. 컴팩트 3.5 SP1 MSI 파일. 기본 64 비트 만 필요한 응용 프로그램의 경우 64 비트 버전의 SQL Server Compact 3.5 SP1의 개인 배포를 활용할 수 있습니다.

나는 이것을 "32 비트 SQLCE 파일 뿐만 아니라64 비트 클라이언트 용으로 배포하는 경우 " 64 비트 파일 .

삶을 흥미롭게 만들어요 .. 제가 "간헐적 인 문제로 보이는 것"라인을 좋아한다고 말해야합니다 ... "당신이 상상하는 일이지만, 만약을 대비해서이 일을 ..."


1

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을 복사하는이 스크립트 sp의 경로를 사용 및 수정합니다.

    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 빈에서 확인되지 않습니다. 따라서 2 단계의 결정이 중요합니다.)

혜택:

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

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

필요에 따라 postbuild 스크립트에서 Corflags.exe를 사용하여 x64 아키텍처 전용 두 번째 실행 파일을 만듭니다.

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


0

마지막 질문에 대해. 대부분의 경우 단일 MSI 내에서이 문제를 해결할 수 없습니다. 레지스트리 / 시스템 폴더 또는 관련 항목을 사용하는 경우 MSI 자체가이를 인식하고 32 비트 컴퓨터에 올바르게 설치하려면 64 비트 MSI를 준비해야합니다.

32 it 응용 프로그램으로 제품을 설치하고 64 비트로 실행할 수있을 가능성이 있지만 달성하기가 다소 어려울 수 있습니다.

모든 것에 대해 단일 코드베이스를 유지할 수 있어야한다고 생각합니다. 제 현재 직장에서는 그렇게 할 수있었습니다. (그러나 모든 것이 함께 작동하도록하려면 약간의 저글링이 필요했습니다)

도움이 되었기를 바랍니다. 다음은 32/64 비트 문제와 관련된 정보에 대한 링크입니다. http://blog.typemock.com/2008/07/registry-on-windows-64-bit-double-your.html


0

MSI 설치 프로그램의 일부로 .NET으로 작성된 사용자 지정 작업을 사용하는 경우 다른 문제가 있습니다.

이러한 사용자 지정 작업을 실행하는 'shim'은 항상 32 비트이므로 지정한 대상에 관계없이 사용자 지정 작업도 32 비트로 실행됩니다.

더 많은 정보 및 일부 닌자 이동 (기본적으로이 shim의 64 비트 버전을 사용하도록 MSI를 변경)

SharePoint 64에서 작동하도록 Visual Studio 2005/2008에서 MSI 빌드

Visual Studio를 사용한 64 비트 관리 사용자 지정 작업


0

두 가지 솔루션을 다르게 생성하고 나중에 병합 할 수 있습니다! 나는 VS 2010을 위해 이것을했다. 그리고 그것은 작동한다. CMake에 의해 생성 된 두 가지 솔루션이 있었고 병합했습니다.


0

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