Monday, May 03, 2010

What do you need to build VC++ in 2010?

As you probably know, Visual C++ projects in VS 2010 use MSBuild to build. That works fine when you have Visual Studio installed, but can you build your C++ stuff without Visual Studio installed? One could build C#/VB projects with only .NET Framework installed, and prior to 2010, to build VC++ you only needed Windows SDK (that included headers, libraries, compilers and other goodies). So what is the story in 2010?

It turns out the story is similar in 2010 - you will need to have Windows SDK (for C++ specific bits) and .NET Framework 4.0 for vcxproj files. The only fly in the ointment is that Windows SDK is yet to be released (with target date somewhere in June 2010), so for now to build your C++ projects you will need to have Visual Studio installed.

Mirror from my MSDN blog

MSBuild resources reference page

.NET 4.0 and MSBuild 4.0 are out there now, but resources are still ramping up. So as a quick time saver, I have created the biggest most complete no-nonsense 100% satisfaction guarantee MSBuild resources reference page. :) That will be updated as newer content comes online. Enjoy!

Mirror from my MSDN blog.

Friday, May 01, 2009

MSBuild UsingTask gotchas

One significant drawback of MSBuild UsingTask element is that you must specify exactly the task name you are importing. That is if the assembly you are importing contains 200 tasks, you will have to import them explicitly one by one. And since you probably do not want to do that in every project you author, usually these 200 tasks will be defined in separate project file that can be imported whenever the tasks are needed.

While there is no workaround for specifying the task name, there is another, somewhat easier way to make sure that the tasks are available to your projects without explicitly importing tasks project file.

Let’s suppose that you have created MSBuild project file that contains UsingTask statements for all custom tasks you want to have available in your projects. Then if you rename this project file to have .tasks extension and place it in .NET framework folder (e.g. C:\WINDOWS\Microsoft.NET\Framework\v3.5 folder for .NET 3.5), the tasks defined there will be available in any project using that version of MSBuild without explicit import statement.

This is the mechanism used to make tasks shipped with MSBuild by default available to all projects (look into Microsoft.Common.tasks file to see these tasks defined there). No magick required!

By the way, looking into Microsoft.Common.tasks file imparts two additional pieces of wisdom (to quote):

NOTE: Listing a <UsingTask> tag in a *.tasks file like this one rather than in a project or targets file can give a significant performance advantage in a large build, because every time a <UsingTask> tag is encountered, it will cause the task to be rediscovered next time the task is used.

Another useful comment relates to the way the tasks are defined in UsingTask – you can either specify fully-qualified task name (including namespaces) or a short one; however, (again, quote from Microsoft.Common.tasks file):

NOTE: Using the fully qualified class name in a <UsingTask> tag is faster than using a partially qualified name.

In addition to performance win, you will also be able to disambiguate the task used. For example, both SDC tasks and MSBuild Community tasks packages define a bunch of tasks that differ only by name. In such cases you will have to be explicit both in UsingTask statement and when using the imported task:

<!-- Import SDC Sleep task -->
<UsingTask AssemblyFile="Microsoft.Sdc.Tasks.dll" 
          TaskName="Microsoft.Sdc.Tasks.Sleep"/>
<!-- Import MSBuild Community Sleep task -->
<UsingTask AssemblyFile="MSBuild.Community.Tasks.dll" 
          TaskName="MSBuild.Community.Tasks.Sleep" />
<!-- Use SDC Sleep task, full name to disambiguate -->
<Target Name="Sleep">
  <Microsoft.Sdc.Tasks.Sleep SleepTimeout="1"/>
</Target>

Mirror from MSDN blog

Monday, October 06, 2008

MSBuild Extension Pack is released!

MSBuild Extension Pack is the library of over 170 MSBuild tasks including

  • System Items: Certificates, COM+, Console, Date and Time, Drives, Environment Variables, Event Logs, Files and Folders, GAC, Network, Performance Counters, Registry, Services, Sound
  • Code: Assemblies, CAB Files, Code Signing, File Detokenisation, GUID’s, Mathematics, Strings, Threads, Zip
  • Applications: BizTalk 2006, Email, IIS7, MSBuild, SourceSafe, StyleCop, Team Foundation Server, Visual Basic 6, WMI

The library is authored by Mike Fourie, who has been very active in custom MSBuild tasks area for the last few years. And I mean active – he was the person who single-handedly maintained well-known SDC tasks library for the last year.

