要正确引用类似的工具sn
or sqlmetal
(我所追求的)在适合大多数人的 msbuild 脚本中,您必须考虑操作环境和框架实现的不同方面。主要有两种情况:Microsoft Windows 和 Microsoft 框架的实现,然后是其他所有内容(我指的是 Mono/unix)。最后列出了支持我能想到的情况的正确方法的示例。
微软
找到哪里的正确方法sn
或 Windows 中的其他类似工具是从GetFrameworkSdkPath 任务 http://msdn.microsoft.com/en-us/library/ms164298, as 已经提到过 https://stackoverflow.com/a/12822416/429091.
然而,正如问题所暗示的,FrameworkSdkPath 中的确切位置sn
或其他刀具寿命无法直接确定。引用的答案表明 FrameworkSdkPath 下唯一可能存放工具的文件夹是bin
and bin/NETFX 4.0 Tools
。但是,其他值也是可能的(Visual Studio 2013 Preview 使用bin/NETFX 4.5.1 Tools
)。因此,唯一正确的方法是搜索sn
是使用 glob 表达式或递归搜索它。我无法弄清楚如何使用 MSBuild 进行全局扩展,并且内置的 MSBuild 任务似乎不支持在 FrameworkSdkPath 下搜索特定实用程序。然而,cmd 的WHERE http://ss64.com/nt/where.html具有此功能,可用于进行搜索。结果类似于以下 msbuild 代码:
<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>
(See 属性功能 http://msdn.microsoft.com/en-us/library/dd633440#BKMK_String看看为什么我可以使用String.TrimEnd
here. WHERE
不喜欢尾随斜杠。编辑:我添加了使用属性函数来访问Regex.Replace()
删除除第一个找到的路径之外的所有路径SNPath
财产。我朋友的一台机器WHERE
调用将为某些命令输出多个结果,并破坏任何尝试<Exec/>
喜欢的工具。这一更改可确保仅找到一个结果,并且<Exec/>
实际上成功了。)
现在您可以调用sn
with <Exec Command=""$(SNPath)"" />
.
Portable
毫不奇怪,解决了路径sn
在 Windows 以外的任何操作系统上都简单得多。在 Mac OSX 和任何 Linux 发行版上,我发现sn
在路径中。使用GetFrameworkSdkPath
在这种情况下没有帮助;事实上,这似乎返回了一条路径sn
找不到,至少对于我在使用xbuild时测试的旧版本的mono-2.10来说是这样:
- 在 Mac OSX 上
FrameworkSdkPath
is /Library/Frameworks/Mono.framework/Versions/2.10.5/lib/mono/2.0
and /usr/bin/sn
是一个符号链接/Library/Frameworks/Mono.framework/Commands/sn
.
- 在某个 Linux 安装上,
FrameworkSdkPath
is /usr/lib64/mono/2.0
and sn
is /usr/bin/sn
(这是一个调用的 shell 脚本/usr/lib64/mono/4.0/sn.exe
with mono
).
因此,我们需要做的就是尝试执行sn
。任何 Unix 用户将他们的sn
非标准位置的实现已经知道适当更新 PATH,因此构建脚本无需搜索它。还,WHERE
在unix中不存在。因此,在 unix 情况下,我们要替换第一个<Exec/>
调用会输出的东西sn
在 UNIX 上运行时仍然执行完整搜索。为了区分类 UNIX 环境和 Windows 环境,我们使用了一个技巧,该技巧利用了 Unix shell 的快捷方式true
命令和 cmds 标签语法。作为一个简短的示例,以下脚本将输出I’m unix!
在 unix shellout 中和I’m Windows :-/
在 Windows shellout 上。
:; 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 > 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 工具。