我需要在构建完成后重新签署我的程序集(并且我已经对它做了一些其他的事情),所以我开始添加一个名为 <Exec>C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\sn.exe 任务。这必须适用于其他开发人员/环境,所以我希望我可以从该文件夹中复制 sn.exesn.exe.config 并将其存储在我们的代码存储库中,以便我始终可以从已知位置调用它的通用版本。
sn.exe 在 sdk 目录之外单独崩溃,所以我想知道如何在不知道它将位于什么路径下的情况下引用它。不同的人有不同的环境(x86 与 x64,不同的安装目录,不同的版本),所以我希望能够轻松引用该工具的最新版本(或者任何版本)。似乎是一个足够简单的工具,也许还有另一种方法可以使用另一个工具/命令/msbuild 任务来签署程序集?任何帮助,将不胜感激。

最佳答案

要以适合大多数人的方式在 msbuild 脚本中正确引用 snsqlmetal(我所追求的)等工具,您必须考虑操作环境和框架实现的不同方面。主要有两种情况:Microsoft Windows 和 Microsoft 的框架实现,然后是其他所有内容(我指的是 Mono/unix)。最后列出了支持我能想到的情况的正确方法的示例。

微软

在 Windows 中找到 sn 或其他类似工具所在位置的正确方法是从 GetFrameworkSdkPath task 开始,如 already mentioned

但是,正如问题所暗示的那样,无法直接确定 sn 或其他工具所在的 FrameworkSdkPath 中的确切位置。引用的答案表明 FrameworkSdkPath 下唯一可能用于工具驻留的文件夹是 binbin/NETFX 4.0 Tools 。但是,其他值也是可能的(Visual Studio 2013 Preview 使用 bin/NETFX 4.5.1 Tools )。因此,搜索 sn 的唯一正确方法是使用 glob 表达式或递归搜索它。我无法弄清楚如何使用 MSBuild 进行 glob 扩展,并且内置的 MSBuild 任务似乎不支持在 FrameworkSdkPath 下搜索特定实用程序。但是cmd的 WHERE 有这个功能,可以用来做搜索。结果类似于以下 msbuild 代码:

<Target Name="GetSNPath" BeforeTargets="AfterBuild">
  <GetFrameworkSdkPath>
    <Output TaskParameter="Path" PropertyName="WindowsSdkPath" />
  </GetFrameworkSdkPath>
  <Exec Command="WHERE /r &quot;$(WindowsSdkPath.TrimEnd('\\'))&quot; sn &gt; sn-path.txt"  />
  <ReadLinesFromFile File="sn-path.txt">
    <Output TaskParameter="Lines" PropertyName="SNPath"/>
  </ReadLinesFromFile>
  <Delete Files="sn-path.txt" />
  <PropertyGroup>
    <SNPath>$([System.Text.RegularExpressions.Regex]::Replace('$(SNPath)', ';.*', ''))</SNPath>
  </PropertyGroup>
</Target>

(请参阅 Property Functions 以了解为什么我可以在这里使用 String.TrimEndWHERE 不喜欢尾部斜杠。编辑:我添加了使用属性函数来访问 Regex.Replace() 以删除除 SNPath 属性中第一个找到的路径之外的所有路径。我 friend 的一台机器的 WHERE调用将为某些命令输出多个结果,并破坏了对 fon 工具进行 <Exec/> 的任何尝试。此更改确保仅找到一个结果并且 <Exec/> s 实际上成功。)

现在您可以使用 sn 调用 <Exec Command="&quot;$(SNPath)&quot;" />

便携的

不出所料,在 Windows 以外的任何操作系统上解析 sn 的路径都要简单得多。在 Mac OSX 和任何 Linux 发行版上,我在 PATH 中找到了 sn。在这种情况下,使用 GetFrameworkSdkPath 无济于事;实际上,这似乎返回了一个找不到 sn 的路径,至少对于我在使用 xbuild 时测试的旧版 mono-2.10 而言:
  • 在Mac OSX上,FrameworkSdkPath/Library/Frameworks/Mono.framework/Versions/2.10.5/lib/mono/2.0,而/usr/bin/sn/Library/Frameworks/Mono.framework/Commands/sn的符号链接(symbolic link)。
  • 在某个 Linux 安装中,FrameworkSdkPath/usr/lib64/mono/2.0sn/usr/bin/sn(这是一个 shell 脚本,使用 /usr/lib64/mono/4.0/sn.exe 调用 mono)。

  • 因此,我们需要做的就是尝试执行 sn 。任何将他们的 sn 实现放置在非标准位置的 unix 用户都知道要适本地更新 PATH,因此构建脚本无需搜索它。此外,WHERE 在 unix 中不存在。因此,在unix的情况下,我们希望将第一个<Exec/>调用替换为仅在unix上输出sn并在Windows上运行时仍进行完整搜索的东西。为了区分类 Unix 和 Windows 环境,我们使用了一个技巧,它利用了 unix shell 的 true 命令和 cmd 标签语法的快捷方式。作为一个简短的示例,以下脚本将在 unix shellout 中输出 I’m unix!,在 Windows shellout 中输出 I’m Windows :-/
    :; echo 'I’m unix!'; exit $?
    echo I’m Windows :-/
    

    利用这一点,我们生成的 GetSNPath 任务如下所示:
    <Target Name="GetSNPath" BeforeTargets="AfterBuild">
      <GetFrameworkSdkPath>
        <Output TaskParameter="Path" PropertyName="WindowsSdkPath" />
      </GetFrameworkSdkPath>
      <Exec Command=":; echo sn &gt; sn-path.txt; exit $?
    WHERE /r &quot;$(WindowsSdkPath.TrimEnd('\\'))&quot; sn &gt; sn-path.txt"  />
      <ReadLinesFromFile File="sn-path.txt">
        <Output TaskParameter="Lines" PropertyName="SNPath"/>
      </ReadLinesFromFile>
      <Delete Files="sn-path.txt" />
      <PropertyGroup>
        <SNPath>$([System.Text.RegularExpressions.Regex]::Replace('$(SNPath)', ';.*', ''))</SNPath>
      </PropertyGroup>
    </Target>
    

    结果是一种可移植的方法,用于查找调用 sn 所需的字符串。最后一个解决方案让您可以同时支持 Microsoft 及其 msbuild 以及使用 xbuild 的所有其他平台。它还克服了将 bin\NETFX 4.0 Tools 硬编码到 .csproj 文件的问题,以同时支持 Microsoft 工具的 future 和当前版本。

    关于c# - 我应该如何在 msbuild 脚本中引用 sn.exe?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12781870/

    10-10 03:22