I've created a custom workflow for my build process in TFS that is using the MSBuild activity.
For some reason in the output folder I'm getting config files for all of my class library projects. Since I only need the app config file for project I'm actually building, is there a command line argument to prevent MSBuild from creating the [library].dll.config files in the output directory?
I wasn't able to find any msbuild arguments that caused this behavior, so I just gave up and added this to the end of the csproj file:
<Target Name="AfterBuild">
<ItemGroup>
<DeleteAfterBuild Include="$(OutDir)*.dll.config" />
</ItemGroup>
<Delete Files="#(DeleteAfterBuild)" />
</Target>
Related
I'm attempting to use TFS and MSBuild as a build and source control for a non-.NET project. This project contains a series of individual called .skbsrc files, that each compile into a .skb file. I'm trying to figure out if it's possible to use MSBuild in a way to build these files.
Say I'm using the example on the msdn website:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Compile Include="testfile.skbsrc" />
</ItemGroup>
<Target Name="Build">
<Csc Sources="#(Compile)"/>
</Target>
</Project>
Csc is clearly used for C# code, and runs the csc.exe program. Is there a way I can make a block like this for my own compiler (skbuilder) so I could run like:
<Skbuilder Sources="#(Compile)" />
which in turn would run
>skbuilder testfile.skbsrc
If this is possible with msbuild, could anyone post an example? I've been unable to find anything in my searches.
Thank you so much.
You can create a customized task in msbuild to do it. "CSC" is a default task in C#, so what you need is to implement a similar task for your exe.
This MSDN article explains how to write a task for msbuild.
Take a look at the Exec Task.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<SourceFiles Include="*.skbsrc"/>
</ItemGroup>
<Target Name="Build">
<Exec Command="skbuilder "%(SourceFiles.Identity)""/>
</Target>
</Project>
You'll also need to pass an argument to your skbuilder program telling it to output it's files to the $(OutDir) directory or use Copy Task to pick up *.skb to $(OutDir). Use quotes around the argument incase the TFS workspace path has spaces in it.
Finally you can test this on your own machine without using TFS by creating a simple .BAT file:
set PATH=%CD%;C:\Windows\Microsoft.NET\Framework\v4.0.30319
msbuild build.proj > build.log
In my C++ project, Test.wcxproj, I have the following configurations defined:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
Then I have the problematic import of the default C++ properties:
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
When my build server builds my MSBuild project file (configuration is Release and platform is Any CPU), I get this error:
error MSB4019: The imported project "C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110\Microsoft.Cpp.Default.props" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.
The relevant parts of my MSBuild project file look like this:
<ItemGroup>
<ProjectFiles Include="$(MSBuildProjectDirectory)\**\*.csproj" />
<ProjectFiles Include="$(MSBuildProjectDirectory)\**\*.vcxproj" />
</ItemGroup>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>x64</Platform>
<OutputFolder>$(MSBuildProjectDirectory)\BuildOutput\$(Configuration)</OutputFolder>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)</SolutionDir>
</PropertyGroup>
...
<Target Name="Compile">
<MSBuild Projects="#(ProjectFiles)" Targets="Build" Properties="Configuration=$(Configuration);Platform=$(Platform);OutputPath=$(OutputFolder)\$(MSBuildProjectName);SolutionDir=$(SolutionDir)\" />
</Target>
The problem
In my MSBuild project file, I am using ToolsVersion="12.0". Visual Studio 2013 is indeed installed, so I don't understand why it chooses to use v4.0\v110. Are my project configurations for some reason skipped by MSBuild? I guess I could somehow override this folder using the /p switch, but I want my .proj file to be self-contained.
Try to set up environment variable
VisualStudioVersion=12.0
or pass it explicitly as property to msbuild on commandline
msbuild.exe <project or solution to build> /p:VisualStudioVersion=12.0
I think it is because Microsoft tries to keep compatibility with older Visual Studios.
see Visual Studio project compatibility and VisualStudioVersion
In my case, my build definition was configured to build my .sln file instead of my .proj file. I remember configuring it to build the MSBuild project, but somehow it seems to have reverted to the Solution.
Anyway, I found two solutions to the problem:
Make sure to build the .proj file (where the tools version is indeed set to 12.0).
Explicitly set the VCTargetsPath.
I have several build files which all import the same base build file, like this:
base.xml:
<project name="base">
<!-- does not define a 'build' target -->
</project>
buildA.xml:
<project name="buildA">
<import file="base.xml" />
<target name="build">
<ant antfile="buildB.xml" target="build"
inheritall="false" inheritrefs="false" />
</target>
</project>
buildB.xml:
<project name="buildB">
<import file="base.xml" />
<target name="build">
...snip...
</target>
</project>
(Module A depends on module B.)
Now, the above calling of B's build target from buildA.xml gives the following error:
Duplicated project name in import. Project base defined first in buildA.xml and again in buildB.xml
Since both buildA.xml and buildB.xml inherit the same base.xml, this seems unavoidable.
How could I get rid of this error?
Based on sudocode's answer, I solved the problem. Because the absolute path to base.xml is different in both cases, Ant does not recognize it as the same file. Even though inheritAll is set to false, the context of the calling task is preserved and this causes the name clash.
To solve this, one can omit the name attribute from base.xml. Since Ant 1.8, the import task has an attribute as, which can be used to reference base targets when the base project is nameless. If you don't override any targets, you can use include instead of import. I'm on 1.7, so that does not help me.
For previous versions of Ant, you can go through an exec call to prevent proliferation of the Ant context entirely (then you get two running Ant instances). Better yet, find a way to import the exact same base.xml (with the same absolute path) in both files.
Are you using Ant 1.6? This resolved Ant bug looks like the same issue.
EDIT
I tried to reproduce the dir structure you refer to in your recent comment.
./base.xml
./buildA
./buildA/buildA.xml
./buildB
./buildB/buildB.xml
And amended the build files accordingly, e.g.
<project name="buildA">
<import file="../base.xml"/>
<target name="build">
<ant antfile="../buildB/buildB.xml" target="build" inheritall="false" inheritrefs="false"/>
</target>
</project>
I still get no build error for the following with ant 1.8.2 or 1.7.1:
ant -f buildA/buildA.xml build
We use ajaxmin to create .min.js files from all our .js files. We have edited the .csproj file of the project and added following:
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\MicrosoftAjax\ajaxmin.tasks" />
<Target Name="AfterBuild">
<ItemGroup>
<JS Include="**\*.js" Exclude="**\*.min.js" />
</ItemGroup>
<AjaxMin JsSourceFiles="#(JS)" JsSourceExtensionPattern="\.js$" JsTargetExtension=".min.js" />
</Target>
This works great when we build the site on our workstation and the .min.js files can be used in the site. When we check this project in this task runs also on the msbuild server but the .min.js files generated by ajaxmin are not copied to the drop location of the tfs2010 Rolling Build we use. These .min.js files are also not included into the package we create during this rolling build and which is also copied to the drop location. Only the files included into the project are used for the package and copied to the drop location.
The MSBuild Arguments we use to create the package are the following:
/p:DeployOnBuild=True /p:DeployTarget=MsDeployPublish /p:MSDeployPublishMethod=InProc /p:CreatePackageOnPublish=True /p:MSDeployServiceURL=localhost
I've tried several things as adding an extra build task to copy all the .min.js files to the location where the package is created. I tried also the following url http://sedodream.com/2010/05/01/WebDeploymentToolMSDeployBuildPackageIncludingExtraFilesOrExcludingSpecificFiles.aspx to include this files with the following in my .csproj file:
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
<Target Name="CustomCollectFiles">
<ItemGroup>
<_CustomFiles Include="**\*.min.js" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
Has anyone else also this problem or does anyone have an idea how to include the *.min.js files in the msdeploy package and make the files copy to the drop location?
You missed the destination directory so all you have to do is creating pair folders for each script in your script folder, source and destination to make sure you didn't copy all the min files to each folder in your project according to the script folder structure of your project, any way I write an article and who how to do that, you can also download project that do that, http://mohamedradwan.wordpress.com/2010/11/12/how-to-include-minify-files-or-custome-files-with-web-pagckage-or-ms-deploy-package/
Thanks
Is there a well-established way to share Ant targets between projects? I have a solution currently, but it's a bit inelegant. Here's what I'm doing so far.
I've got a file called ivy-tasks.xml hosted on a server on our network. This file contains, among other targets, boilerplate tasks for managing project dependencies with Ivy. For example:
<project name="ant-ivy-tasks" default="init-ivy"
xmlns:ivy="antlib:org.apache.ivy.ant">
...
<target name="ivy-download" unless="skip.ivy.download">
<mkdir dir="${ivy.jar.dir}"/>
<echo message="Installing ivy..."/>
<get src="http://repo1.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar"
dest="${ivy.jar.file}" usetimestamp="true"/>
</target>
<target name="ivy-init" depends="ivy-download"
description="-> Defines ivy tasks and loads global settings">
<path id="ivy.lib.path">
<fileset dir="${ivy.jar.dir}" includes="*.jar"/>
</path>
<taskdef resource="org/apache/ivy/ant/antlib.xml"
uri="antlib:org.apache.ivy.ant"
classpathref="ivy.lib.path"/>
<ivy:settings url="http://myserver/ivy/settings/ivysettings-user.xml"/>
</target>
...
</project>
The reason this file is hosted is because I don't want to:
Check the file into every project that needs it - this will result in duplication, making maintaining the targets harder.
Have my build.xml depend on checking out a project from source control - this will make the build have more XML at the top-level just to access the file.
What I do with this file in my projects' build.xmls is along the lines of:
<property name="download.dir" location="download"/>
<mkdir dir="${download.dir}"/>
<echo message="Downloading import files to ${download.dir}"/>
<get src="http://myserver/ivy/ivy-tasks.xml" dest="${download.dir}/ivy-tasks.xml" usetimestamp="true"/>
<import file="${download.dir}/ivy-tasks.xml"/>
The "dirty" part about this is that I have to do the above steps outside of a target, because the import task must be at the top-level. Plus, I still have to include this XML in all of the build.xml files that need it (i.e. there's still some amount of duplication).
On top of that, there might be additional situations where I might have common (non-Ivy) tasks that I'd like imported. If I were to provide these tasks using Ivy's dependency management I'd still have problems, since by the time I'd have resolved the dependencies I would have to be inside of a target in my build.xml, and unable to import (due to the constraint mentioned above).
Is there a better solution for what I'm trying to accomplish?
If you are using ANT 1.8+, then you could just import the build.xml directly from the hosted location.
http://ant.apache.org/manual/Tasks/import.html
Since Ant 1.8.0 the task can also
import resources from URLs or
classpath resources (which are URLs,
really). If you need to know whether
the current build file's source has
been a file or an URL you can consult
the property ant.file.type.projectname
(using the same example as above
ant.file.type.builddocs) which either
have the value "file" or "url".
<!-- importing.xml -->
<project name="importing" basedir="." default="...">
<import file="http://myserver/ivy/ivy-tasks.xml"/>
</project>
If you use Antlibs you can package them all inside a JAR file. Then simply copy this file into the ${ANT_HOME}/lib directory to use them.
After some additional searching, a possible solution would be to use SVN externals to check out specific required files that may be needed by the build.xml.
However, this would only work for users who are using Subversion as source control. It would still be nice to have a SCM-agnostic solution for users who aren't using Subversion, or another SCM that supports similar functionality.
What we've done is to create a project called 'bootstrap' which contains the various xml-files needed for the other projects at our office.
So to set up your development environment you run build.xml in bootstrap which copies the xml-files (like your ivy-stuff, and other targets) to a known location, and then your build files include these like this:
<import file="${ant.bootstrap.dir}/ant-commons.xml" />
<import file="${ant.bootstrap.dir}/ant-commons-ear.xml" />
Our bootstrap build.xml contains this:
<target name="install">
<fail unless="ant.bootstrap.dir" message="ant.bootstrap.dir ${missing.property.message}"/>
<copy todir = "${ant.bootstrap.dir}">
<fileset dir = "src/xml"/>
</copy>
</target>