NAnt 和双平台构建 - 在 Windows 和 Mono/Linux 上构建的最佳方式
-
09-06-2019 - |
题
我是 NAnt 新手,但对 Ant 和 CruiseControl 有一些经验。
我想做的是让我的 SVN 项目包含所需的所有工具(如 NUnit 和 Mocks 等),这样我就可以检查到新机器并进行构建。J.P Boodhoo 概述了这一策略 这里。
到目前为止,如果我只想在 Windows 上运行,那就太好了,但我也希望能够在 Linux 上运行并针对 Mono 进行构建/测试/运行。我不希望 SVN 项目外部有任何依赖项。我不介意项目中有两套工具,但只想要一个 NAnt 构建文件
这一定是可能的——但是如何实现呢?有哪些技巧/“年轻球员的陷阱”
解决方案
这不应该是一个特别困难的练习。我们在我的一个项目中做了一些相当类似的事情,因为其中一半在 Java 上运行,使用 Ant 来运行相关目标,另一半是用于 UI 的 .Net (C#)。项目在 Windows 机器上运行进行开发,但服务器(Java)运行 Linux,但在 UAT 环境(Linux)中我们需要运行 nunits(集成测试)。这背后真正的技巧(实际上并不是一个困难的技巧)是拥有一个可以在两种环境中运行的 NAnt 构建文件,这似乎与您在这里尝试做的事情相同。
当然,您意识到您需要首先在 Mono 上安装 NAnt:
$ export MONO_NO_UNLOAD=1
$ make clean
$ make
$ mono bin/NAnt.exe clean build
然后你的构建文件需要以分离关注点的方式编写。例如,为 Windows 编写的构建文件的某些部分在 Linux 中无法工作。因此,您实际上只需将其划分为构建文件中的特定目标即可。之后,您可以通过多种方式从命令行运行特定目标。一个例子可能如下所示:
<project name="DualBuild">
<property name="windowsDotNetPath" value="C:\WINDOWS\Microsoft.NET\Framework\v3.5" />
<property name="windowsSolutionPath" value="D:\WorkingDirectory\branches\1234\source" />
<property name="windowsNUnitPath" value="C:\Program Files\NUnit-Net-2.0 2.2.8\bin" />
<property name="monoPath" value="You get the idea..." />
<target name="BuildAndTestOnWindows" depends="WinUpdateRevision, WinBuild, WinTest" />
<target name="BuildAndTestOnLinux" depends="MonoUpdateRevision, MonoBuild, MonoTest" />
<target name="WinUpdateRevision">
<delete file="${windowsSolutionPath}\Properties\AssemblyInfo.cs" />
<exec program="subwcrev.exe" basedir="C:\Program Files\TortoiseSVN\bin\"
workingdir="${windowsSolutionPath}\Properties"
commandline="${windowsSolutionPath} .\AssemblyInfoTemplate.cs
.\AssemblyInfo.cs" />
<delete file="${windowsSolutionPath}\Properties\AssemblyInfo.cs" />
<exec program="subwcrev.exe" basedir="C:\Program Files\TortoiseSVN\bin\"
workingdir="${windowsSolutionPath}\Properties"
commandline="${windowsSolutionPath} .\AssemblyInfoTemplate.cs
.\AssemblyInfo.cs" />
</target>
<target name="WinBuild">
<exec program="msbuild.exe"
basedir="${windowsDotNetPath}"
workingdir="${windowsSolutionPath}"
commandline="MySolution.sln /logger:ThoughtWorks.CruiseControl.MsBuild.XmlLogger,
ThoughtWorks.CruiseControl.MsBuild.dll;msbuild-output.xml
/nologo /verbosity:normal /noconsolelogger
/p:Configuration=Debug /target:Rebuild" />
</target>
<target name="WinTest">
<exec program="NCover.Console.exe"
basedir="C:\Program Files\NCover"
workingdir="${windowsSolutionPath}">
<arg value="//x "ClientCoverage.xml"" />
<arg value=""C:\Program Files\NUnit-Net-2.0 2.2.8\bin
\nunit-console.exe"
MySolution.nunit /xml=nunit-output.xml /nologo" />
</exec>
</target>
<target name="MonoUpdateRevision">
You get the idea...
</target>
<target name="MonoBuild">
You get the idea...
</target>
<target name="MonoTest">
You get the idea...
</target>
</project>
为了简洁起见,我将双方都排除在外。巧妙的是,您可以在这两种环境中使用 NUnit 和 NAnt,从依赖关系的角度来看,这使得事情变得非常简单。对于每个可执行文件,您可以替换为在该环境中工作的其他可执行文件,例如(xBuild 用于 MSBuild,svn 用于 tortoise 等)
有关 Mono 上 Nunit 等的更多帮助,请查看 这个很棒的帖子.
希望有帮助,
干杯,
罗布·G
其他提示
@Rob G - 嘿!这就是我的帖子!;)
对于其他一些好的示例,请务必浏览 NUnit 源代码。只要有可能,我都会与 Charlie 密切合作,以确保它在 Mono 上构建和测试。只要有可能,他也会尝试跑步。
值得注意的是,像 Nant 这样的许多工具都是“开箱即用”地在单声道上运行,即
mono nant.exe
作品
我使用以下模板。它允许在任何平台上进行简单的构建(build
在赢或 ./build.sh
在 Linux 上)并最大限度地减少构建脚本中的重复。
NAnt 可执行文件与项目一起存储在 tools\nant
.
构建配置文件确定要使用哪个构建工具,MSBuild 或 xbuild(在本例中,对于 Windows,我需要 VS2015 MSBuild 版本,请根据需要更改路径)。
这 build-csproj
当解决方案中有多个项目时,可以重用构建目标。
这 test-project
需要根据您的需求扩展目标。
构建.bat
@tools\nant\nant.exe %*
构建.sh
#!/bin/sh
/usr/bin/cli tools/nant/NAnt.exe "$@"
默认构建
<?xml version="1.0"?>
<project name="MyProject" default="all">
<if test="${not property::exists('configuration')}">
<property name="configuration" value="release" readonly="true" />
</if>
<if test="${platform::is-windows()}">
<property name="BuildTool" value="C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" readonly="true"/>
</if>
<if test="${platform::is-unix()}">
<property name="BuildTool" value="xbuild" readonly="true"/>
</if>
<property name="TestTool" value="tools/mytesttool.exe"/>
<target name="all" depends="myproject myprojectlib" />
<target name="build-csproj" description="Build a given csproj">
<!-- Must not be called standalone as it requires some properties set. -->
<exec program="${BuildTool}">
<arg path="src/${ProjectName}/${ProjectName}.csproj" />
<arg line="/property:Configuration=${configuration}" />
<arg value="/target:Rebuild" />
<arg value="/verbosity:normal" />
<arg value="/nologo" />
</exec>
</target>
<target name="test-project">
<!-- Must not be called standalone as it requires some properties set. -->
<exec program="${TestTool}">
<arg path="my/${ProjectName}/tests/path/for/tool" />
<arg value="/aproperty=value" />
</exec>
</target>
<target name="myproject" description="Build the project">
<property name="ProjectName" value="MyProject"/>
<call target="build-csproj" />
<call target="test-project" />
</target>
<target name="myprojectlib" description="Build the project's library dll">
<property name="ProjectName" value="MyProjectLib"/>
<call target="build-csproj" />
<call target="test-project" />
</target>
</project>