【问题标题】:msbuild and visual studio project configuration problemmsbuild和visual studio项目配置问题
【发布时间】:2009-12-09 04:28:42
【问题描述】:

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

现在我必须选择正确的方式来部署本机 DLL,在程序员机器上的编译期间和在用户机器上的安装期间。

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

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

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

  1. 我可以将本机 DLL 添加到使用它的项目中,并在 DLL 的属性配置中,将其设置为“如果较新则复制”。这样,本机 DLL 将被复制到项目的输出文件夹以及引用该项目的每个项目。这样,我就不用记住任何东西了。本机 DLL 将被复制到每个依赖项目的本地文件夹中。

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

现在我完全不知道什么是适合我的情况的最佳解决方案。对于使用本机 DLL 的任何人,您如何部署 DLL 1. 既方便在开发人员机器上(编译和运行)部署,又在用户机器上(安装和运行)部署,2. 大团队的开发人员没有当他或她向解决方案添加新项目/安装程序时要记住任何事情, 3. 足够聪明的构建方式,避免不必要的冗余操作。感谢您提前提供任何提示、网络教程、建议或聪明的教导。

【问题讨论】:

    标签: c# visual-studio-2008 msbuild


    【解决方案1】:

    我们通常所做的是将所有 \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 的调用来使用联结。

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

    【讨论】:

    • 一个警告:永远不要以相对路径作为链接目标运行该脚本。痛苦会随之而来。
    • 是否需要NTFS?它可以在FAT32 上工作吗?
    【解决方案2】:

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

    “Copy If Newer”标志可能效果不佳,但它会向您保证:1)所需的依赖项将被复制到输出 2)它不会使构建失败 3)几乎没有可维护性。

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

    【讨论】:

      【解决方案3】:

      史蒂夫,

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

      这是来自 devx 的解释:

      要添加共享文件,请打开对话框 选择现有文件 项目 |添加现有项目菜单项 并选择你想要的文件 包括。然后,而不是单击 打开按钮,点击上面的箭头 该按钮的左侧,然后单击链接 下拉列表中的文件。 这样你链接到原来的 文件,而不是它的本地副本。

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

      将项目链接添加到 dll 肯定比在构建事件中复制更容易维护。

      【讨论】:

      • 嗨,Soctt,我从不尝试链接本机 dll。我会试一试。当您构建软件的安装程序时,我想您必须将 dll 放在安装程序项目下。那么 dll 的位置可能会在开发时间和安装时间之间发生变化。你如何保持链接指向正确的位置?
      • 史蒂夫,如果我理解你的问题,我认为如果你在项目中链接 dll,它应该作为依赖项复制到部署项目中。如果您不想,您不需要将 dll 移动到 system32。如果您确实需要,您将需要修改部署项目。因为我通常使用 Installshield 并明确定义所有要安装的文件及其目标位置,所以我可能会对此不以为然...
      【解决方案4】:

      您的项目设置中一定有一些“狡猾”的东西(如循环引用)会导致无限复制循环 - 但找到它可能会很棘手和/或耗时。

      我会尝试两件事:

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

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

      【讨论】:

      • 后期构建肯定会有所帮助。但是这样,每次我将一个新项目添加到对包含本机 dll 的项目具有依赖关系的解决方案时,我都需要在构建后脚本中添加一个新的复制行。而且,即使现在我有十几个项目,创建这样的脚本已经足够乏味了。
      【解决方案5】:

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

      例如,我有一个 Library.msbuild 文件,它运行源 .csproj 的 MsBuild 任务作为我的构建目标。我的 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 方法。目标是当您运行\调试您的项目时,所有内容都将与 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,是的,但是可以)。在最坏的情况下,您可以将暂存目录放在安装路径中的某个位置。

      在大多数情况下,您不必对 MsBuild 进行比 .csproj 或 .wixproj 文件更进一步的抽象,从而摆脱困境。 Before/AfterBuild 的上限非常低,但我发现自己现在几乎在所有情况下都选择了这种方法。

      【讨论】:

        【解决方案6】:

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

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

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

        【讨论】:

        • 链接已损坏 (404)。
        猜你喜欢
        • 2012-09-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-14
        • 1970-01-01
        • 2011-06-05
        相关资源
        最近更新 更多