Moving compile items in msbuild into a separate file? - visual-studio

This is probably a FAQ, but we weren't able to find a solution even after a lot of searching.
We have a number of msbuild files that all operate on the same set of source files. (It's not particularly relevant but they compile to completely different platforms.) To make managing these a little simpler, we'd like to move the <Compile> source file names to a separate file and reference that from all the msbuild files.
We tried cutting the <ItemGroup> containing the <Compile> items and pasting it into a new file, and surrounding it with
<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
and then referencing that file from the original with
<Import Project="Common.files.csproj" />
but that does not work - the solution opens (with a warning since we hacked the default config), but no items appear in the Solution Explorer.
What are we doing wrong?

Tried with Visual Studio 2010:
1) Create your external .proj (or .target) file and add your files (I used a different item name but that shouldn't matter)
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ExternalCompile Include="Program.cs" />
<ExternalCompile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
</Project>
2) Import your external .proj file at the top of your Visual Studio project file:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="MyExternalSources.proj" />
<PropertyGroup>
...
and modify the Compile ItemGroup like this:
...
<ItemGroup>
<Compile Include="#(ExternalCompile)" />
</ItemGroup>
...
Warning: You'll have to add new items/files to your external .proj file - all items/files added from within Visual Studio will end up like this:
...
<ItemGroup>
<Compile Include="#(ExternalCompile)" />
<Compile Include="MyNewClass.cs" />
</ItemGroup>
...

I've never seen "include" files work with MSBuild. Obviously Targets files work this way, but I haven't seen a partial msbuild file included in another. COuld you use a method such as illustrated in this?
http://msdn.microsoft.com/en-us/library/ms171454(VS.80).aspx
Using wildcards is how I've addressed this in the past.

Related

MSBuild reexpand property

I use some custom props file like this (my_super_props.props)
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<TargetOsName>linux</TargetOsName>
<RemoteGeneratedFilesDir>$(RemoteIntDir)generated_files/</RemoteGeneratedFilesDir>
</PropertyGroup>
<ItemGroup />
</Project>
VS generates vcxproj file for me like this (piece)
.....
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="Shared" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='debug|x86'">
<Import Project="my_super_props.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='debug|x86'">
<RemoteIntDir>$(RemoteProjectDir)/obj/$(PlatformTarget)/$(TargetOsName)/$(Configuration)/</RemoteIntDir>
</PropertyGroup>
.....
Inside Microsoft.Cpp.props - $(RemoteIntDir) already defined like this
<RemoteIntDir Condition="'$(RemoteIntDir)' == ''">$(RemoteProjectDir)/obj/$(Platform)/$(Configuration)/</RemoteIntDir>
So Inside my Targets i'ev got wrong value of $(RemoteGeneratedFilesDir)
for exmaple
my_proj/obj/x86/debug/generated_files
instead of
my_proj/obj/x86/linux/debug/generated_files
because properties expands at declaration time,
but i can't declare $(RemoteIntDir) earlier, cos it depends of $(TargetOsName)
So I must somehow reexpand $(RemoteGeneratedFilesDir) before targets start - but i don't know how ??
PS
$(RemoteIntDir) - filled with Visual Studio project configuraion UI Dialog, so i even can't change order of properties declaration/props imports and etc
Your requirements are in a mess and there are no default properties RemoteProjectDir,RemoteGeneratedFilesDir,RemoteIntDir on system Microsoft.Cpp.props file. So it is quite strange due to your description.
I have added
<RemoteIntDir Condition="'$(RemoteIntDir)' == ''">$(RemoteProjectDir)/obj/$(Platform)/$(Configuration)/</RemoteIntDir>
.....
into my Microsoft.Cpp.props file to keep the same MSBuild environment as yours.
I have two questions.
my_proj/obj/x86/linux/debug/generated_files, is your current build configuration is linux? And why did you have two similar configuration linux and debug under it?
Also, is it my_proj/obj/x86/linux/generated_files?
In this situation, I have trusted your description, and assume it is my_proj/obj/x86/linux/debug/generated_files.
Besides, the changed $(Configuration) will act on the whole msbuild files including Microsoft.Cpp.props system files and vcxproj file.
One
If your current build configuration is debug and Platform is x86, you should try to change your my_super_props.props file like this:
<RemoteGeneratedFilesDir>$(RemoteProjectDir)/obj/$(Platform)/$(TargetOsName)/$(Configuration)/generated_files/</RemoteGeneratedFilesDir>
Two
If your build configuration is linux(to create it, you have to enter Build top menu under VS IDE-->Configuration Manager-->click New under the Project Configuration then input linux under it)
First, you have to add these under your current vcxproj file:
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='linux|x86'">
<Import Project="my_super_props.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='linux|x86'">
<RemoteIntDir>$(RemoteProjectDir)/obj/$(PlatformTarget)/$(TargetOsName)/debug/</RemoteIntDir>
</PropertyGroup>
Second, modify your my_super_props.props file:
<RemoteGeneratedFilesDir>$(RemoteProjectDir)/obj/$(Platform)/$(TargetOsName)/debug/generated_files/</RemoteGeneratedFilesDir>
Rebuild the project:

Can I reference files in a Visual Studio project file from a separate targets file in MSBuild?

I'm using Jenkins and MSBuild to build our solution and would like to use the command line tool that is bundled with one of our Visual Studio plugins to generate CSS and JavaScript for us. For reasons that I hope are obvious, I'd like to do this using MSBuild and the Visual Studio project file as opposed to having to maintain a separate batch file.
I've got as far as creating a separate .targets file and have got that to run, but I'm struggling when it comes to grabbing the files themselves. I can use a wildcard to grab files from the filesystem, but what I'd really like to do is get a list of files from the project file itself.
Here's a brief version of our project file – I've removed a lot of the 'default' stuff:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- I'll omit all the standard project bits and bobs for brevity -->
<ItemGroup>
<Content Include="css\scss\styles.scss">
<Compile>True</Compile>
<Minify>False</Compile>
<CompileStyle>Nested</CompileStyle>
<DebugInfo>False</DebugInfo>
</Content>
<Content Include="css\scss\_imported-1.scss">
<Compile>False</Compile>
<Minify>False</Compile>
<CompileStyle>Nested</CompileStyle>
<DebugInfo>False</DebugInfo>
</Content>
<Content Include="css\scss\_imported-2.scss">
<Compile>False</Compile>
<Minify>False</Compile>
<CompileStyle>Nested</CompileStyle>
<DebugInfo>False</DebugInfo>
</Content>
</ItemGroup>
<Import Project="$(SolutionDir)\.webcompile\WebCompile.targets" />
</Project>
WebCompile.targets looks like this:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
WebCompile
</BuildDependsOn>
</PropertyGroup>
<ItemGroup>
<SassFiles Include="**/*.scss" />
</ItemGroup>
<Target Name="WebCompile">
<Message Text="SassFiles: #(SassFiles)" />
</Target>
</Project>
This returns all of the matching *.scss files from the Solution directory, but I'm really interested in just returning files that are already listed in the project file that have the <Compile> child node set to True.
Is this possible?
This returns all of the matching *.scss files from the Solution
directory, but I'm really interested in just returning files that are
already listed in the project file that have the child node
set to True.
You could add a filter to the SassFiles itemgroup where only the members with the appropriate criteria would appear.
<ItemGroup>
<SassFiles Include= "#(Content)" Condition = "'%(Extension)' == '.scss' AND '%(Compile)' == 'true'"/>
</ItemGroup>
#Abit, here is my MsBuild script (saved as "abit.msbuild"):
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="WebCompile" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- I'll omit all the standard project bits and bobs for brevity -->
<ItemGroup>
<Content Include="css\scss\styles.scss">
<Compile>True</Compile>
<Minify>False</Minify>
<CompileStyle>Nested</CompileStyle>
<DebugInfo>False</DebugInfo>
</Content>
<Content Include="css\scss\_imported-1.scss">
<Compile>False</Compile>
<Minify>False</Minify>
<CompileStyle>Nested</CompileStyle>
<DebugInfo>False</DebugInfo>
</Content>
<Content Include="css\scss\_imported-2.scss">
<Compile>False</Compile>
<Minify>False</Minify>
<CompileStyle>Nested</CompileStyle>
<DebugInfo>False</DebugInfo>
</Content>
</ItemGroup>
<Target Name="WebCompile">
<ItemGroup>
<SassFiles Include="#(Content)" Condition="'%(Extension)' == '.scss' AND '%(Compile)' == 'true'" />
</ItemGroup>
<Message Text="SassFiles: #(SassFiles)" />
</Target>
</Project>
This is the command I am running:
%WinDir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe abit.msbuild
Here is the output:
Project "d:\msbuild\abit.msbuild" on node 1 (default targets).
WebCompile:
SassFiles: css\scss\styles.scss
Done Building Project "d:\msbuild\abit.msbuild" (default targets).
I'm not seeing any errors due to the condition on the #(SassFiles) ItemGroup, and I believe I'm seeing the correct output.

