I had a .NET 1.1 project, which I built in NAnt using the following snippet:
<property name="Refs.dir" value="Refs" readonly="false"/>
<property name="OAIDLLs.dir" value="OAI\bin\ServerDebug"/>
<solution
solutionfile="OAI\CC.OAI.sln"
configuration="ServerDebug"
outputdir="${OAIDLLs.dir}">
<assemblyfolders>
<include name="${Refs.dir}"/>
</assemblyfolders>
</solution>
Now someone has converted the project to .NET 2.0, and NAnt can't build it anymore.
It's easy enough to replace the solution tag with
<exec program="msbuild">
<arg value="OAI\CC.OAI.sln" />
</exec>
but I can't figure out how to pass value in assemblyfolders tag to msbuild. For those who don't know, assemblyfolders tag specifies the folder where the project should look for dependent assemblies.
One can specify additional properties with a /p switch. The properties that might be of interest here are:
AdditionalLibPaths - Specifies additional folders in which compilers should look for reference assemblies.
AssemblySearchPaths - A list of locations to search during build-time reference assembly resolution. The order in which paths appear in this list is meaningful because paths listed earlier takes precedence over later entries.
To specify additional properties using msbuild with the exec task:
<exec program="msbuild">
<arg value="OAI\CC.OAI.sln" />
<arg value="/p:AssemblySearchPaths=c:\path1" />
</exec>
As a side there is an msbuild task that is provided with NAntContrib.
Related
I've been using Sandcastle Help File Builder for a while to generate documentation - I'm now trying to get it to be part of our build process. Our build is controlled using NAnt, and each time it's built the output gets sent to a different location (based on changeset numbers, so we can have concurrent builds without clashes) - ie the dlls are not in a fixed path relative to the source code.
I've added a target into the NAnt script to call SHFB, which invokes the msbuild task, pointing at the solution that contains the SHFB project:
<target name="GenerateDocumentation">
<msbuild
project="${SourceURL}\Documentation\API Documentation\APIs.sln"
verbosity="Detailed">
<property name="OutputPath" value="${OutputPath}Documentation" />
<property name="ReferencePath" value="${OutputPath}wwwroot\\bin\\" />
</msbuild>
</target>
I've specified the ReferencePath property, as on this page, it seems to indicate that this would allow SHFB to find the assemblies and use them, rather than relying on the information in the original project file:
If the ReferencePath property is defined, it will be passed to and used by GenerateRefInfo.proj when generating reflection information. This allows you to specify an alternate path in which to find reference assemblies that will override hint paths in the project file.
However when the build reaches this point, it fails with the following error:
SHFB: Error BE0040: Project assembly does not exist: D:\Build\Debug\wwwroot\bin\MyAssembly.dll
Which is the default output path specified in the original project.
What is the correct mechanism for passing the location of the assemblies into SHFB?
Turns out that using OutDir instead of ReferencePath is the way to go:
<target name="GenerateDocumentation">
<msbuild
project="${SourceURL}\Documentation\API Documentation\APIs.sln"
verbosity="Detailed">
<property name="OutputPath" value="${OutputPath}Documentation" />
<property name="OutDir" value="${OutputPath}wwwroot\bin\\" />
</msbuild>
</target>
Also note that the path specified in OutDir must end in a double slash, otherwise MSBuild attempts to concatenate it with the project path
I am using Msbuild 4.0.
In our project few solution are having .net 3.5 projects.
When i compile it through Visual studio it works. If i build the same using Msbuild it fails.
Following is the compilation issue:
error : Compilation failed. Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
Exception from HRESULT: 0x80131515
Even i tried with changing
toolsversion to 3.5
through additionalproperties of item. [ I am using Msbuild task to build my solution]
Our Msbuild task looks like below.
<Target Name="BuildDotNETSolutions" Condition="'$(Group)' != ''" DependsOnTargets="Init;GetNextVersionNumber">
<!-- Complie solutions -->
<!-- Version property is useful for changing the Wix Msi version-->
<MSBuild Projects="#(Solution)" BuildInParallel="true"
Properties="Configuration=$(Configuration);PostbuildEvent=;Version=$(BuildNextVersionNumber)"
Condition="'%(Solution.Group)' == '$(Group)' And '%(Solution.Type)' == 'DotNET' And '%(Solution.IsRebuild)'=='$(IsRebuild)'">
<Output
TaskParameter="TargetOutputs"
ItemName="BuildOutputs" />
</MSBuild>
We are passing solutions through properties file like below
<Solution Include="$(Implementation)\MultiEvent.csproj;">
<Group>Event</Group>
<AdditionalProperties>
ReferencePath=$(Implementation)\References;
ToolsVersion=3.5;
</AdditionalProperties>
<IsRebuild>True</IsRebuild>
<Type>DotNET</Type>
</Solution>
I don't know if you happen to have any script-runner that runs MSBuild. Personnally, I'm using NAnt and everything is working fine. I've read (somewhere) that MSBuild sometimes do stupid things and by adding the property "TrackFileAccess" and set it to "false" helps a lot. In my case, it fixed the problem.
If it can be of any help, I've included my NAnt build task. I hope it can be useful to you.
<!--*******************************************************************************
Runs MSBuild to build the project solution
Arguments:
${MSBuild.exe}: Path to MSBuild.exe
${project.solution}: the solution name to build
${buildconfiguration}: The build configuration to trigger the build
${build.dir} : The directory where to put builded files
********************************************************************************-->
<target name="run.msbuild" description="Rebuilds a given solution file">
<echo message="Rebuilding Solution ${project.solution}" />
<echo>${MSBuild.exe}</echo>
<exec program="${MSBuild.exe}">
<arg value="${project.solution}"/>
<arg line="/property:SignAssembly=${project.sign},AssemblyOriginatorKeyFile=${project::get-base-directory()}\${project.signature.file}" />
<arg line="/property:OutDir=${build.dir}" />
<arg line="/property:TrackFileAccess=false" />
<arg line="/property:DebugType=${debug.type}" />
<arg line="/property:Platform="Any CPU"" />
<arg line="/nologo" />
<arg line="/verbosity:minimal" />
<arg line="/property:Configuration=${buildconfiguration}"/>
</exec>
in the case of a Development build, I set the following params :
<property name="buildconfiguration" value="Debug"/>
<property name="debug.type" value="full" />
I have the following NANT CSC target for building winexe:
<csc target="winexe" output="${Deploy.dir}\VMIS.exe" debug="${debug}">
<sources>
<include name="${App.dir}\**\*.cs" />
<include name="${Build.dir}\AssemblyInfo.cs" />
<exclude name="${App.dir}\**\AssemblyInfo.cs" />
</sources>
<references refid="Lib.fileset">
</references>
...
</csc>
The following is the failure message:
D:\..\myClass.cs(9,17): error CS0234: The type or namespace name 'Reporting'
does not exist in the namespace 'Microsoft' (are you missing an assembly
reference?)
In myClass.cs, I have this using reference:
using Microsoft.ReportViewer.WinForms;
There is no problem to build my app in VS, but I could not build from NANT. I think that I may miss reference to Microsoft.ReportViewer.WinForms.dll in NANT build. Not sure how I can include this dll in my bin for NANT?
I have tried to modify csc target's references:
<csc ...>
...
<references refid="Lib.fileset">
<include name="Microsoft.ReportViewer.Common.dll" />
<include name="Microsoft.ReportViewer.WinForms.dll" />
</references>
...
</csc>
Still not working. Should I use COPY target to copy all the dll files from bin to $(build.dir)?
Updates: I found that those Microsoft.ReportViewer.xx.dll files in project references are not copy to local. How can I simulate copy to local in NANT for those two dll files? I guess that may resolve the issue since NANT is a build app in console and does not have knowledge about references in global cache.
NAnt is configured with the default set of DLLs for the .NET framework, and knows where those DLLs reside (e.g. C:\Windows\Microsoft.NET\Framework64\v4.0.30319). When you include non-framework assemblies, whether they are yours or a 3rd party, you can include them, but use the full path of the DLL:
<include name="C:\Common\ThirdParty.dll" />
You can also use variables:
<property name="common.directory" value="C:\Common" />
...
<csc ...>
...
<references>
<inclde name="${common.directory}\ThirdParty.dll" />
</references>
</csc>
Recommended:
Use MSBuild in your NAnt script(s) to build your application.
FYI: Visual Studio uses MSBuild to compile and build your solution and projects.
<!-- Verify the right target framework -->
<property name="MSBuildPath" value="C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe" />
<target name="Build">
<exec program="${MSBuildPath}">
<arg line='"${SolutionFile}"' />
<arg value="/target:Rebuild" />
<arg value="/verbosity:normal" />
<arg value="/nologo" />
</exec>
</target>
Possibility:
Copy references/files locally (i.e. using copy task). Or similarly use full paths in the include name.
Not recommended:
Use NAnt's "solution" task, or NAntContrib's "msbuild" task.
This would simplify the msbuild call but would tie you into older versions of msbuild/VS solution/project files. Newer VS solution/project files would not be supported readily.
Hope it helps.
I am using team city to call a nant script, currently this nant script is very simplistic and only calls an msbuild task on a single project in the solution.
The build is failing, it looks like msbuild 3.5 is being called, but it is incorrectly calling the csc.exe from the .net 2.0 folder. Since we are using .net 3.5 language features the compilation fails.
Looking at the csproj file, both the ToolsVersion and TargetFrameworkVersion are both set to use 3.5. What would be causing msbuild to pick the wrong version of csc.exe?
MSBuild uses a Toolset of tasks, targets, and tools to build an application. Typically, a MSBuild Toolset includes a microsoft.common.tasks file, a microsoft.common.targets file, and compilers such as csc.exe and vbc.exe. To ensure MSBuild invokes the correct C# compiler (csc.exe), specify the Toolset in the ToolsVersion attribute on the Project element in the project file.
The following example specifies that the project should be built by using the MSBuild 4.0 Toolset.
<Project ToolsVersion="4.0" ... </Project>
More information pertaining to the ToolsVersion attribute can be found here:
http://msdn.microsoft.com/en-us/library/78f4aasd.aspx
Do you have the 2.0 version of csc directly in your path, perhaps?
What happens when you run msbuild from a Visual Studio 2008 Command Prompt?
You can directly point which msbuild you want to use in nant script by declaring:
<!-- Initial path to use MSBuild from .NET Framework 3.5 -->
<property name="MSBuildApp" value="C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe" />
And then execute build via msbuild:
<exec failonerror="true" program="${MSBuildApp}" verbose="true">
<arg value="${SlnDir}\${SlnFile}" />
<arg value="/t:Rebuild" />
<arg value="/p:Configuration=${SlnConfig}" />
</exec>
Or you can point to proper .NET framework version when running NANT script:
nant CreateYouProjectTask -t:net-3.5 -buildfile:BuildYourProject.build
I'm new to NAnt and have been able to create a <target> which
1) Deletes any code from the current folder
2) Exports fresh code from SVN
3) Builds the code in the default directory which is the PrecompiledWeb folder (its a web app)
Here it is:
<target name="export" description="export code from svn">
<delete dir="${Delete.Dir}"></delete>
<exec program="svn" commandline="export ${MySVN.Repos} ${MySVN.Dest}" />
<msbuild project="${Solution.Filename}">
<property name="Configuration" value="Release"/>
</msbuild>
</target>
I want to specify a custom output directory (other than "PrecompiledWeb"). Is this possible and could you please show me the necessary tag/property?
Thank you!
EDIT
Thanks to Scott and Si, I'm getting closer to a solution, but I still don't have anything that works. There comments led me to this article on MSBuild's Output Path Property. Using their code:
<?xml version="1.0"?>
<project name="test" default="build" basedir="." xmlns="http://nant.sf.net/schemas/nant-0.84.win32.net-1.0.xsd">
<target name="build">
<exec program="${framework::get-framework-directory('net-3.5')}/msbuild.exe">
<arg value="${Full.Path}\Code\MySolution.sln" />
<arg value="/p:OutputPath=${Full.Path}\Output\" />
</exec>
</target>
</project>
This will sucessfully run; however, in my solution which contains a web site and a class library, it publishes the class library dll to the specified output path, but it still publishes the actual web site to the default PrecompiledWeb folder.
Does anyone have any suggestions for how to change the PrecompiledWeb folder path from NAnt?
Thanks again to everyone who's helped!
Edit 2 Final Solution
Here is what I finally was able to get working (updated for .net 4):
<exec program="${framework::get-framework-directory('net-4.0')}/msbuild.exe">
<arg value="${Full.Path}\Code\MySolution.sln" />
<arg value="/t:Rebuild" />
<arg value="/t:ResolveReferences" />
<arg value="/t:_CopyWebApplication" />
<arg value="/p:OutDir=${Build.Output}bin\" />
<arg value="/p:WebProjectOutputDir=${Build.Output}" />
<arg value="/p:Configuration=Release" />
</exec>
One can specify and override some of properties for msbuild. In order to specify the output directory, override the OutputDir property.
<target name="export" description="export code from svn">
<delete dir="${Delete.Dir}" />
<exec program="svn" commandline="export ${MySVN.Repos} ${MySVN.Dest}" />
<msbuild project="${Solution.Filename}">
<property name="Configuration" value="Release"/>
<property name="OutputDir" value="${Output.Dir}"/>
</msbuild>
</target>
Just had a quick peek at a project, does OutputPath instead of OutputDir help?
Another option might be a web deployment project, which I like because it calls aspnet_compiler as well as the C# compiler, so it picks up issues which you may otherwise miss until deployment.
A build script for one of our projects uses this command to publish a web application:
msbuild.exe /t:_CopyWebApplication /p:Configuration=Release /p:OutDir=.\..\published\ /p:WebProjectOutputDir=.\..\published
(The current directory is set to the web app's project directory at this point, which is why no .csproj file is specified. The entire solution has already been rebuilt earlier in the script.)
By the sound of it, WebProjectOutputDir might be the property you need.
/t:_CopyWebApplication may also be important. I've not used NAnt so I don't know if you can pass this parameter with the msbuild task. You may need to use an exec task, like in this example: http://www.netomatix.com/development/wapwithnant.aspx. This example appears to rebuild and copy all in one go.
When using the task, the correct property name is OutDir, not OutputDir:
<msbuild project="${Solution.Filename}">
<property name="Configuration" value="Release"/>
<property name="OutDir" value="${Output.Dir}"/>
</msbuild>
A source of confusion is that you're blending two distinct build systems. Your NAnt target is delegating all the work of figuring out how to publish your web application to the solution file, hence by extension to the csproj files it references.
csproj files are MsBuild files, so you should probably look there for how to direct your project output. This post by dave^2 might be helpful on that issue.
You can publish your web application wherever you want using NAnt, provided it's doing the publishing. You can do the same with MsBuild. The cause of your quandary is that NAnt is not doing the publishing in this case, and you're letting the csproj file determine the location of your web directory. So either bypass the csproj file and have NAnt (or MsBuild) publish the code; or modify the csproj file to publish the web application where you want; or make a second location for your web application and publish it there as well using your build tool.
AFAIK, those options are exhaustive.
Hmm, don't know how to do it with MSBuild in Nant, but using NAnt, I've done it previously like this:
<solution solutionfile="${build.dir}\solution.sln">
<webmap>
<map url="http://localhost/somdir/project.csproj"
path="c:\inetpub\wwwroot\somelocaldir" />
<webmap>
</solution>
But then, you're using the NAnt 'solution' task offcourse instead of using MSBuild directly.
edit:
I'm also having a look at some msbuild options;
If you set OutDir & OutputPath to the same value, what happens ?
Try something like this:
<property name="nant.settings.currentframework" value="net-3.5"/>
<msbuild project="${Solution.Filename}">
<property name="Configuration" value="Release"/>
<property name="OutDir" value="${Full.Path}\Output\\"/>
<property name="WebProjectOutputDir" value="${Full.Path}\Output\Web\\"/>
</msbuild>