You might wonder – what is so different about this new project? Several points of note:

  • Extensive documentation – every task has example and a usage sample
  • Uniform implementation (since all tasks are implemented off the same base classes)
  • Remote execution support (where applicable)
  • Novel concept of TaskAction, that provides several related functions in the same task (f. e. <Folder TaskAction=”Remove”> would remove a folder as compared with <Folder TaskAction=”Rename”> renaming folder)
  • Last but not least, this project will probably have very high level of support. While MSBuild Extension Pack is stable (since it is based on several beta released of FreeToDev tasks), you still might need someone to communicate with – and judging by the awesome work Mike did with SDC tasks one might expect that the new project will be maintained well.

And if you have something to contribute, the project is at CodePlex which means that the contributors are welcome.

Tuesday, June 24, 2008

Automate workspace creation with MSBuild

And now as promised I shall script workspace creation. I will use MSBuild for this exercise (since it is way better looking and more convenient than batch files, and more standard than PowerShell); if you shied away from MSBuild previously may be it is time to get better acquainted :)

The task at hand is pretty simple: create new workspace and define set of mappings as specified per script; the user will pass workspace name and root folder for the mappings as an arguments to the script.

I will use tf command-line client with workspace and workfold commands for the purpose [while there are CreateWorkspace MSBuild tasks shipped as part of VSTS 2005/2008, they are not suitable for the purpose as the mappings cannot be specified as parameters to the task; 2005 version uses XML file and 2008 version uses Team Build database].

One thing to note before going into further details – when you use tf workspace /new to create a workspace, the default mapping is created (yes, no one asked for that, but tf does so nevertheless). That necessitates removal of that default root mapping as a first step after workspace creation.

So here goes the script (it is a longish one, but it is pretty self-descriptive):

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="CreateWorkspace"
  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!-- Default values for the properties the script  uses -->
  <PropertyGroup>
    <RootPath></RootPath>
    <WorkspaceName></WorkspaceName>
    <Tf>tf</Tf>
  </PropertyGroup>
  <!-- Workspace mappings to create -->
  <!-- Customize at will -->
  <ItemGroup>
    <WorkspaceMapping Include="$/Project1/Source">
      <LocalPath>$(RootPath)Source</LocalPath>
    </WorkspaceMapping>
    <WorkspaceMapping Include="$/Infra/Bin">
      <LocalPath>$(RootPath)Common</LocalPath>
    </WorkspaceMapping>
  </ItemGroup>
  <!-- Main target -->
  <Target Name="CreateWorkspace">
    <!-- Checking input parameters -->
    <Error Condition="$(WorkspaceName) == ''" 
          Text="Please specify WorkspaceName property"/>
    <Error Condition="$(RootPath) == ''" 
          Text="Please specify RootPath property"/>
    <Error Condition="!HasTrailingSlash('$(RootPath)')" 
          Text="Please make sure RootPath is slash terminated"/>
    <!-- Create new workspace-->
    <Exec Command="$(Tf) workspace /new /noprompt 
                    &quot;$(WorkspaceName)&quot;" />
    <!-- Remove default mapping -->
    <Exec Command="$(Tf) workfold /unmap 
                  /workspace:&quot;$(WorkspaceName)&quot; $/"/>
    <!-- Create new mappings (uses MSBuild batching) -->
    <Exec Command="$(Tf) workfold 
                /map &quot;%(WorkspaceMapping.Identity)&quot; 
                    &quot;%(WorkspaceMapping.LocalPath)&quot; 
                /workspace:&quot;$(WorkspaceName)&quot;"/>
    <!-- Great success! -->
    <Message Text="Workspace '$(WorkspaceName)' created sucessfully"/>
    <!-- List created mappings -->
    <Exec Command="$(Tf) workfold 
                /workspace:&quot;$(WorkspaceName)&quot;"/>
  </Target>
</Project>

To execute the script, fire up “VS 200x Command Prompt” and type the following:



msbuild CreateWorkspace.proj /p:WorkspaceName=VistaDevt /p:RootPath=c:\Vista\


Only caveat is that the folder the script located in cannot be mapped anywhere (as I noted above, tf workspace /new will try to map it and will fail).

If you are convinced that using script to create workspace is better than typing in the mappings, CreateWorkspace.proj is available for download here.

