Programming

동일한 솔루션 / 프로젝트에서 Visual Studio를 사용하여 32 비트 및 64 비트 모두 대상

procodes 2020. 8. 4. 19:42
반응형

동일한 솔루션 / 프로젝트에서 Visual Studio를 사용하여 32 비트 및 64 비트 모두 대상


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

배경 : c # .NET v2.0 (설치 프로젝트가 포함 된 타사 32 비트 DLL, SQL Compact v3.5 SP1에 호출). 현재 플랫폼 대상이 x86으로 설정되어 Windows x64에서 실행될 수 있습니다.

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

이것은 아직 답변을 얻지 못한 몇 가지 질문을 제기합니다. 정확히 동일한 코드베이스를 갖고 싶습니다. 32 비트 DLL 또는 64 비트 DLL에 대한 참조로 빌드해야합니다. (타사 및 SQL Server Compact 모두)

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

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

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


예, 동일한 프로젝트에서 동일한 코드 기반으로 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 태그 안에 감싸서 적용되는 솔루션 구성을 나타냅니다. 예 :

<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의 Advanced Installer 는 기본 트릭을 풀기 때문에 32 비트뿐만 아니라 일반적인 MSI를 만듭니다. 및 64 비트 특정 MSI를 사용하고 .EXE 설치 프로그램을 사용하여 올바른 버전을 추출하고 런타임에 필요한 수정 작업을 수행하십시오).

다른 도구 또는 WiX (Windows Installer XML) 도구 세트를 사용하여 동일한 결과를 얻을 수는 있지만 Advanced Installer는 다른 대안을 본 적이없는 매우 쉬운 도구 입니다.

고급 설치 프로그램을 사용하는 경우에도 WiX 여전히 필요할 수있는 것은 .NET 설치 관리자 클래스 사용자 지정 작업입니다. 특정 플랫폼에서만 실행되어야하는 특정 동작 (각각 VersionNT64 및 NOT VersionNT64 실행 조건 사용)을 지정하는 것은 쉽지 않지만 내장 AI 사용자 지정 동작은 64 비트 시스템에서도 32 비트 프레임 워크를 사용하여 실행됩니다. .

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


편집 : 버전 8.1.2부터 Advanced Installer는 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>

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


두 플랫폼 모두에 대해 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는 선택한 플랫폼의 올바른 디렉토리를 찾습니다.


귀하의 질문에 대한 완전한 대답을 확신하지 못했지만 x64를보고 있는 SQL Compact 3.5 SP1 다운로드 페이지 의 추가 정보 섹션에서 의견을 지적한다고 생각했는데 도움이되기를 바랍니다.

Due to changes in SQL Server Compact SP1 and additional 64-bit version support, centrally installed and mixed mode environments of 32-bit version of SQL Server Compact 3.5 and 64-bit version of SQL Server Compact 3.5 SP1 can create what appear to be intermittent problems. To minimize the potential for conflicts, and to enable platform neutral deployment of managed client applications, centrally installing the 64-bit version of SQL Server Compact 3.5 SP1 using the Windows Installer (MSI) file also requires installing the 32-bit version of SQL Server Compact 3.5 SP1 MSI file. For applications that only require native 64-bit, private deployment of the 64-bit version of SQL Server Compact 3.5 SP1 can be utilized.

I read this as "include the 32bit SQLCE files as well as the 64bit files" if distributing for 64bit clients.

Makes life interesting I guess.. must say that I love the "what appears to be intermittent problems" line... sounds a bit like "you are imagining things, but just in case, do this..."


Regarding your last question. Most likely you cant solve this inside a single MSI. If you are using registry/system folders or anything related, the MSI itself must be aware of this and you must prepare a 64bit MSI to properly install on 32 bit machine.

There is a possibility that you can make you product installed as a 32 it application and still be able to make it run as 64 bit one, but i think that may be somewhat hard to achieve.

that being said i think you should be able to keep a single code base for everything. In my current work place we have managed to do so. (but it did took some juggling to make everything play together)

Hope this helps. Heres a link to some info related to 32/64 bit issues: http://blog.typemock.com/2008/07/registry-on-windows-64-bit-double-your.html


If you use Custom Actions written in .NET as part of your MSI installer then you have another problem.

The 'shim' that runs these custom actions is always 32bit then your custom action will run 32bit as well, despite what target you specify.

More info & some ninja moves to get around (basically change the MSI to use the 64 bit version of this shim)

Building an MSI in Visual Studio 2005/2008 to work on a SharePoint 64

64-bit Managed Custom Actions with Visual Studio


You can generate two solutions differently and merge them afterwards! I did this for VS 2010. and it works. I had 2 different solutions generated by CMake and I merged them


You can use a condition to an ItemGroup for the dll references in the project file.
This will cause visual studio to recheck the condition and references whenever you change the active configuration.
Just add a condition for each configuration.

Example:

 <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>

One .Net build with x86/x64 Dependencies

While all other answers give you a solution to make different Builds according to the platform, I give you an option to only have the "AnyCPU" configuration and make a build that works with your x86 and x64 dlls.

You have to write some plumbing code for this. I could not get this working with app.config. If somebody else knows a way to solve it via app.config I really would like to know.

Resolution of correct x86/x64-dlls at runtime

Steps:

  1. Use AnyCPU in csproj
  2. Decide if you only reference the x86 or the x64 dlls in your csprojs. Adapt the UnitTests settings to the architecture settings you have chosen. It's important for debugging/running the tests inside VisualStudio.
  3. On Reference-Properties set Copy Local & Specific Version to false
  4. Get rid of the architecture warnings by adding this line to the first PropertyGroup in all of your csproj files where you reference x86/x64: <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. Add this postbuild script to your startup project, use and modify the paths of this script sp that it copies all your x86/x64 dlls in corresponding subfolders of your build bin\x86\ bin\x64\

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

    --> When you would start application now, you get an exception that the assembly could not be found.

  6. Register the AssemblyResolve event right at the beginning of your application entry point

    AppDomain.CurrentDomain.AssemblyResolve += TryResolveArchitectureDependency;
    

    withthis method:

    /// <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. If you have unit tests make a TestClass with a Method that has an AssemblyInitializeAttribute and also register the above TryResolveArchitectureDependency-Handler there. (This won't be executed sometimes if you run single tests inside visual studio, the references will be resolved not from the UnitTest bin. Therefore the decision in step 2 is important.)

Benefits:

  • One Installation/Build for both platforms

Drawbacks: - No errors at compile time when x86/x64 dlls do not match. - You should still run test in both modes!

Optionally create a second executable that is exclusive for x64 architecture with Corflags.exe in postbuild script

Other Variants to try out: - You would not need the AssemblyResolve event handler if you assure otherwise that the dlls get copied in your binary folder at start (Evaluate Process architecture -> move corresponding dlls from x64/x86 to bin folder and back.) - In Installer evaluate architecture and delete binaries for wrong architecture and move the right ones to the bin folder.

참고URL : https://stackoverflow.com/questions/145803/targeting-both-32bit-and-64bit-with-visual-studio-in-same-solution-project

반응형