Can I include a .targets file in a .props property sheet? - visual-studio

I'm developing in C++ using Visual Studio 2012; I have about 25 projects in a solution that all use the same property sheet (.props file). I now need every project that uses said props file to also use a specific .targets file. Instead of editing each of the 25 .vcxproj files to add an import tag (or adding the import via the GUI for each project), I'd like to put an import statement in the .props file they all already use. Is this even possible? I've tried adding the import statement that works in the project file to the .props file just before the closing </Project> tag, and in a new importgroup at that location, and in the existing but empty importgroup labeled for property sheets at the top of the file, and while there are no errors reported, it doesn't actually do anything with the import statement.
Edit:
I'm overriding the predefined PostBuildEvent target in order to pass the IgnoreStandardErrorWarningFormat flag to Exec. My postbuild command runs a batch file which runs some unit tests, and the stdout and stderr output from those tests are parsed by VS for errors according to this post. The IgnoreStandardErrorWarningFormat flag disables this parsing.
Here is the contents of my .targets file:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="PostBuildEvent" Condition="'$(PostBuildEventUseInBuild)'!='false'">
<Message Text="Description: %(PostBuildEvent.Message)" Condition="'% (PostBuildEvent.Message)' != '' and '%(PostBuildEvent.Command)' != ''"/>
<Exec IgnoreStandardErrorWarningFormat="True" Command="% (PostBuildEvent.Command)$(_BuildSuffix)" Condition="'%(PostBuildEvent.Command)' != ''"/>
</Target>
</Project>

Related

how use properties from Directory.Build.props in Import from project file of Visual Studio

