我应该如何在msbuild脚本中引用sn.exe?

我需要在构建完成后重新签署我的程序集(我已经完成了其他一些工作),所以我首先添加一个名为C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\sn.exe任务C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\sn.exe 。 这必须适用于其他开发人员/环境,所以我希望我可以从该文件夹中复制sn.exesn.exe.config并将其存储在我们的代码存储库中,这样我就可以从已知的代码库中调用它的通用版本地点。

sn.exe在sdk目录之外独立崩溃,所以我想知道如何引用它而不知道它将在哪个路径下。 不同的人有不同的环境(x86 vs x64,不同的安装目录,不同的版本),所以我希望能够轻松地引用该工具的最新版本(或者任何版本)。 看起来像一个简单的工具,或许有另一种方法用另一个工具/命令/ msbuild任务签署程序集? 任何帮助,将不胜感激。

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

微软

找到sn或其他类似工具在Windows中的位置的正确方法是从GetFrameworkSdkPath任务开始, 如前所述 。

但是,正如问题所示,无法直接确定Framework或其他工具所在的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具有此function,可用于执行搜索。 结果类似于以下msbuild代码:

           $([System.Text.RegularExpressions.Regex]::Replace('$(SNPath)', ';.*', ''))   

(请参阅属性函数 ,了解为什么我可以在这里使用String.TrimEnd不喜欢尾部斜杠。编辑:我添加了使用属性函数来访问Regex.Replace()以删除除SNPath属性中第一个找到的路径之外的所有路径我朋友的机器之一的WHERE调用会为某些命令输出多个结果并打破任何尝试喜欢的工具。这个改变确保只找到一个结果并且 s实际上成功了。)

现在,您可以使用调用sn

手提

不出所料,在除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的符号链接。
  • 在某个Linux安装上, FrameworkSdkPath/usr/lib64/mono/2.0/usr/bin/sn (这是一个shell脚本调用带有mono /usr/lib64/mono/4.0/sn.exe )。

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

 :; echo 'I'm unix!'; exit $? echo I'm Windows :-/ 

利用这一点,我们生成的GetSNPath任务看起来像:

           $([System.Text.RegularExpressions.Regex]::Replace('$(SNPath)', ';.*', ''))   

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

原来有一个名为“GetFrameworkSdkPath”的任务将获得Windows SDK位置。 从那里,我必须测试以查看sn.exe是否直接存在于bin文件夹中,或者它是否位于bin\NETFX 4.0 Tools\ 。 到目前为止似乎可靠。

  NotSet        $(WindowsSdkPath)bin\sn.exe   $(WindowsSdkPath)bin\NETFX 4.0 Tools\sn.exe      

我现在使用的方法涉及使用属性函数在框架SDK路径下执行SN.exe搜索 – ala:

     $([System.IO.Directory]::GetFiles("$(DotNetFrameworkDir)", "sn.exe", SearchOption.AllDirectories)[0])  

到目前为止,我只在Visual Studio 2013上亲自测试过,但文档暗示它应该回到Visual Studio 2010。

您可以在引用可执行文件的每台开发计算机上创建环境变量,MSBuild允许您作为属性引用。

因此,通过系统属性的高级选项卡创建环境变量。 我通常只创建一个系统环境变量,而不是一个作用于当前用户的变量。 您必须重新启动Visual Studio才能将其拾取。

然后,在MSBuild中引用它:

  

其中SnExe是您定义的环境变量。

值得一提的是,$(SDK40ToolsPath)变量在类似情况下对我有用。 这使得无需知道安装了哪些特定版本的工具,例如:

   $(SDK40ToolsPath)xsd.exe