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


124

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

也许我会采用错误的方式,但是我希望能够在配置下拉菜单中在x86和x64之间切换,并使引用的DLL正确无误。


非常不清楚,这是什么语言?DLL项目是否在解决方案中?
汉斯·帕桑特

抱歉,这是.NET,我正在用C#编写。
乔纳森·YE

4
好的,我用一个愚蠢的解决方案解决了它:创建了一个仅引用x64 DLL的附加csproj文件(并从csproj中删除了x86配置)。它可以工作,但是如果有人有一个更优雅的解决方案而不涉及额外的csproj,我很乐意看到它。
乔纳森·YE

Answers:


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_ARCHITEWTURE2)和$(PROCESSOR_ARCHITECTURE)作为条件。我发现有一个注释,$(PROCESSOR_ARCHITECTURE)在32位和64位平台上均返回x86,但是$(PROCESSOR_ARCHITEW6432)仅在64位上返回AMD64。如果您尝试测试x86,则需要注意一些事项(因为我假设AMD64是x86的派生产品)。
tjmoore 2013年

感谢您提供的信息@tjmoore。您在哪个O / S上注意到这一点?我只是再次检查了我的(Win7SP1),并说了AMD64作为$(PROCESSOR_ARCHITECTURE),但绝对希望拥有尽可能完整和透彻的信息。
雨果

7
有趣的是,我的搜索将我带到了这里,并且我只需要这个,因为我也在使用LeadTools ... +1
Ed S.

该解决方案适用于默认配置,但如果您从Visual Studio(在我的情况下为2012)“解决方案配置”下拉列表中更改配置,则该配置不适用于我的测试。
莎拉·温伯格

出于某些原因,我使用$(Platform)而不是使用$(PROCESSOR_ARCHITEW6432)$(PROCESSOR_ARCHITEW6432)无法正常工作。
Dzyann 2014年

60

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

我应该注意以下解决方案未经测试,但应该可以。如果您愿意手动编辑.csproj文件,那么您应该能够通过单个项目获得所需的结果。.csproj文件只是一个MSBuild脚本,因此,有关完整参考,请参见此处。在编辑器中打开.csproj文件后,找到<Reference>元素。您应该能够将这些元素分成3个不同的项目组:不是平台特定的引用,特定于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/zh-cn/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

我引用的是我项目中的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"

为我工作。


3

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

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

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

脚步:

  1. 在csproj中使用AnyCPU
  2. 确定您是否仅在csprojs中引用x86或x64 dll。使UnitTests设置适应您选择的体系结构设置。这对于在Visual Studio中调试/运行测试很重要。
  3. 在“参考属性”上,将“ 复制本地特定版本”设置 false
  4. 通过将此行添加到引用x86 / x64的所有csproj文件中的第一个PropertyGroup中,可以消除体系结构警告: <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. 将此postbuild脚本添加到启动项目中,使用和修改此脚本的路径,以便将所有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的Method来创建TestClass,并在其中注册上述TryResolveArchitectureDependency-Handler。(如果您在Visual Studio中运行单个测试,有时将不会执行此操作,则不会从UnitTest bin中解析引用。因此,第2步中的决定很重要。)

好处:

  • 两个平台的一个安装/构建

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

(可选)使用postbuild脚本中的Corflags.exe创建x64体系结构专用的第二个可执行文件

可以尝试使用的其他变体:-如果确保在启动时将dll复制到二进制文件夹中,则不需要AssemblyResolve事件处理程序(评估流程体系结构->将相应的dll从x64 / x86移至bin文件夹,然后再移回。) -在Installer中评估架构,并删除错误架构的二进制文件,然后将正确的二进制文件移至bin文件夹。


2

我遇到了同样的问题,花了相当长的时间寻找一个不错的解决方案。大多数人都提供对Visual Studio解决方案文件的手动编辑,这在以后在Visual Studio GUI中浏览这些编辑后的文件时非常繁琐,容易出错并且令人困惑。当我已经放弃时,解决方案本身就来了。这与Micke在上面的答案中建议的非常相似。

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

一段时间后,我最终忘记了限制,并意外地开始了x64构建。当然,构建失败了。但是重要的是我收到的错误消息。错误消息告诉我,与我的参考x86程序集完全相同的程序集在我的解决方案的x6​​4构建目标文件夹中丢失。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.