在 x86 中编译引用 C++/CLI DLL 的 C# 项目时,MSBuild 无法构建

Posted

技术标签:

【中文标题】在 x86 中编译引用 C++/CLI DLL 的 C# 项目时,MSBuild 无法构建【英文标题】:MSBuild fails to build when compiling C# project referencing C++/CLI DLL in x86 【发布时间】:2013-09-03 00:56:35 【问题描述】:

我正在使用 VS2010 和 .NET 4.0。

我有两个小项目 ABA 是 C++/CLI DLL 项目,B 是引用 A 的 C# EXE 项目。两者都必须在 x86 中编译,因为 A 使用 x86 原生 dll。

当我使用 VS2010 IDE 构建 B 时,B 编译良好。接下来我尝试使用以下命令行使用 MSBuild 构建 B

MSBuild B.csproj /property:Platform=x86;Configuration=Release

它失败并出现以下错误。

"A.vcxproj" (默认目标) (16) -> (InvalidPlatformError 目标) -> C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.Cpp.InvalidPlatform.Targets(23,7): 错误 MSB8007:项目“A.vcxproj”的平台无效。平台='x86'。 您可能会看到此消息,因为您正在尝试构建一个没有 解决方案文件,并指定了此项目不存在的非默认平台。 [A.vcxproj]

这似乎是因为 C++/CLI 使用“Win32”作为平台名称,而 C# 使用“x86”。因此,当我指定“x86”时,它无法构建 A。如果是“Win32”,则无法构建 B

由于自动构建,我必须使用 MSBuild。 B 的默认平台固定为 AnyCPU(我无法更改),因此我无法使用默认平台技巧,并且在使用 MSBuild 构建时必须指定“x86”。我怎样才能做到这一点?有什么方法可以更改平台名称,或者使用 MSBuild 的更好方法吗?我可以在不使用默认平台的情况下执行此操作吗?

【问题讨论】:

C#项目的平台名称是没有意义的,你可以随意命名。只有平台目标设置很重要。如果你不能改变一个毫无意义的名字,那么这就是它结束的地方。但是您确实必须解释为什么构建项目 B 也会构建项目 A。这只会在您构建解决方案时发生,而不是在您构建项目时发生。 @HansPassant 因为项目 B 引用了项目 A。该信息包含在 .csproj 文件中,因此 MSBuild 尝试首先构建 A。而且我真的找不到在哪里可以更改 C# 项目的平台名称.. 除了直接编辑 .csproj 文件,这可能会有一些潜在的问题或副作用。 【参考方案1】:

如果您有一个包含两个项目的解决方案并正确设置,您应该能够使用 msbuild 构建该解决方案(afaik 该解决方案将首先使用 Win32 构建 A,然后使用 x86 构建 B)。

另一个选项是不要从 B 引用项目 A,您应该只添加引用 A 的输出 dll。为此,首先确保 A.dll 与 B.exe 位于同一目录中。然后通过浏览输出目录并选择 A.dll 添加对项目 B 的引用。还将“复制本地”设置为 false,因为那时不需要。

【讨论】:

第二个方案似乎有点困难,因为直接构建.sln的输出路径可能与使用msbuild的输出路径不同。第一个看起来很明智,但我决定使用默认平台技巧,因为它更容易。还是谢谢。【参考方案2】:

对于这个我看不到任何解决方法,除了删除 A 对本机 x86 dll 的依赖关系,方法是将其替换为可以与其接口并编译为“AnyCPU”的东西(不确定您受哪些 dll/s 限制)。基本上我的理解是,作为 win32 意味着它可以在比 x86 编译程序更多的处理器上运行,因此从 MSbuild 的角度来看它们不兼容。如果为平台指定“AnyCPU”会怎样?

【讨论】:

提到 A 使用的 x86 本机 dll 是外部 DLL,仅在 x86 中受支持。如果 B 内置于 AnyCPU 并在 x64 操作系统中执行,它将作为 x64 加载,并且不会使用 x86 原生 dll。 实际上 B 可能甚至不会加载 sinec 它不会找到 A 的 x64 版本或它的本机依赖项【参考方案3】:

刚刚找到了一个有趣的方法来解决这个问题:使用一些自定义 XML 扩展 .csproj 文件,以便正确构建依赖的 .vcxproj。

http://troyparsons.com/blog/2012/08/fixing-csproj-builds-that-reference-vcxproj-files-using-assignprojectconfiguration-task/#comment-843

以防万一链接失效,这是重要的部分。不知道为什么或如何工作,但它为我完成了这项工作!

<Target Name="PrepProjectConfiguration" BeforeTargets="PrepareForBuild" Condition="'$(Platform)' == 'x86'">
   <AssignProjectConfiguration
         CurrentProjectConfiguration="$(Configuration)"
         CurrentProjectPlatform="$(Platform)"
         ProjectReferences="@(ProjectReference)"
         ResolveConfigurationPlatformUsingMappings="true">
      <Output TaskParameter="AssignedProjects" ItemName="ProjectReferenceWithConfiguration" />
   </AssignProjectConfiguration>
   <ItemGroup>
      <ProjectReference Remove="@(ProjectReferenceWithConfiguration)" />
   </ItemGroup>
   <Message Text="  regular reference %(ProjectReference.Identity)" />
   <Message Text="re-mapped reference %(ProjectReferenceWithConfiguration.Identity) - %(ProjectReferenceWithConfiguration.Configuration)|%(ProjectReferenceWithConfiguration.Platform)" />
</Target>

【讨论】:

以上是关于在 x86 中编译引用 C++/CLI DLL 的 C# 项目时,MSBuild 无法构建的主要内容,如果未能解决你的问题,请参考以下文章

C++/CLI 为啥对托管不可见

VS不同编译器,x86,x64,动态库,静态库交叉引用问题

VS不同编译器,x86,x64,动态库,静态库交叉引用问题

VS不同编译器,x86,x64,动态库,静态库交叉引用问题

DllImport 自动选择x64或x86 dll

『开源重编译』System.Data.SQLite.dll 自适应 x86 x64 AnyCPU 重编译