繁体   English   中英

msbuild和Visual Studio项目配置问题

[英]msbuild and visual studio project configuration problem

我有一个包含很多项目和安装程序项目的解决方案。 一个项目使用第三方程序包。 该软件包带有一个本机DLL和.net包装器DLL。 为了使代码正常工作,.net包装器DLL需要在运行时查找本机DLL。 但是代码在编译时从不直接引用本机DLL(代码在编译时与.net包装器DLL通信)。

现在,我必须在程序员的计算机上的编译期间以及在用户计算机上的安装期间选择适当的方法来部署本机DLL。

基本上,我有两个选择,要么将本机DLL放入Windows System文件夹,要么将本机DLL放入包含exe文件的本地文件夹。

要将本机DLL放入系统文件夹,在构建解决方案后,我需要一个后构建脚本来将该文件xcopy到目录中。 我还需要在安装程序项目中创建系统文件夹输出,以便安装程序在客户端计算机上工作。 我不知道将文件复制到系统文件夹是否是个好主意。 对于此解决方案,每次(大团队中的其他人)创建新的安装程序时,他或她都必须记住创建系统文件夹输出并在配置下添加本机DLL,否则他或她的安装程序将无法安装用户计算机上的软件。

要将本机DLL放入本地文件夹,我有以下两种方式:1.使用后期生成脚本。 此解决方案必须在我的大型解决方案中找出每个使用本机DLL对该项目进行引用的可执行项目,并将构建后脚本链接到每个此类可执行项目。 将来,当某人(其他人在大团队中)创建相同类型的新可执行项目时,他(或她)必须记住链接相同的构建后脚本,否则可执行文件将无法找到本机DLL。 。 这是我真正不喜欢的,人们往往会忘记。

  1. 我可以将本机DLL添加到使用它的项目中,并在DLL的属性配置中将其设置为“ Copy If Newer”。 这样,本机DLL将被复制到项目的输出文件夹以及引用该项目的每个项目中。 这样,我不必记住任何东西。 本机DLL将被复制到每个相关项目的本地文件夹中。

这似乎是一个很好的解决方案。 但是msbuild命令似乎不能巧妙地处理这种情况。 例如,假设项目A直接使用本机DLL,并且我将本机DLL添加到项目A。项目B指代项目A,项目C指代项目B和项目A。如果使用msbuild生成解决方案,则本机DLL将是重复复制3次到项目C的输出文件夹,一次复制到项目A,一次复制到项目B,一次复制到项目B,复制到项目A。在我的大型解决方案中,依赖项链接的末尾无论“复制较新”设置如何,本机DLL都会以指数方式多次复制到同一输出文件夹。 这将花费大量时间来构建整个解决方案。

现在我完全不知道什么是最适合我的情况的解决方案。 对于使用本机DLL的任何人,您如何部署DLL,因此1.既方便在开发人员机器(编译并运行)和用户计算机(安装并运行)上进行部署,2.大型团队中的开发人员没有在他或她向解决方案添加新项目/安装程序时记住任何东西,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上,可以通过将对mklink的调用替换为对junction.exe的调用来代替使用结点。

默认情况下,它必须以管理员身份运行。

对于初学者,除非没有其他选择,否则避免使用构建后事件。 生成后事件不受管理的性质往往会使生成失败并且可维护性较低。

“如果较新则复制”标志可能有些la脚,但可以向您保证:1)所需的依赖项将被复制到输出2)它不会使构建失败3)实际上没有可维护性。

其次,可以通过仅使用“ Copy If Newer”标志设置构建链中的最后一个项目来减少冗余复制,例如:项目A直接引用DLL但将其复制到输出,项目C通过以下方式间接指向项目A项目B,并且具有对DLL的虚拟引用,并启用了“如果更新则复制”。

史蒂夫,

我一直都将本机dll添加到我的项目中,而将dll作为内容添加到项目中并没有问题。 您实际上可以将必要的dll添加为项目链接,而不是实际内容。 这样,dll将不会被复制到项目文件夹以及目标文件夹中。

这是devx的解释:

要添加共享文件,请打开对话框以使用“项目” |“选择”来选择现有文件。 添加现有项菜单项,然后选择要包括的文件。 然后,不要单击“打开”按钮,而是单击该按钮左侧的箭头,然后从下拉列表中单击“链接文件”。 这样,您可以链接到原始文件,而不是其本地副本。

您是否将所有项目都构建到公共解决方案目标目录中,即.. \\ bin \\ debug? 这可能会减少不必要的副本。

将项目链接添加到dll绝对比在构建事件中复制要容易维护。

在项目设置中必须有一些“狡猾”的东西(例如循环引用)来引起无限的复制循环-但是找到它可能很棘手和/或很耗时。

我会尝试两件事:

  • 关闭“较新”标志,看看它是否对您的问题有影响。 复制单个dll不太可能极大地影响构建时间,并且当文件的日期戳不清时,使用此选项可能会出现问题。 (我不希望这会导致重复的复制尝试)

  • 尝试对xcopy使用构建后事件来复制文件,而不要依赖自动系统。 然后,您将完全控制一个简单的系统,而不用担心为什么一个聪明的系统不起作用。

我个人将本机DLL和程序集DLL视为一个实体。 将链接添加到文件是一种方法。 或者,您可以有一个单独的主构建脚本,以完善您的项目和安装程序。

例如,我有一个Library.msbuild文件,该文件运行源.csproj的MsBuild任务作为构建目标。 我的部署目标使用复制任务将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方法。 目的是当您运行\\调试项目时,所有内容都是相对于bin的。 如果要从.NET DLL中分离本机,甚至可以使用bin \\ win32。

现在,每个构建都是通过.build.cmd批处理文件(一键生成)完成的,该文件就是这样: C:\\Windows\\Microsoft.NET\\Framework\\v3.5\\MSBuild Library.msbuild /t:Deploy 您可以自由地在构建后但部署之前在测试中添加更多目标,例如测试。

如果您使用的是WiX或任何其他类型的安装程序,则应该能够为文件本身使用相对路径。 我有一个顶级的staging \\目录,从source \\ install \\(.. \\ .. \\ staging \\ icky,是的,没问题,但是可以使用)进入。 最坏的情况是,您可以将登台目录放置在安装路径内的某个位置。

在大多数情况下,您不必摆脱.csproj或.wixproj文件的抽象MsBuild所困扰。 之前/之后构建遇到一个非常低的上限,但是我发现自己现在几乎在每种情况下都选择这种方法。

看到这个职位: http : //blog.alexyakunin.com/2009/09/making-msbuild-visual-studio-to.html

它说明了如何自动将第N级依赖项复制到Bin文件夹中。

如果您有一些甚至没有间接引用的程序集,则可以创建另一个程序集(例如MyProject.ThirdPartyMagnet ),从该项目中引用该程序集,并从需要将所有程序集复制到其中的项目中引用MyProject.ThirdPartyMagnet

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM