我有一个包含很多项目和安装程序项目的解决方案。一个项目使用第三方包。该软件包附带一个本机DLL和一个.net包装器DLL。为了使代码工作,.net包装器DLL需要在运行时中找到本机DLL。但代码永远不会在编译时直接引用本机DLL(代码在编译时与.net包装器DLL对话)。
现在,我必须选择正确的方式来部署本机DLL,在程序员机器的编译期间以及在用户计算机上安装时间。
基本上我有两个选项,要么将本机DLL放到Windows系统文件夹中,要么将本机DLL放在包含exe文件的本地文件夹中。
要将本机DLL放入系统文件夹,我需要一个构建后的脚本,在构建解决方案后将文件xcopy写入目录。我还需要在安装程序项目中创建一个系统文件夹输出,以便安装程序在客户端计算机上工作。我不知道是否将文件复制到系统文件夹是个好主意。对于此解决方案,每当有人(大团队中的其他人)创建新安装程序时,他或她必须记住创建系统文件夹输出并在配置下添加本机DLL,否则他或她的安装程序将无法安装可用的部分用户机器上的软件。
要将本机DLL放到本地文件夹,我有以下两种方法: 1.使用后构建脚本。这个解决方案,我必须找到我的大解决方案中的每个可执行项目,它使用本机DLL引用项目,并将构建后脚本链接到每个这样的可执行项目。在将来,当某人(大团队中的其他人)创建一个具有相同类型的新可执行项目时,他或她必须记住链接相同的构建后脚本,否则可执行文件将无法找到本机DLL 。这是我真的不喜欢的,人们往往会忘记。
这似乎是一个很好的解决方案。但是msbuild命令似乎无法巧妙地处理这种情况。例如,假设项目A直接使用本机DLL,我将本机DLL添加到项目A.项目B指项目A,项目C指项目B和项目A.如果使用msbuild构建解决方案,本机DLL将是重复复制到项目C的输出文件夹3次,一次用于参考项目A,一次用于参考项目B,一次用于参考项目B到项目A.在我的大解决方案中,在依赖关系链接的末尾,无论“Copy If Newer”设置如何,本机DLL都将以指数方式多次复制到同一输出文件夹。这需要花费大量时间来构建整个解决方案。
现在我完全不知道对我的情况最好的解决方案是什么。对于使用本机DLL的任何人,如何部署DLL以便1.在开发人员计算机(编译和运行)和用户计算机(安装和运行)上进行部署都很方便.2。大团队中的开发人员没有在他或她向解决方案添加新项目/安装程序时记住任何内容,3。足够聪明的构建方式,以避免不必要的冗余操作。感谢您提前提供任何提示,网上教程,建议或聪明的教学。
答案 0 :(得分:3)
我们一般所做的是将所有\ bin目录放入符号链接到公共目录。这样可以避免VS为所有引用执行的所有传递副本,并且可以加速大型解决方案的干净构建,最高可达10-20倍。
我们使用以下powershell脚本来设置符号链接:
param($linkTarget={throw "Link target must be specified"}, $rootDir=".")
ls $rootDir -Recurse -Include *.csproj | % { $_.DirectoryName } | % { Join-Path $_ -ChildPath "bin" } | % {
Write-Host "Creating link from $_ to $linkTarget"
if (Test-Path $_)
{
Remove-Item -Force -Recurse $_
cmd /c rd $_
}
cmd /c mklink /D $_ $linkTarget
}
符号链接需要Vista或Win7;如果在XP上,可以通过调用junction.exe替换对mklink的调用来代替联结。
默认情况下,必须以管理员身份运行。
答案 1 :(得分:1)
首先,除非没有其他选择,否则请避免使用post build事件。构建后事件非托管性质往往会导致构建失败并且可维护性较低。
“Copy If Newer”标志可能具有蹩脚的效果,但它会向您保证:1)所需的依赖项将被复制到输出2)它不会失败构建3)几乎没有可维护性。
其次,您可以通过使用“Copy If Newer”标志仅设置构建链中的最后一个项目来减少冗余复制,例如:项目A直接引用DLL但不将其复制到输出,项目C通过项目B间接指向项目A,并且具有对DLL的虚拟引用,并启用“Copy If Newer”。
答案 2 :(得分:1)
史蒂夫,
我一直在为我的项目添加本机dll,并且我没有将dll作为内容添加到项目中。您实际上可以将必要的dll添加为项目链接而不是实际内容。这样,dll就不会被复制到项目文件夹中以及目标文件夹中。
以下是devx的解释:
要添加共享文件,请打开该对话框 选择一个现有的文件 项目|添加现有项目菜单项 并选择您想要的文件 包括。然后,而不是点击 打开按钮,单击上的箭头 在该按钮的左侧,然后单击“链接” 下拉列表中的文件。 这样您就可以链接到原始版本 文件,而不是它的本地副本。
您是否将所有项目构建到公共解决方案目标目录中,即.. \ bin \ debug?这可能会减少不必要的副本。
将项目链接添加到dll肯定比在构建事件中复制更容易。
答案 3 :(得分:0)
在项目设置中必须有一些“狡猾的”(如循环引用)才能产生无限的复制循环 - 但找到它可能会非常棘手和/或耗费时间。
我会尝试两件事:
关闭“较新”标志,看看它是否对您的问题有任何影响。复制单个dll不太可能影响构建时间,并且当文件日期戳混淆时,此选项可能会出现问题。 (我不希望这会导致重复的复制尝试)
尝试使用带有xcopy的后期构建事件来复制文件,而不是依赖于自动系统。然后你将完全控制一个简单的系统,而不是想知道为什么一个聪明的系统不起作用。
答案 4 :(得分:0)
就个人而言,我将本机DLL和程序集DLL视为一个实体。添加链接到文件是一种方法。或者,您可以使用单独的主构建脚本来按摩项目和安装程序。
例如,我有一个Library.msbuild文件,它运行源.csproj的MsBuild任务作为我的Build目标。 My Deploy目标使用复制任务将dll从source \ library \ LibraryName \ bin \ Configuration * .dll复制到library \ LibraryName。我有一个库位置用于我需要构建的所有源文件,另一个是我的主项目引用的所有bin。
这是整个Library.msbuild脚本:`
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<ProjectDirectory>library\AspNetMvc\DataAnnotationsModelBinder\src</ProjectDirectory>
<LibraryDirectory>..\library\AspNetMvc</LibraryDirectory>
</PropertyGroup>
<ItemGroup>
<CompiledBinaries Include="$(ProjectDirectory)\bin\$(Configuration)\*.dll" />
</ItemGroup>
<Target Name="Clean">
<MSBuild Projects="$(ProjectDirectory)\Microsoft.Web.Mvc.DataAnnotations.csproj"
Targets="Clean" Properties="Configuration=$(Configuration)" />
</Target>
<Target Name="PreBuild" DependsOnTargets="Clean">
</Target>
<Target Name="Build" DependsOnTargets="PreBuild">
<MSBuild Projects="$(ProjectDirectory)\Microsoft.Web.Mvc.DataAnnotations.csproj"
Targets="Build" Properties="Configuration=$(Configuration)" />
</Target>
<Target Name="Deploy" DependsOnTargets="Build">
<Copy SourceFiles="@(CompiledBinaries)" DestinationFolder="$(LibraryDirectory)"/>
</Target>
</Project>
` 在您的实例中,我将Deploy复制任务移动到PreBuild或完全删除它以依赖于复制dll的Add Existing方法。目标是当你运行\ debug你的项目时,一切都将是bin相对的。如果您要将本机与.NET DLL分离,您甚至可以使用bin \ win32。
现在,每个构建都是从.build.cmd批处理文件(一键构建)完成的,就是这样:C:\Windows\Microsoft.NET\Framework\v3.5\MSBuild Library.msbuild /t:Deploy
。您可以在链中添加更多目标,例如在构建之后但在部署之前添加。
如果您使用的是WiX或任何其他类型的安装程序,则应该能够为文件本身使用相对路径。我有一个顶级的staging \目录,我没有问题从源\安装\(.. \ .. \ staging \ icky进入,是但工作)。最糟糕的情况是,您可以将临时目录放在安装路径中的某个位置。
在大多数情况下,您可以远离.csproj或.wixproj文件而不必抽象MsBuild。在After / AfterBuild遇到的天花板非常低,但我发现自己现在几乎在所有情况下都选择了这种方法。
答案 5 :(得分:0)
请参阅此帖子:http://blog.alexyakunin.com/2009/09/making-msbuild-visual-studio-to.html
它解释了如何自动将N级依赖项复制到Bin文件夹中。
如果您有一些程序集,甚至没有间接引用,您可以创建另一个程序集(例如MyProject.ThirdPartyMagnet
),从该项目引用此程序集并从您需要的项目中引用MyProject.ThirdPartyMagnet
将所有程序集复制到。