MSBuild attach to Visual Studio Project Build

I am using YUICompressor.Net for minification. The .proj file executes from MSBuild and works fine.
The question is how do I attach the MSBuild action to the build of the main Project?
I know there are some "After Build" events, bud how do I point them to execute my additional MSBuild.
In case it's relevant this is how my MSBuild file looks like:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/MsBuild/2003">
<UsingTask TaskName="CssCompressorTask" AssemblyFile="..\bin\Yahoo.Yui.Compressor.Build.MsBuild.dll" />
<UsingTask TaskName="JavaScriptCompressorTask" AssemblyFile="..\bin\Yahoo.Yui.Compressor.Build.MsBuild.dll" />
<Target Name="Minify">
<ItemGroup>
<CssFile_Common Include="../Styles/common.css"/>
<CssFile_Plugins_All Include="../Styles/plugins.all.css"/>
</ItemGroup>
<CssCompressorTask
SourceFiles="#(CssFile_Common)"
DeleteSourceFiles="false"
OutputFile="../Styles/common.min.css"
CompressionType="Standard"
LoggingType="Info"
PreserveComments="false"
LineBreakPosition="-1"
/>
<CssCompressorTask
SourceFiles="#(CssFile_Plugins_All)"
DeleteSourceFiles="false"
OutputFile="../Styles/plugins.all.min.css"
CompressionType="Standard"
LoggingType="Info"
PreserveComments="false"
LineBreakPosition="-1"
/>
</Target>
</Project>
Assuming your sample file is named Minify.proj you would simply need to put something like this at the bottom of your main project file:
<Import Project="Minify.proj" />
<Target Name="BeforeBuild" DependsOnTargets="Minify">
</Target>

Can I use a property sheet to generate project configurations?

I'm trying to avoid hard coding settings into my .vcxproj files. I'd like to edit a single file, i.e. inherited property sheets (.props), to change my settings. This works great for compiler and linker settings. I also use this technique for all my dependent libraries like boost, zlib, for appending the include path and the libpath.
I'd like to take this a step farther and create the list of configurations in one property sheet.
Is this possible. I keep getting a error.
proj1.vcxproj
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="configurations.props"/>
<PropertyGroup Label="Globals">
<ProjectGuid>{36327322-B9FA-4D71-1111-E94F5BB55D57}</ProjectGuid>
<RootNamespace>Proj1</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
configurations.props
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="DebugUnicode|Win32">
<Configuration>DebugUnicode</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
</Project>
proj1.vcxproj : error : Project "proj1" does not contain any
configuration. The project cannot be loaded.
So is this possible?
Sorry, that is a bug I reported in VS 2010 Beta 2, but a fix didn't make RTM.
Link to Connect bug report

How can I create a common post build event used by multiple csproj projects

I have several Visual Studio 2010 C# projects. I'd like to have them all have the same post build event. Basically I want them to copy their output somewhere. I think I can do this using an <import> statement in each csproj file, but I can't seem to figure out the properties/targets and such that I need in the imported file. Do you have any suggestions?
EDIT: I've tried the following but can't get it to work. This is what the Imports.props file looks like:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="AfterBuild">
<Message Text="Here I come to save the day!" />
</Target>
</Project>
I then Include it in the csproj files:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="Imports.props" />
...
I've also tried this as Imports.props:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PostBuildEvent>echo Here I come to save the day!</PostBuildEvent>
</PropertyGroup>
</Project>
Make sure that you import your targets file after the Microsoft.Common.targets import, as that file defines an empty AfterBuild target, which would override the definition in your targets file.
<import> in each projectfile and a <AfterBuild> target in your common build file.
CommonTargets
http://msdn.microsoft.com/en-us/library/ms171464.aspx
TargetOrder
http://msdn.microsoft.com/en-us/library/ms171462.aspx
I managed to share a build script via the property sheets, by writing it as a macro in the inherited property sheet. Then calling the macro in any of the projects that need them.
Macros are found under (VS2005):
Common Properties->User Macros
Remember, you can put macros inside other macros so long as the order is correct.

Resources