在使用 Visual Studio 进行编译时,根据需要使用 32/64 位引用。

129

我有一个项目可以生成32位或64位的版本,并且有对应的32/64位依赖项。我想要能够切换配置并且使用正确的引用,但是我不知道如何告诉Visual Studio使用适当架构的依赖项。

也许我在做错事情,但我希望能够在配置下拉菜单中切换x86和x64,并且引用的DLL是正确的位数。


非常不清楚,这是什么语言? DLL项目是否在解决方案中? - Hans Passant
抱歉,这是.NET,我正在使用C#编写。 - Jonathan Yee
4
好的,我用一个比较简单的方法解决了它:创建了一个额外的csproj文件,只引用了x64 DLL(并从csproj中删除了x86配置)。这样做是可行的,但如果有更优雅的解决方案不需要额外的csproj文件,我会很乐意看到它。 - Jonathan Yee
7个回答

107

以下是我在以前的一个项目中所做的事情,这将需要手动编辑 .csproj 文件。您还需要为不同的二进制文件创建单独的目录,最好是彼此同级,并与您正在针对的平台名称相同。

在将单个平台的引用添加到项目后,在文本编辑器中打开 .csproj 文件。在 <Project> 元素内第一个 <ItemGroup> 元素之前添加以下代码,可以帮助确定您正在运行(和构建)哪个平台。

<!-- 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
感谢您提供的信息@tjmoore。您在哪个操作系统上注意到这一点?我刚刚再次检查了我的(Win7SP1),并且$(PROCESSOR_ARCHITECTURE)显示为AMD64,但我肯定希望尽可能获得完整和详细的信息。 - Hugo
7
有趣,我的搜索把我带到了这里,我只需要这个是因为我也在使用LeadTools... +1 - Ed S.
该解决方案适用于默认配置,但在我的测试中,如果您从Visual Studio(我使用的是2012版)解决方案配置下拉列表更改配置,则无法正常工作。 - Sarah Weinberger
出于某种原因,我使用了$(Platform)而不是$(PROCESSOR_ARCHITEW6432),因为$(PROCESSOR_ARCHITEW6432)无法正常工作。 - Dzyann
8年过去了,这仍然是最好的解决方案吗?编辑项目文件? - Pedro77

63
据我所知,如果您的项目需要特定于32位或64位的引用(即COM-interop程序集),并且您不想手动编辑.csproj文件,则必须创建单独的32位和64位项目。
我应该注意到以下解决方案未经测试,但应该可以工作。如果您愿意手动编辑.csproj文件,则应该能够通过单个项目实现所需的结果。.csproj文件只是一个MSBuild脚本,因此要获取完整的参考,请查看这里。打开编辑器中的.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

21
你可以在项目文件中的 ItemGroup 中使用条件来引用 dll 。 这将导致 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
1
说真的,这个答案比被采纳的那个更好更简单。 - Yandros
1
在执行此操作后,参考中出现重复条目是正常的吗? - natenho

8
我在我的项目中引用了位于例如\component\v3_NET4的x86 DLL文件。特定的x86/x64 DLL文件分别位于名为“x86”和“x64”的子文件夹中。
然后,我使用一个预构建脚本,根据$(PlatformName)将适当的DLL文件(x86/x64)复制到引用的文件夹中。
xcopy /s /e /y "$(SolutionDir)..\component\v3_NET4\$(PlatformName)\*" "$(SolutionDir)..\component\v3_NET4"

对我来说可以。


4

使用x86/x64依赖项构建一个.Net应用程序

虽然其他答案提供了根据平台制作不同构建的解决方案,但我给出了一种选择,只需要“AnyCPU”配置并制作一个可以与您的x86和x64 dll一起使用的构建。

在运行时正确解决x86/x64-dlls的问题

步骤:

  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 so 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.)

好处:

  • 一个安装/构建适用于两个平台

缺点: - 当x86 / x64 dll不匹配时,编译时没有错误。 - 您仍应在两种模式下运行测试!

可选地,在postbuild脚本中使用Corflags.exe创建第二个仅适用于x64架构的可执行文件

其他变体尝试: - 如果您确保将dll复制到启动时的二进制文件夹中(评估进程架构->将相应的dll从x64 / x86移动到bin文件夹中并返回),则无需使用AssemblyResolve事件处理程序。 - 在安装程序中评估架构,并删除错误架构的二进制文件并将正确的文件移到bin文件夹中。


3
我遇到了同样的问题,并花了相当长时间寻找一个体面的解决方案。 大多数人提供手动编辑Visual Studio解决方案文件的方法,这是相当繁琐、易错且在后来在Visual Studio GUI中探索这些编辑过的文件时非常令人困惑的。当我已经放弃时,解决方案自己出现了。它与Micke在他上面的回答中推荐的非常相似。
在帐户管理器中,我为x86和x64平台创建了两个单独的构建目标,像往常一样。接下来,我向我的项目添加了对x86程序集的引用。在这一点上,我认为该项目仅配置了x86构建,除非我按照Hugo上面建议的进行手动编辑,否则将永远不会为x64配置构建。
过了一会儿,我最终忘记了限制并意外开始x64构建。当然,构建失败了。但重要的是我收到的错误消息。错误消息告诉我,在预期作为我解决方案的x64构建目标的文件夹中缺少完全与我所引用的x86程序集名称相同的程序集。
注意到这一点后,我手动将正确的x64程序集复制到了这个目录中。辉煌!我的x64构建奇迹般地成功了,并且找到并隐式链接了正确的程序集。修改我的解决方案以将构建目标目录设置为x64程序集的此文件夹只需要几分钟。完成这些步骤后,解决方案将自动为x86和x64构建而无需手动编辑MSBuild文件。
总之:
创建单个项目中的x86和x64目标 添加所有适当的项目引用到x86程序集 为所有x64程序集设置一个共同的构建目标目录 如果您已经准备好了x64程序集,只需将它们复制一次到x64构建目标目录中
完成这些步骤后,您的解决方案将在x86和x64配置下正确构建。
这对我在Visual Studio 2010 .NET 4.0 C#项目上起作用。显然,这是Visual Studio的某种未记录的内部行为,可能会在2012、2013和2015版本中发生变化。 如果有人尝试其他版本,请分享您的经验。

-1
我最终使用了一种我认为更简单的解决方案,有点像Micke提出的倒置方法。该项目是一个C#窗体应用程序,使用Visual Studio 2015,具有x86和x64目标。我引用了其中一个.NET程序集,使用了32位的那个。在引用属性中,我将“Copy Local”设置为false。然后,我只需将适当(32或64位)的.Net程序集手动放入每个目标目录中。实际引用的比特数是无关紧要的,假设它们具有相同的功能,因为它只是定义外部接口。如果你想变得高端一些,你还可以放一个后构建复制步骤。请注意,这个项目也有一个COM引用,同样的方法可以奏效。引用定义对象/接口,因此引用DLL的比特数是无关紧要的。如果同时注册了32位和64位COM DLL,则应用程序将在注册表中的适当位置查找并创建正确的32位或64位COM对象。对我而言可行!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接