I need to define a custom build rule for files in my projects.
However the rule may be different for different solutions (more percisely, for the same solution in a parallel dev branch).
I have two questions:
Can a .rules file be specified in a location relative to the solution? That way I'd be able to create rules per development branch.
MSDN says that the custom rule is inheritable similarly to the properties (vsprops). How can that be achieved? Where do I specify the inheritance?
Thanks,
Gil Moses.
.vcproj file will contain the following clause:
<ToolFiles>
<ToolFile
RelativePath="..\my.rules"
/>
</ToolFiles>
You can use $(SolutionDir) to customize placement of the .rules file, like this:
<ToolFiles>
<ToolFile
RelativePath="$(SolutionDir)..\..\..\my.rules"
/>
</ToolFiles>
Related
it's probably a stupid question, but I have wasted a lot of time.
I found this one and several other links where people are editing .xml, .props and .targets file to create a customization in Visual Studio build.
Adding new target to use ClCompile
Here he/she is extending CL rule in xml file and doing other things in .props and .targets file.
But as I am referring to MSBuild documentations, I cannot find a way to customize using these three files. I only found creating a custom target in .vcxproj file. However, when I try to extend a rule here, it just says
Rule is not an element of Project.
These are related documentations I found -
https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2019
https://learn.microsoft.com/en-us/cpp/build/how-to-add-custom-build-tools-to-msbuild-projects?view=vs-2019
Has methods of adding customization changed or am I not referring to right documentations? Please help. Basically, I want to do what has been done in above stack overflow answer. (Create a preprocessing target which can get all properties/items of CLCompile target.)
I did manage to override ClCompile target by adding ClCompile.props and added my custom task in it by using Exec Command. It served my purpose and I didn't actually go through extending xml file.
I have a Visual Studio solution with over 100 projects in it. I want to apply certain settings to all projects, so I used a Directory.Build.Props file and it works great. However, after reading the documentation I just realized that all of the solutions in the sub directories will use those settings too, but I don't want to affect those solutions since I don't maintain them. Is there a way to limit the scope of a Directory.Build.Props file to the current directory, or a particular solution? (Perhaps you can customize the name of the Props file and import it for a particular solution?)
For example, consider a directory structure organized as such:
/code/MySolutionFile.sln
/code/Project001/
/code/Project002/
/code/Project003/
...
/code/Project100/
/code/OtherStuff/OtherStuff.sln
/code/OtherStuff/ProjectA
/code/OtherStuff/ProjectB
/code/OtherStuff/[lots of other solutions somewhere in this directory tree]
I have put my Directory.Build.Props file in the /code directory because I would like to define settings for all projects in /code/MySolutionFile.sln. But I don't want to affect any of the other solutions in subdirectories of the /code folder.
If all else fails I think I could create an empty Directory.Build.Props file and drop it in every directory that contains a solution file except for the one I want mine to apply to. (But this feels like a last resort.)
Modifying my Directory.Build.props file in this way accomplishes my goal:
<Project>
<PropertyGroup Condition="$(SolutionFileName) == 'MySolution.sln'">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
</Project>
This works by setting the PropertyGroup to conditionally run the rules. (Note the condition could also be applied to specific rules rather than the group.) In this case I was able to use the name of the solution file to limit the scope of this rule to my desired solution without affecting any others.
One caveat though, the documentation claims that the solution variables are only available when used in the IDE. However, with my limited testing the rules are also correctly applied when I use msbuild from the command line, like this: msbuild.exe MySolution.sln
I tested it from both a VS Developer Command Prompt and a regular Windows Command Prompt, and both still read the $(SolutionFileName) variable properly.
MSBuild supports Conditions on many types of element, including PropertyGroup and individual properties. In this case, you don't need the Choose-When - you could just put the condition on the PropertyGroup or TreatWarningsAserrors directly.
Is there a way to limit the scope of a Directory.Build.Props file to
the current directory, or a particular solution? (Perhaps you can
customize the name of the Props file and import it for a particular
solution?)
The Directory.Build.Props will act on the xxxx.sln of the current folder which contains many included xxxx.csproj files and then also act on the xxxx.proj files of all the sub folders. It will go down one step at a time for any xxx.proj file which it finds and it is designed by that. You can see the search scope of it.
Since your workaround works well but it is a bit complex, or you can try my solution if you are willing to:
Workaround
Please create a folder called MyStuff under the folder code and then put Project001---Project100 into this folder. After that, put your Directory.Build.Props file into MyStuff folder. With it, the file will affect only Project001---Project100.
Hope it could help you.
I have a custom tool that I run on certain file types using the .targets mechanism in Visual Studio 2015.
Projects exist at many levels, and I want to reference this tool when the code is pulled to ANY drive/folder, including the TFS CI agent.
I tried using a relative path, but because the files are at different levels, it doesn't work for all projects.
I tried using a registry setting and environment variable, but that doesn't bode well for the CI machine which might build in a different folder each time.
Is it possible to get the solution folder of which the project/file is in, then I can use a relative path to the tool directory?
All I can find is these properties, which do not seem to help:
General MSBuild properties:
https://msdn.microsoft.com/en-us/library/bb629394.aspx
https://msdn.microsoft.com/en-us/library/ms164309.aspx
Registry and environment variables:
https://msdn.microsoft.com/en-us/library/ms171458.aspx
You can use all the standard tokens within .targets.
Just use
$(SolutionDir)
See https://msdn.microsoft.com/en-us/library/c02as0cs.aspx
Self-service answer: use visual studio's property editing for a vcxproj in preprocessor macros or include paths or such to look at a bunch of available variables. You can usually find what you need in there, by name, or by example, including the one you need here. Better than any documentation.
I have a question about MSBuild.exe and Environment Variables. First, the development environment:
The code is mostly C++ with some C#. There are over 5,000 classes, 340 projects and 200 solutions arranged in a deep source tree. There is a solution at the root of the tree and at various other points in the tree. We use TFS and maintain multiple active branches for a series of future releases. Each developer uses a local view to modify and test code. Some developers work on multiple branches concurrently. Sometimes developers build solutions from different TFS branches concurrently.
We use about 70 environment variables for locating shared header files, libraries, etc. In VS2008 we used a file with the same base name as the solution file and an extension of .slnenv for defining the environment variables. All variables are defined relative to the base of the source tree. This .slnenv file is read by a custom VS2008 AddIn that creates Environment Variables in the VS2008 process space, i.e.
MyProjectDir=$(SolutionDir)\..\..
MyRoot=$(MyProjectDir)\..\..
MyInstallDir=$(MyRoot)\Install
MySourceDir=$(MyRoot)\Source
MyUnmanagedSourceDir=$(MySourceDir)\My\Unmanaged
MyIncludeDirs=$(MyProjectDir);$(MyUnmanagedSourceDir)
This AddIn does not work correctly with VS2010 because MSBuild does not inherit the environment variables that are created after the solution is loaded.
My question is how do I get these environment variables to MSBuild? I have found two methods that work, but are not as convenient as the AddIn we had been using.
VS2010 can be started with a command script that first sets Environment Variables in the process space and then starts VS2010. MSBuild does inherit these Environment Variables. This is unsatisfactory because the scripts would need to be customized for the various points where a solution can be loaded.
The second method I have tried is defining the Environment Variables as Properties in property sheets and .vcxproj files. We have a base property sheet that all .vcxproj files load. In that property sheet:
<PropertyGroup>
<MyRoot>$(MyProjectDir)\..\..</MyRoot>
<MyInstallDir>$(MyRoot)\Install</MyInstallDir>
<MySourceDir>$(MyRoot)\Source</MySourceDir>
<MyUnmanagedSourceDir>$(MySourceDir)\My\Unmanaged</MyUnmanagedSourceDir>
<MyIncludeDirs>$(MyProjectDir);$(MyUnmanagedSourceDir)</MyIncludeDirs>
</PropertyGroup>
Then I can define the base directory in each .vcxproj file:
<PropertyGroup>
<MyProjectDir>..\..</MyProjectDir>
</PropertyGroup>
This method uses relative path names where the AddIn resolved all Environment Variables to absolute path names. I'd rather not have to edit 340 .vcxproj files where the definition of "MyProjectDir" would vary depending on how far from the source root the project file exists. So far I've tried this method in just one project.
I have tried to modify the AddIn to create Properties rather than Environment Variables. I tried using ENV2.get_Properties(), but that seems to work only for Properties that are defined in VS2010, not for Properties I've defined.
Thank you,
Dan Kary
After discussion via email, we figured what were Dan needs and following message helps him with question issue. He agrees that this could be helpfull to other SO members:
Aha, I get it now.
As I did understand from that topic - you really need all that stuff only for build step (paths for include clause, paths to built tool to resolve dll\exe dependency), and no regular developer activities depends on it.
It's good, cause we don't need to fight VStudio about not reinitializing env vars after first load. We just need somehow edit and implement your solution for huge amount of proj files ;) Task become much easier :D
Small disclaimer - I'm writing this on the road and have no access to fully fledged dev env to check and bulletproof all further recomendations, so take my apologizes in advance for any mistakes I will make ;)
I would like to bring your attention to some msbuild features:
http://msdn.microsoft.com/en-us/library/ms164309.aspx
You have predefined properties, that available for all scripts and projects, it looks like this will help you solve first issue - absolute paths instead of relative. This is small excerpt from the link for further reference
$(MSBuildProjectDirectory) -
The absolute path of the directory where the project file is located, for example, C:\MyCompany\MyProduct.
$(MSBuildProjectFile) -
The complete file name of the project file, including the file name extension, for example,
MyApp.proj.
$(MSBuildProjectExtension)
The file name extension of the project file, including the period, for example, .proj.
$(MSBuildProjectFullPath)
The absolute path and complete file name of the project file, for example, C:\MyCompany\MyProduct\MyApp.proj.
$(MSBuildProjectName)
The file name of the project file without the file name extension, for example, MyApp.
So you should be able to use this defined properties in your Property sheets.
Now, with msbuild 4.0 toolset (toolset defined by attribute ToolsVersion="" on the root script element) there is interesting trick
Microsoft.Common.Targets define 2 variables to conditionally import custom msbuild script before or after itself
CustomBeforeMicrosoftCommonTargets and CustomAfterMicrosoftCommonTargets
You can use it the following way ( I think it will possible help you to avoid editing of all proj files or at least - reduce editing to very simplified copy-paste part)
Define it using relative path to include your property sheet files
<CustomBeforeMicrosoftCommonTargets>$(MSBuildProjectFile)\ConcreteProjectCustomProperties.propz</CustomBeforeMicrosoftCommonTargets>
Take a note that CustomBeforeMicrosoftCommonTargets should be global scoped property to be inherited by all secondary
And if you properly define your ConcreteProjectCustomProperties.propz I think you could achieve what you need.
"Properly" is that you will include there your global properties file (with relative or absolute path) and then define all your project-level properties.
NB:
Also take a note that later defined properties not available for reference to early defined
Your example defines $(MyIncludeDirs) with reference to $(MyProjectDir), but $(MyProjectDir) declared and defined a bit later.
It could be due to "exampling" and fast churning that code, but if you define your vars same way in production - it could lead to subtle error.
I hope I got your problem properly and my explanations will help you to quickly move all your properties from custom add-on to simpler and native msbuild script ;)
I have a csproj file, being part of two different Visual Studio solutions. The project file should be able to behave slightly different, depending on the solution it will be used from. What I would need, is something usable as a 'Condition' - a property named for example $(SolutionName) - filled in automagically.
At least, this is my idea. I didn't found anything like that.
I also considered to have two small project files importing the common parts. This would prevent editing all these properties from inside Visual Studio, I guess. It would write changes only in the active 'master file', correct?
So, is there any other way to discriminate at project level using solution information?
Turns out there is a property named exactly $(SolutionName). Try this; first set an environment variable as:
> set MSBuildEmitSolution=1
Then build your solution file using MSBuild from the same command line
> MSBuild My.sln
You will find the MSBuild project transformation of your solution file, it will be named My.sln.metaproj.
Just open that in a text editor and you can see the other properties. Examine the "Build" target in this projectd file, you can see that all these properties are passed in to the MSBuild task when it builds your projects, so you should be able to discriminate conditions based on any of them.