For completeness sake, it is worth mentioning /template argument of tf workspace command. If you want to copy somebody else’s workspace it is pretty attractive choice (or if you do not want to remember that somebody’s workspace name and AD user name, you can use Workspace Sidekick UI for the same purpose)

If you want to have “single-click” build, you may want to add to this script a) getting everything once workspace is created and b) building everything once get latest is finished. MSBuild makes both tasks very easy to achieve.

Tuesday, April 29, 2008

MSBuild goes famous, MSDN docs don't

It looks like MSBuild 3.5 got a new champion – none other than Scott Hanselman himself! He recently published two posts on how build time may be drastically improved on multi-core machines with new 3.5 multiprocessor support.

While I certainly like that additional visibility for MSBuild coming from the popular online author, for me it also indicates something else (not as positive) – most people become really allergic to MSDN content, to the point where they never read it. In later years, MSDN content tends to be late/incomplete/not helpful, so it ceased to be first resource you look into (for MS technologies, that is). And additionally, the visibility of MSDN content in the search engines results is so lame, the content may just as well be non-existent.

But for MSBuild, the content is there, and it provides very decent handling of various MSBuild topics. For example, speaking of 3.5 specific features:

Overall, MSDN MSBuild content node contains loads and loads of pertinent information. So I thought – what's the heck, I shall try to provide some visibility for the good stuff.

And speaking of content, if you are interested in everything MSBuild there is couple of must-have blogs to follow: MSBuild Team blog and Sayed Hashimi's blog. Oh, and probably Scott Hanselman will chime on as well, so make sure you keep reading his blog!

Friday, March 14, 2008

PowerShell and MSBuild get married

Do you use MSBuild much? Do you use (or plan to use) PowerShell? Then it might be a good time to spell out what kind of integration you expect between MSBuild and PowerShell – since Windows SDK team is asking for your comments for future versions of PowerShell.

And if you did not start on PowerShell yet – I'd recommend that post by John Robbins to get you started.

Monday, February 04, 2008

Building VS2008 projects in VS2005

Today I got reminded of one issue, that I did not mention in the previous post on VS2005 solutions and projects conversion to VS2005 (mostly because I was not aware of that at the time :).

As it is .Net projects created in VS2005 can be built both in 2005 and 2008 without any changes to the project file. However, should you create a new project in VS2008 (even one targeting .Net 2.0), you will not be able to build it in VS2005. The reason is that VS2008 project is created compliant with MSBuild 3.5, in which $(MSBuildBinPath) property (location of all system target files) is deprecated, and $(MSBuildToolsPath) is used instead. Thus VS2008 will use MSBuildToolsPath to specify the location of Microsoft.CSharp.targets file, and the project will promptly blow in VS2005 on build.

As far as I know, there is no elegant solution to this problem (short of changing the project file). Probably the easiest solution would be to create the projects in VS2005 (that is, if you want to have .Net 2.0 projects that can be opened in both versions of Visual Studio). If you do modify the project files, here is the snippet I use to make sure that the project can be built in both flavours of Visual Studio:

<!-- VS2008 original import (sans condition 

     which is added for VS2005 benefit) -->

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" 

        Condition="$(MSBuildToolsPath) != ''" />

<!-- VS2005 import - added for VS2005 compatibility 

     (since there is no ToolsPath there) -->

<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" 

        Condition="$(MSBuildToolsPath) == ''" />

Footnote: once you decide to use .Net 3.5 in your project on VS2008, then obviously your project wont build in VS2005 no matter the modifications.

Tuesday, January 29, 2008

Skipping post-build in VS project in Team Build

Interesting question has come up in the forums: "If one has custom pre- or post- build logic in Visual Studio projects, that are being built both on desktop and using Team Build, how one would disable the pre-/post-build for non-desktop build?".
Or to be more concise - is there any property available that makes it possible to detect, whether the build is being performed from Visual Studio or from Team Build process?

Now, Team Build build types will simply call MSBuild task with the solution(s) to build; will Team Build pass any custom properties to MSBuild with the solution files?

It turns out that Team Build does indeed pass such property, named TeamBuildConstants; thus when the solution will be built from the Team Build script, the property will get the value of _TEAM_BUILD_, as defined in Microsoft.TeamFoundation.Build.targets file.

