关于如何设置我的visual studio构建以实现多目标,我有点困难。
后台:c#.NET v2.0,带有p /调用第三方32位DLL,SQL compact v3.5 SP1,带有安装项目。 现在,平台目标设置为x86,因此可以在Windows x64上运行。
第三方公司刚刚发布了他们的DLL的64位版本,我想建立一个专用的64位程序。
这提出了一些我还没有得到答案的问题。 我想拥有完全相同的代码库。 我必须使用32位DLL或64位DLL的引用来构建。 (第三方和SQL Server Compact)
这可以通过2组新配置(Debug64和Release64)来解决吗?
我必须创建2个单独的安装项目(标准视觉工作室项目,没有Wix或任何其他实用程序),还是可以在同一个.msi中解决?
欢迎任何想法和/或建议。
答案 0 :(得分:81)
是的,您可以在同一个项目中使用相同的代码库同时定位x86和x64。一般情况下,如果你在VS.NET中创建正确的解决方案配置,事情将会正常工作(虽然P / Invoke到完全非托管的DLL很可能需要一些条件代码):我发现需要特别注意的项目是:
汇编引用问题无法在VS.NET中完全解决,因为它只允许您将具有给定名称的引用添加到项目中一次。要解决此问题,请手动编辑项目文件(在VS中,在解决方案资源管理器中右键单击项目文件,选择“卸载项目”,然后再次右键单击并选择“编辑”)。在添加对程序集的x86版本的引用之后,您的项目文件将包含以下内容:
<Reference Include="Filename, ..., processorArchitecture=x86">
<HintPath>C:\path\to\x86\DLL</HintPath>
</Reference>
将ItemGroup标记内的Reference标记包装,指示它适用的解决方案配置,例如:
<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用于此目的,因为它取消了基本技巧涉及(创建一个通用的MSI,以及32位和64位特定的MSI,并使用.EXE设置启动器来提取正确的版本并在运行时执行所需的修正)非常非常好。
你可以使用其他工具或Windows Installer XML (WiX) toolset获得相同的结果,但是高级安装程序使事情变得如此简单(并且在这方面非常实惠),我从未真正考虑过替代方案。
可能仍然需要WiX,即使使用Advanced Installer,也适用于.NET Installer Class自定义操作。尽管指定仅应在某些平台上运行的某些操作(分别使用VersionNT64和NOT VersionNT64执行条件)是微不足道的,但内置的AI自定义操作将使用32位框架执行,即使在64位计算机上也是如此
这可以在将来的版本中修复,但是现在(或者当使用不同的工具来创建具有相同问题的MSI时),您可以使用WiX 3.0的托管自定义操作支持来创建动作DLL。使用相应的框架执行的适当位数。
编辑:从版本8.1.2开始,Advanced Installer正确支持64位自定义操作。不幸的是,自从我的原始答案以来,它的价格已经增加了很多,尽管与InstallShield及其同类产品相比,它的价值仍然非常高......
编辑:如果您的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>
条件也减少到所有构建类型,发布或调试,并且只指定处理器体系结构。
答案 1 :(得分:27)
假设您为两个平台构建了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将查找所选平台的正确目录。
答案 2 :(得分:1)
不确定您的问题的完整答案 - 但我想在SQL Compact 3.5 SP1 download page的附加信息部分中指出您正在查看x64时发表评论 - 希望它有所帮助。
由于SQL Server Compact的变化 SP1和其他64位版本 支持,集中安装和混合 模式环境的32位版本 SQL Server Compact 3.5和64位 SQL Server Compact 3.5 SP1的版本 可以创造出似乎是什么 间歇性的问题。尽量减少 冲突的可能性,并使 平台中立部署托管 客户端应用程序,集中 安装64位版本的SQL Server Compact 3.5 SP1使用 Windows Installer(MSI)文件也 需要安装32位版本 SQL Server Compact 3.5 SP1 MSI 文件。仅适用于应用程序 需要本机64位,私有 部署64位版本 SQL Server Compact 3.5 SP1可以 使用。
如果分发给64位客户端,我将其读作“包含32位SQLCE文件以及 64位文件”。
让生活变得有趣我猜...必须说我喜欢“似乎是间歇性的问题”这一行...听起来有点像“你在想象事情,但为了以防万一,做到这一点......” / p>
答案 3 :(得分:0)
关于你的上一个问题。很可能你不能在一个MSI内解决这个问题。 如果您正在使用注册表/系统文件夹或任何相关的文件夹,MSI本身必须知道这一点,您必须准备64位MSI才能在32位计算机上正确安装。
有可能您可以将产品作为32位应用程序安装,并且仍然可以将其作为64位应用程序运行,但我认为这可能有点难以实现。
据说,我认为你应该能够为所有事情保留一个代码库。在我目前的工作场所,我们设法做到了。 (但它确实花了一些时间来让所有东西一起玩)
希望这会有所帮助。 以下是与32/64位问题相关的一些信息的链接: http://blog.typemock.com/2008/07/registry-on-windows-64-bit-double-your.html
答案 4 :(得分:0)
如果您使用.NET编写的自定义操作作为MSI安装程序的一部分,那么您还有另一个问题。
运行这些自定义操作的“shim”始终为32位,然后您的自定义操作也将运行32位,无论您指定的目标是什么。
更多信息&amp;一些忍者移动到周围(基本上改变MSI使用这个垫片的64位版本)
Building an MSI in Visual Studio 2005/2008 to work on a SharePoint 64
答案 5 :(得分:0)
您可以不同地生成两个解决方案,然后合并它们! 我为VS 2010做了这个。它有效。我有两个不同的解决方案由CMake生成,我合并了它们
答案 6 :(得分:0)
您可以对项目文件中的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>
答案 7 :(得分:0)
一个具有x86 / x64依赖项的.Net构建
虽然所有其他答案都为您提供了一个根据平台进行不同构建的解决方案,但我为您提供了一个选项,使其仅具有“ AnyCPU”配置,并构建可与您的x86和x64 dll一起使用的构建。
您必须为此编写一些管道代码。我无法通过app.config使用它。如果其他人知道通过app.config解决它的方法,我真的很想知道。
在运行时解析正确的x86 / x64-dll
步骤:
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
将此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
->立即启动应用程序时,会出现异常 找不到该程序集。
直接在应用程序入口点的开头注册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;
}
好处:
缺点: -x86 / x64 dll不匹配时,在编译时没有错误。 -您仍然应该在两种模式下都进行测试!
(可选)使用Postbuild脚本中的Corflags.exe创建第二个x64架构专有的可执行文件
要试用的其他变体: -如果确保在启动时将dll复制到二进制文件夹中,则不需要AssemblyResolve事件处理程序(评估流程体系结构->将相应的dll从x64 / x86移至bin文件夹,然后再移回。) -在Installer中评估架构,并删除错误架构的二进制文件,然后将正确的二进制文件移至bin文件夹。