问题描述
我需要在构建完成后重新签名我的程序集(并且我还做了其他一些事情),因此我首先添加了一个名为C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\sn.exe
的<Exec>
任务.这必须适用于其他开发人员/环境,因此我希望可以从该文件夹中复制sn.exe
和sn.exe.config
并将其存储在我们的代码存储库中,以便始终可以从已知位置调用它的通用版本.
I need to re-sign my assembly after the build has finished (and I've done some other things to it), so I started by adding an <Exec>
Task that called C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\sn.exe
. This has to work for other developers/environments, so I was hoping I could just copy sn.exe
and sn.exe.config
from that folder and store it in our code repository so I could always call a common version of it from a known location.
sn.exe
在sdk目录外部隔离崩溃,所以我想知道如何在不知道其路径的情况下如何引用它.不同的人具有不同的环境(x86与x64,不同的安装目录,不同的版本),因此我希望能够轻松引用该工具的最新版本(或任何版本).似乎是一个足够简单的工具,也许还有另一种方法可以用另一个工具/命令/msbuild任务对程序集进行签名?任何帮助将不胜感激.
sn.exe
crashes in isolation outside of the sdk directory, so I'm wondering how I can reference it without knowing what path it will be under. Different people have different environments (x86 vs x64, different install directories, different versions), so I would like to be able to easily reference the latest version of the tool (or perhaps any version). Seems like a simple enough tool, perhaps there is another way to sign an assembly with another tool/command/msbuild task? Any help would be appreciated.
推荐答案
以对大多数人有效的方式在msbuild脚本中正确引用sn
或sqlmetal
之类的工具(我所追求的) ,您必须考虑操作环境和框架实施的不同方面.主要有两种情况:Microsoft Windows和Microsoft对框架的实现,然后再进行其他操作(我指的是Mono/unix).最后列出了支持我能想到的情况的正确方法的示例.
To properly reference a tool like sn
or sqlmetal
(what I am after) in an msbuild script in the way that will work for the most people, you must take into consideration different aspects of the operating environment and framework implementation. There are two main cases: Microsoft Windows and Microsoft’s implementation of the framework followed by everything else (by which I mean Mono/unix). An example of the correct approach which supports the situations I can think of is listed at the end.
查找sn
或其他类似工具在Windows中的位置的正确方法是从 GetFrameworkSdkPath任务,如已经提到的 .
The proper way to find where sn
or other similar tools live in Windows is to start with the GetFrameworkSdkPath task, as already mentioned.
但是,正如问题所暗示的,sn
或其他工具所处的FrameworkSdkPath的确切位置无法直接确定.引用的答案表明,FrameworkSdkPath下只能用于存放工具的文件夹是bin
和bin/NETFX 4.0 Tools
.但是,其他值也是可能的(Visual Studio 2013预览版使用bin/NETFX 4.5.1 Tools
).因此,搜索sn
的唯一正确方法是使用全局表达式或递归搜索.我很难弄清楚如何使用MSBuild进行全局扩展,并且内置的MSBuild任务似乎不支持在FrameworkSdkPath下搜索特定实用程序.但是,cmd的 WHERE
具有此功能,可用于进行搜索.结果类似于以下msbuild代码:
However, as the question suggests, the exact location within the FrameworkSdkPath that sn
or another tool lives cannot be determined directly. The referenced answer suggests that the only possible folders under FrameworkSdkPath for tools to reside in are bin
and bin/NETFX 4.0 Tools
. However, other values are possible (Visual Studio 2013 Preview uses bin/NETFX 4.5.1 Tools
). Thus, the only proper way to search for sn
is to use a glob expression or recursively search for it. I have trouble figuring out how to do glob expansion with MSBuild and the built-in MSBuild tasks do not seem to support searching under FrameworkSdkPath for particular utilities. However, cmd’s WHERE
has this functionality and can be used to do the search. The result is something like the following msbuild code:
<Target Name="GetSNPath" BeforeTargets="AfterBuild">
<GetFrameworkSdkPath>
<Output TaskParameter="Path" PropertyName="WindowsSdkPath" />
</GetFrameworkSdkPath>
<Exec Command="WHERE /r "$(WindowsSdkPath.TrimEnd('\\'))" sn > 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>
(请参见属性函数,以了解为什么我可以使用String.TrimEnd
此处WHERE
不喜欢尾部斜杠我添加了使用Property Functions来访问Regex.Replace()
的功能,以删除除SNPath
属性中的第一个找到的路径之外的所有路径.我朋友的机器之一WHERE
调用将为某些命令输出多个结果,并破坏了对<Exec/>
常用工具的任何尝试.此更改可确保仅找到一个结果,并且<Exec/>
实际上成功.)
(See Property Functions to see why I can use String.TrimEnd
here. WHERE
doesn’t like trailing slashes. I added use of Property Functions to access Regex.Replace()
to delete all but the first found path in the SNPath
property. One of my friend’s machines’s WHERE
invocations would output multiple results for certain commands and broke any attempt to <Exec/>
the fond tool. This change ensures that only one result is found and that <Exec/>
s actually succeed.)
现在您可以使用<Exec Command=""$(SNPath)"" />
调用sn
.
不足为奇的是,在Windows以外的任何操作系统上,解析sn
的路径都简单得多.在Mac OSX和任何Linux发行版上,我在PATH中找到sn
.使用GetFrameworkSdkPath
在这种情况下无济于事;实际上,这似乎返回了一个路径,在该路径下找不到sn
,至少对于我在使用xbuild时测试过的mono-2.10的旧版本而言:
Unsurprisingly, resolving the path to sn
is much simpler on any operating system other than Windows. On Mac OSX and any distribution of Linux, I find sn
in the PATH. Using GetFrameworkSdkPath
does not help in such a situation; in fact, this seems to return a path under which sn
cannot be found, at least for the old versions of mono-2.10 I tested while using xbuild:
- 在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
,sn
是/usr/bin/sn
(这是使用mono
调用/usr/lib64/mono/4.0/sn.exe
的shell脚本).
- On Mac OSX
FrameworkSdkPath
is/Library/Frameworks/Mono.framework/Versions/2.10.5/lib/mono/2.0
and/usr/bin/sn
is a symlink to/Library/Frameworks/Mono.framework/Commands/sn
. - On a certain Linux install,
FrameworkSdkPath
is/usr/lib64/mono/2.0
andsn
is/usr/bin/sn
(which is a shell script invoking/usr/lib64/mono/4.0/sn.exe
withmono
).
因此,我们要做的就是尝试执行sn
.任何将sn
实现放在非标准位置的unix用户都已经知道适当地更新PATH,因此构建脚本无需搜索它.另外,WHERE
在UNIX中不存在.因此,在unix情况下,我们希望将第一个<Exec/>
调用替换为仅在unix上输出sn
并且在Windows上运行时仍进行完整搜索的东西.为了区分类似Unix的环境和Windows环境,我们使用了一个技巧,该技巧利用了Unix Shell的true
commmand和cmd的标签语法的快捷方式.作为一个简短示例,以下脚本将在unix外壳程序中输出I’m unix!
,在Windows外壳程序中输出I’m Windows :-/
.
Thus, all we need to do is try to execute sn
. Any unix users placing their sn
implementations in non-standard places already know to update PATH appropriately, so the build script has no need to ever search for it. Also, WHERE
does not exist in unix. Thus, in the unix case, we want to replace the first <Exec/>
call with something that will output just sn
on unix and still do the full search when run on Windows. To differentiate unix-like and Windows environments, we use a trick which takes advantage of unix shells’ shortcut for the true
commmand and cmd’s label syntax. As a short example, the following script will output I’m unix!
in a unix shellout and I’m Windows :-/
on a Windows shellout.
:; echo 'I’m unix!'; exit $?
echo I’m Windows :-/
利用此优势,我们产生的GetSNPath
任务看起来像:
Taking advantage of this, our resulting GetSNPath
Task looks like:
<Target Name="GetSNPath" BeforeTargets="AfterBuild">
<GetFrameworkSdkPath>
<Output TaskParameter="Path" PropertyName="WindowsSdkPath" />
</GetFrameworkSdkPath>
<Exec Command=":; echo sn > sn-path.txt; exit $?
WHERE /r "$(WindowsSdkPath.TrimEnd('\\'))" sn > 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工具.
The result is a portable method for finding the string required to invoke sn
. This last solution lets you support both Microsoft and its msbuild and every other platform using xbuild. It also overcomes hardcoding bin\NETFX 4.0 Tools
into .csproj files to support future and current versions of Microsoft tools simultaneously.
这篇关于我应该如何在msbuild脚本中引用sn.exe?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!