Then Visual Studio project (C# and VB.NET alike) can be modified in the following manner:


<!-- Prebuild logic will be executed both in VS and Team Build compilations -->
<Target Name="BeforeBuild">
    <Exec Command="attrib -r $(TargetPath)"/>
</Target>

<!-- Postbuild logic that will not be executed in Team Build-->
<Target Name="AfterBuild" Condition="'$(TeamBuildConstants)' == ''">
    <Copy SourceFiles="$(TargetPath)"
      DestinationFolder="$(SolutionDir)\bin\$(ConfigurationName)" />
</Target>

Team Build targets file also exposes property with very tempting name - SkipPostBuild; however, modifying the property value in TFSBuild.proj will have no effect on the projects post build logic. Setting SkipPostBuild property to false disables running GenCheckinNotesUpdateWorkItems task during Team Build build, and thus has no connection to Visual Studio projects logic.

Saturday, December 01, 2007

Choices in conversion of solutions and projects to VS2008

On the weekend I am trying to catch up on my blogroll, and I have found several excellent posts on conversion between VS2005 and VS2008. Now that VS2008 is released, the conversion of code base from previous version will become a common problem, and here is some advise on dealing with that.

Of course simplest way would be just converting all solutions to VS2008 (see below why you do not have to convert projects). Here you have several choices:
- Open VS2005 solution in VS2008 and run the conversion wizard.
- Run VS2008 in command-line converting the solution in place in the background (that should be perfect if you have more than one solution :). Read more about magical command-line "/upgrade" switch in John Robbins blog post.
- Mess around with solution file in text editor. The difference between solution for VS2005 and VS2006 would be only the version specifier("Format Version 9.00" vs. "Format Version 10.00"). The difference in projects would be only MSBuild ToolsVersion attribute (that serves to define .NET toolset project is built with). Since all converted projects use 2.0, that can be easily set. Read in more detail about solution and project formats changes in DJ Park blog post.

Now, if you still need to do some development on VS2005 while doing development in VS2008 in the same solution, the best bet would be probably to create a new solution (e.g. "Solution_3.5.sln"). The projects that are using .NET 2.0 will build both in VS2005 and Orcas.

Personally, I will probably use the magnificent "/upgrade" command-line switch to convert all solutions while keeping in mind that I have an option to tweak the files by hand (sometimes it may come in handy if you need to quickly rollback certain solution to VS2005).

And another conclusion - reading blogs can be very useful and save lots of time :)

Saturday, November 17, 2007

MSBuild team wants your feedback!

If you ever used MSBuild (and if you have Visual Studio 2005, you probably do it daily) and have ideas how to make it better, MSBuild team is asking for your opinion. And if you use mainly Team Build, that should be of interest to you too, since MSBuild is the engine used to execute all builds.

Dan Moseley recently wrote a post that lists 11 propositions for future MSBuild features (though they numbered from 1 to 12 with number ten missing - I guess ten is unlucky number for MSBuild :). You can spend virtual $100 to rate the propositions and root for the features dear to you.

I urge you to go over there and vote with your money!

Tuesday, October 24, 2006

HasTrailingSlash in MSBuild scripts

There is useful undocumented function that may be used in MSBuild scripts conditions, called HasTrailingSlash. As its name implies, the function checks its only argument for trailing backward slash:

Sample updated at 01-Fev-2008 (recently somebody complained that while function works my old sample does not :):

<!-- Initial target will be always called first to verify properties -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
InitialTargets="VerifyInputParameters">
 
    <!-- Target verifies that the property is not empty (throws error) -->
    <!-- and has trailing slash (adds one if no slash provided)        -->
    <Target Name="VerifyInputParameters">

        <Error Condition="'$(ExternalPath)' == ''" Text="ExternalPath is empty" />

        <CreateProperty Condition="!HasTrailingSlash('$(ExternalPath)')" 
        Value="$(ExternalPath)\">

              <Output TaskParameter="Value" PropertyName="ExternalPath" />

        </CreateProperty>
    </Target>
    <!-- Here goes the rest of the project -->
</Project>


<PropertyGroup>


 <OutputPath Condition=" !HasTrailingSlash('$(OutputPath)') ">


  $(OutputPath)\


 </OutputPath>


</PropertyGroup>



The thing is, the function is used extensively in Microsoft system targets files (for example, in Microsoft.TeamFoundation.Build.targets file) and still does not appear in MSBuild documentation. Beats me...

See also new TFSBuild site for more details.