I have this situation:
I have a .proj file in project directory:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Compile Include="PQExtensionTest.pq">
<SubType>Code</SubType>
</Compile>
<Content Include="PQExtensionTest.query.pq">
<SubType>Code</SubType>
</Content>
</ItemGroup>
<!-- <Import Project="..\Directory.Build.props" /> -->
<Import Project="$(aProperty)add.targets" />
</Project>
In the solution directory (..\ from project directory) I have file Directory.Build.props:
<Project DefaultTargets="BuildExtension" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<aProperty>$(MSBuildProjectDirectory)/Subdir/</aProperty>
</PropertyGroup>
</Project>
In the project directory I have subdirectory "Subdir", where there is file add.targets, which contains all the targets I need (do not show it's contains here because it is not relevant to the problem).
So all above has this folder structure:
Solution directory
Directory.Build.props
Project Directory
Project.mproj
Subdir
add.targets
Preparing all the above, I expected that aProperty will be initiated before the import and the import of add.targets will happen without problem. But I get error that imported project is not found, and I see in error message that MSBuild tries to import from project directory, and not from subdirectory Subdir.
If I uncomment this row:
<Import Project="..\Directory.Build.props" />
all works fine.
The only reasonable explanation for me of such behavior is that aProperty is empty at the moment of importing, because explicit import happens before implicit one.
Is there any way to force MSBuild to inexplicitly import Directory.Build.props before any other imports, while work in Visual Studio?
"While in Visual Studio"
For C# and VB language project, we don't need to import
Directory.Build.props manually or force it before other imports.
When creating a new project(C# or VB) in VS, open its proj file we can find the format is like this:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
...
</PropertyGroup>
<ItemGroup>
...
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Every time when creating new C# or VB project, the top line within the <Project>node is Import project="Microsoft.Common.props", and we can find the sentence from this document:
When MSBuild runs, Microsoft.Common.props searches your directory structure for the Directory.Build.props file (and Microsoft.Common.targets looks for Directory.Build.targets). If it finds one, it imports the property.
So in visual studio, we don't need to force it before other imports.Its always called after import Microsoft.Common.props, and since the import Microsoft.Common.props is always first line of project node by default, the Directory.Build.Targets is always implicitly imported right after the Microsoft.Common.props and before others.
Note: This feature only supports C# and VB, cause only these two kinds of projects will import the Microsoft.Common.Props in proj file.
And for other kinds of projects, just like your .mproj or
.vcxproj(C++), this feature(Directory.Build.props) is not supported
yet.
So the Directory.Build.Targets or .props is the same as any custom .props. It doesn't make difference between Directory.Build.Targets and anyName.props.
In this way,to read the value in it we have to use import project to call it manually. And that's why the build can't succeed until you uncomment the row:<Import Project="..\Directory.Build.props" />
The way to import properties from 'Directory.Build.props' file from nested folder structure is given below:
Refer: https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2019
Note that:
1. These property file definition works from MSBuild tools version 15.0
2. You need to be aware of where to place this import: At the beginning of the file or at the end of the file. Generally it is good to place at the end as nested properties will be visible to parent properties.

Update Post-Build with custom nuget package

I need help to be able to update the post-build event of a project thanks to a custom nuget package.
I've created a package thanks to a nuspec file that include a .targets file :
<file src="*.targets" target="build"/>
Here is the .targets file :
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="AfterBuild" AfterTargets="Build" >
<Message Text="Hello World" Importance="high" />
</Target>
</Project>
Actually, the file is read when i install the package (if i delete some '>', i've an error).
But the .csproj isn't updated (so, nothing in the post-build event textbox).
Did i miss something ?
I agree with Matt Ward. From NuGet 2.5, NuGet recognizes a new top-level folder: \build.
Within the \build folder, you can provide a “.props” file and/or a
“.targets” file that will be automatically imported into the project.
For this convention, the file name must match your package id with
either a “.props” or “.targets” extension.
Please refer to the MSBuild Integration part in following document:
http://blog.nuget.org/20130426/native-support.html
And after install the package, you will see a import node in .csproj which import the package.targets file. Then when build your project, you will see "Hello World" text in output window.

Custom Build Rule fails after converting to VS2013

I need to integrate a legacy VS2008 project into my VS2013 solution. This project uses some custom build rules which initially worked after converting the .vcproj to a .vcxproj. However, when doing a fresh checkout of the project including the .vcxproj, the project file can no longer be opened.
I've tracked it down to this issue:
The project file references a couple of custom build rules like this:
<ImportGroup Label="ExtensionSettings">
<Import Project="..\..\..\tools\build\ms_mc.props" />
(8 similar lines follow)
</ImportGroup>
However, the ms_mc.props file is not present, but there is a ms_mc.rule file. If I convert the VS2008 solution with VS2013 (and assumably also if I opened it in VS2008, which I don't possess), the ms_mc.props file (plus a .targets and a .xml file) is created. However, if I delete that file and open the converted VS2013 project, the file does not get created.
I realized, in the old .vcproj, the corresponding lines are
<ToolFiles>
<ToolFile RelativePath="..\..\..\tools\build\ms_mc.rule" />
(8 similar lines follow)
</ToolFiles>
Why does VS2008 reference the .rule file and VS2013 imports the .props file without specifying the .rule file? And more importantly: How can I make this work again?
The .rule and .props file are added for reference
ms_mc.rule:
<?xml version="1.0" encoding="utf-8"?>
<VisualStudioToolFile
Name="MS MC"
Version="8,00"
>
<Rules>
<CustomBuildRule
Name="MS_MC"
DisplayName="Microsoft Message Catalogue Compiler"
CommandLine="mc [Verbose] [inputs] [RCIncludePath] [CIncludePath]"
Outputs="[$RCIncludePath]\$(InputName).rc;[$RCIncludePath]\$(InputName).h"
FileExtensions="*.mc"
ExecutionDescription="Compiling Message Catalogue $(InputName).mc"
>
<Properties>
<BooleanProperty
Name="Verbose"
DisplayName="Verbose"
Description="Gives verbose output. (-v)"
Switch="-v"
/>
<StringProperty
Name="RCIncludePath"
DisplayName="RC include file path"
Description="Gives the path of where to create the RC include file and the binary message resource files it includes. (-r [pathspec])"
Switch="-r [value]"
DefaultValue=".\"
/>
<StringProperty
Name="CIncludePath"
DisplayName="C include file path"
Description="Gives the path of where to create the include header file. (-h [pathspec])"
Switch="-h [value]"
DefaultValue=".\"
/>
</Properties>
</CustomBuildRule>
</Rules>
</VisualStudioToolFile>
ms_mc.props (after Conversion to VS2013):
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup
Condition="'$(MS_MCBeforeTargets)' == '' and '$(MS_MCAfterTargets)' == '' and '$(ConfigurationType)' != 'Makefile'">
<MS_MCBeforeTargets>Midl</MS_MCBeforeTargets>
<MS_MCAfterTargets>CustomBuild</MS_MCAfterTargets>
</PropertyGroup>
<PropertyGroup>
<MS_MCDependsOn
Condition="'$(ConfigurationType)' != 'Makefile'">_SelectedFiles;$(MS_MCDependsOn)</MS_MCDependsOn>
</PropertyGroup>
<ItemDefinitionGroup>
<MS_MC>
<Verbose>False</Verbose>
<RCIncludePath>.\</RCIncludePath>
<CIncludePath>.\</CIncludePath>
<CommandLineTemplate>mc [Verbose] [inputs] [RCIncludePath] [CIncludePath]</CommandLineTemplate>
<Outputs>%(RCIncludePath)\%(Filename).rc;%(RCIncludePath)\%(Filename).h</Outputs>
<ExecutionDescription>Compiling Message Catalogue %(Filename).mc</ExecutionDescription>
</MS_MC>
</ItemDefinitionGroup>
</Project>
I found this blog post for VS2010 which states the following:
Custom build rule is a build feature introduced in VS2005. It provides the ability for the users to easily Plug-In third party tools to use in their build process. The custom build rule is defined by “.rules” files.
and more importantly
In VS2010, due to the migration to MSBuild, the information in the rules file is represented by three files: .XML, .props and .targets files.
This basically means that the .XML, .props and .targets files are in fact not created by VS2008; instead, they are a replacement of the old .rules file format since VS2010. Using this information, I can now safely check in those new files without breaking the VS2008 solution. I might have to adapt the new files manually in order to make them work as before, as also mentioned in the blog.

Is there a way to add source files to visual studio project from command-line?

I want to use sublime to edit a visual studio project.
I have a custom build:
{
"cmd": ["c:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild.exe"],
"working_dir": "${project_path:${folder:${file_path}}}/../Project"
}
But if I add new files I also need to include them in the project.
Is there a way to do this from the command line, maybe at compile-time?
I am working with opengl using c++;
I basically set up a project using one of the examples provided on the opengl website.
Then I opened the project folder in sublime text and successfully compiled it using the custom build system.
However, when I add NEW source files to the project (*.h and *.cpp) I get a linking error.
I get the same error when I build in visual studio.
The error disappeared after I had included the files by manually browsing and adding them to the project.
What I wanted was a way to automatically add all the source files in a folder to the project(via command line, or wildcard or smth else).
This way I can easily work on a vs2010 project in sublime, add new source files and build the project.
Or maybe there already is a better workflow for this?
You could try to modify your .vcxproj file to include any .h and .cpp file in your project folder or folders below.
In case of a c++ VS project you can try to alter your .vcxproj file like this:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- rest of project file untouched -->
<!-- start of modified part -->
<ItemGroup>
<ClInclude Include="**\*.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="**\*.cpp" />
</ItemGroup>
<!-- end of modified part -->
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
Be aware that adding files to your project from inside VS at later point will replace the modification described above!
As an alternative you could also create an external project file holding the same <ItemGroup /> elements described above and include this project file into your .vcxproj.
I'll add an example of this alternative if you're interested.

Specifying project Property values from within Visual Studio

If I have properties defined in my project file like so
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<foo>bar</foo>
</PropertyGroup>
</Project>
I can easily set these properties on the MSBuild command line using /p:foo=newValue.
Is there a way of specifying the property value within the Visual studio (2010) GUI? I have had a look but could not find anything within the project properties pages.
Are you looking for conditional compilation symbols?
In VS2010:
Go to the project properties
Go to the Build tab
Under General you will see a place to define "Conditional compilation symbols".
You can enter "foo=bar" there, and you will get this in your .csproj file:
<Project ...>
<PropertyGroup ...>
<DefineConstants>Foo=bar</DefineConstants>
</PropertyGroup>
</Project>
I found this question when looking for an answer to the same thing: I can easily use /p or environment variables to control things when calling MSBuild on the command line, but how do you do similar in the IDE?
My solution was to add a “user” properties file. That is
<!-- Running from the IDE, you can't simply set properties via /p or environment variables.
So, this local file is read if it exists. It is not checked in to version control; but can contain
settings to be used for your immediate work.
If you make a settings.props.user file, remember DO NOT check it in!
-->
<ImportGroup>
<Import
Condition="exists('$(MSBuildThisFileDirectory)settings.props.user')"
Project="$(MSBuildThisFileDirectory)settings.props.user" />
</ImportGroup>
I can now edit some properties in the file settings.props.user conveniently located in the same directory, and not worry about accidentally checking in funny settings. Even when building in the IDE, it reads the text file anew when building. So, just keep the props.user file open in a text editor and it's handy enough to change on the fly, without an IDE extension.

Resources