在Visual Studio中构建时,有条件地使用32/64位引用

时间:2010-09-30 16:08:53

标签: .net visual-studio 64-bit 32bit-64bit

我有一个以32/64位构建的项目,并具有相应的32/64位依赖项。我希望能够切换配置并使用正确的引用,但我不知道如何告诉Visual Studio使用与体系结构相关的依赖。

也许我的方法错误,但我希望能够在配置下拉列表中切换x86和x64,并使引用的DLL成为正确的位。

7 个答案:

答案 0 :(得分:97)

这是我在之前的项目中所做的,这将需要手动编辑.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),仅考虑项目的目标平台
  • 更改平台确定逻辑以适合当前计算机,以便您不构建/引用64位二进制文​​件以在32位平台上执行。

我最初是为工作中的内部Wiki编写的,但是,如果您对详细的逐步说明感兴趣,我已对其进行了修改并发布了full process to my blog

答案 1 :(得分:57)

AFAIK,如果您的项目需要32位或64位特定的引用(即COM-interop程序集),并且您没有兴趣手动编辑.csproj文件,那么您将不得不创建单独的32比特和64位项目。

我应该注意以下解决方案未经测试,但应该可行。如果您愿意手动编辑.csproj文件,那么您应该能够通过单个项目实现所需的结果。 .csproj文件只是一个MSBuild脚本,因此要获得完整参考,请查看here。在编辑器中打开.csproj文件后,找到<Reference>元素。您应该能够将这些元素拆分为3个不同的item groups:非平台特定的引用,特定于x86的引用和特定于x64的引用。

以下示例假设您的项目配置了名为“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

答案 2 :(得分:19)

您可以对项目文件中的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>

答案 3 :(得分:7)

我正在引用位于例如x86的x86 DLL。 \ component \ v3_NET4,在我的项目中。 x86 / x64的特定DLL位于名为“x86”和“x64”的子文件夹中。

然后我使用预构建脚本,根据$(PlatformName)将适当的DLL(x86 / x64)复制到引用的文件夹中。

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

适合我。

答案 4 :(得分:2)

我遇到了同样的问题,花了很长时间寻找一个体面的解决方案。大多数人提供Visual Studio解决方案文件的手动编辑,这在以后在Visual Studio GUI中浏览这些编辑过的文件时非常繁琐,容易出错并且容易混淆。当我已经放弃时,解决方案就出现了。这与Micke在上面的回答中推荐的非常相似。

在客户经理中,我像往常一样为x86和x64平台创建了两个独立的构建目标。接下来,我向我的项目添加了对x86程序集的引用。在这一点上,我认为该项目仅针对x86构建进行配置,并且永远不会为x64配置构建,除非我按照上面Hugo的建议对其进行手动编辑。

过了一会儿,我最终忘记了限制并意外启动了x64 build。当然,构建失败了。但重要的是我收到的错误信息。错误消息告知,作为我的解决方案的x6​​4构建目标的文件夹中缺少与我引用的x86程序集完全相同的程序集。

注意到这一点后,我手动将正确的x64程序集复制到此目录中。荣耀!我的x64版本奇迹般地成功找到并隐式链接了正确的程序集。修改我的解决方案以将x64程序集的构建目标目录设置为此文件夹只需几分钟。完成这些步骤后,解决方案将自动为x86和x64构建,无需手动编辑MSBuild文件。

总结一下:

  
      
  1. 在单个项目中创建x86和x64目标
  2.   
  3. 将所有正确的项目引用添加到x86程序集
  4.   
  5. 为所有x64程序集设置一个公共构建目标目录
  6.   
  7. 如果您准备好了x64程序集,只需将它们复制一次到x64构建目标目录
  8.   

完成这些步骤后,您的解决方案将针对x86和x64配置正确构建。

这适用于Visual Studio 2010 .NET 4.0 C#项目。显然,这是Visual Studio的一种无证的内部行为,可能会在2012年,2013年和2015年版本中发生变化。如果有人试用其他版本,请分享您的经验。

答案 5 :(得分:1)

一个具有x86 / x64依赖项的.Net构建

虽然所有其他答案都为您提供了一个根据平台进行不同构建的解决方案,但我为您提供了一个选项,使其仅具有“ AnyCPU”配置,并构建可与您的x86和x64 dll一起使用的构建。

您必须为此编写一些管道代码。我无法通过app.config使用它。如果其他人知道通过app.config解决它的方法,我真的很想知道。

在运行时解析正确的x86 / x64-dll

步骤:

  1. 在csproj中使用AnyCPU
  2. 确定是否仅在csprojs中引用x86或x64 dll。使UnitTests设置适应您选择的体系结构设置。对于在Visual Studio中调试/运行测试很重要。
  3. 在参考属性上,将复制本地特定版本设置为错误
  4. 通过将以下行添加到引用x86 / x64的所有csproj文件中的第一个 PropertyGroup 中来摆脱体系结构警告: <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. 将此postbuild脚本添加到启动项目中,使用并修改此脚本sp的路径,以将所有x86 / x64 dll复制到构建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

    ->立即启动应用程序时,会出现异常 找不到该程序集。

  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文件夹,然后再移回。)  -在Installer中评估架构,并删除错误架构的二进制文件,然后将正确的二进制文件移至bin文件夹。

答案 6 :(得分:0)

我最终使用了我认为更简单的解决方案,类似于Micke的解决方案。该项目是C#表单应用程序Visual Studio 2015,具有x86和x64目标。 我引用了一个.NET程序集,我使用了32位程序集。在参考属性中,将“复制本地”设置为false。然后,我只需在每个目标目录中手动放置适当的(32或64位).Net程序集。假设它们具有相同的功能,则实际的参考位数无关紧要,因为它只是定义外部接口。如果您想花哨的话,也可以放置构建后复制步骤。 请注意,该项目也有一个COM参考,同样的工作原理。该参考定义了对象/接口,因此参考DLL的位无关紧要。如果同时注册了32位和64位COM DLL,则该应用程序将在注册表中的适当位置查找并创建正确的32或64位COM对象。 为我工作!