Trying to run my program through the Microsoft Visual Studio debugger, and have added parameters in Project->Properties->Configuration Properties->Debugging in the Command Arguments field.
One of my parameters contains the string "<u>" and Visual Studio is changing it into "<u xmlns="http://schemas.microsoft.com/developer/msbuild/2003">". This is both unexpected and unhelpful. My program does not expect nor wish to have all this extra stuff passed in instead of the string I am trying to pass in.
As an example, the parameter in question is -nlp:"<u>" and Visual Studio is changing it into -nlp:"<u xmlns="http://schemas.microsoft.com/developer/msbuild/2003>". The expected result is for it to stay as typed in: -nlp:"<u>". This is one example, but there are in fact two parameters affected in this way. Both are "enhanced" with the addition of the same string. If I used other values, they are always affected the same way. It seems any string surrounded by angle brackets is fair game for this string embellishment.
How do I configure Visual Studio not to make this change?
My VS version details are:-
Microsoft Visual Studio Ultimate 2012
Version 11.0.61219.00 Update 5
The problem does not seem to exist with Visual Studio 2017 or higher (I've not tested 2013 nor 2015).
How debug arguments are stored depends on project type packages (C, C#, C++, etc.), even if they are both using the MsBuild system.
Also, without manual intervention, debug arguments are not stored in the project file (.csproj, .vcxproj, etc.), but aside it in a .user file (so it can vary per user).
With Visual studio 2017, for an arguments like -nlp:"<u>", for a C# project, the .user file looks like this
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<StartArguments>-nlp:"<u>"</StartArguments>
</PropertyGroup>
</Project>
And for a C++ project, the .user file looks like this:
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommandArguments>-nlp:"<u>"</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
We see that these are correctly escaped and the < and > are transformed into their respective XML entities.
Visual Studio 2012 doesn't act the same, so the XML must be escaped manually. And the problem may be in MsBuild, not strictly in Visual Studio. Editing the appropriate .user file and manually escaping your < and > characters as shown above will work round the problem in Visual Studio 2012.
Related
I upgraded a project from .NET Framework 4.7.2 to .NET 6. When I ran the program in the Visual Studio debugger, an unexpected argument (call it foo) was passed to Program.Main.
Where did foo come from? The project properties' Debug page shows no arguments:
Nothing to see here, in other words. Then I added a bar argument:
Program.Main now got passed an array of two strings, foo and bar. What's happening?
The upgrade part turns out to be central here. Most likely, just switching to the modern .csproj format is enough to trigger this weirdness.
Visual Studio now keeps things like application arguments in Properties\launchSettings.json, e.g.:
{
"profiles": {
"MyProgram": {
"commandName": "Project",
"commandLineArgs": "bar"
}
}
}
Before the upgrade, that information lived in MyProject.csproj.user:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<StartArguments>foo</StartArguments>
</PropertyGroup>
</Project>
Visual Studio apparently reads both files when starting debugging; it's not clear whether this is intentional or just a bug. (It would've made sense if the .NET Upgrade Assistant had simply moved that information, from old place to new.
Solution
I deleted the .csproj.user file, though removing the StartArguments tag will surely work too. Don't forget to restart Visual Studio!
Everything works with Qt in MSVC2013, except one thing: the DLLs are not found, because $(QTDIR) is not defined, when the local debugging environment is set.
My debugging environment settings:
PATH=$(QTDIR)\bin%3b$(PATH)
My .user file:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerEnvironment>PATH=$(QTDIR)\bin%3b$(PATH)</LocalDebuggerEnvironment>
<QTDIR>C:\Qt\Qt5.4.1\5.4\msvc2013</QTDIR>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerEnvironment>PATH="$(QTDIR)\bin%3b$(PATH)</LocalDebuggerEnvironment>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerEnvironment>PATH=$(QTDIR)\bin%3b"$(QTDIR)\bin%3b$(PATH)</LocalDebuggerEnvironment>
<QTDIR>C:\Qt\Qt5.4.1\5.4\msvc2013</QTDIR>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerEnvironment>PATH="$(QTDIR)\bin%3b$(PATH)</LocalDebuggerEnvironment>
</PropertyGroup>
</Project>
I don't know why, but the $(QTDIR) variable is not available to LocalDebuggerEnvironment.
It works with following debugging environment settings:
PATH=C:\Qt\Qt5.4.1\5.4\msvc2013\bin%3b$(PATH)
Is it possible to make Visual Studio handle this properly or do I have to enter the path manually?
It seems Visual Studio parses the lines from top to bottom, so with your code...
<LocalDebuggerEnvironment>PATH=$(QTDIR)\bin%3b$(PATH)</LocalDebuggerEnvironment>
<QTDIR>C:\Qt\Qt5.4.1\5.4\msvc2013</QTDIR>
...the variable $(QTDIR) is defined in the second line, and is cannot be used in the first line.
Simply switch the order so that the variable is defined before it is used:
<QTDIR>C:\Qt\Qt5.4.1\5.4\msvc2013</QTDIR>
<LocalDebuggerEnvironment>PATH=$(QTDIR)\bin%3b$(PATH)</LocalDebuggerEnvironment>
Note: Visual Studio only reads the .user file at startup, so you need to (re-)start Visual Studio after editing the file.
Thank you for your discussion of this issue. I can report that it still is extant in Qt 5.8 / QT Extension for Windows Version 2.1.1 / Visual Studio 2015. The symptoms are that entering "$(QTDIR)\bin" (the location of the Qt DLLs) as a PATH folder spec in the VStudio Project property Debugger...Environment appears to work, but actually does not.
By "appears to work" I mean that if you click on the option to examine the Debugger Environment property, and the raw form of the Environment property looks like "PATH=$(QTDIR)\bin;...;$(PATH)" the VStudio editing dialog box will helpfully inform you that that PATH string evaluates to (e.g.) "PATH=D:\TechApps\Qt\5.8\msvc2015_64b\bin;..."--just as it should if the QTDIR macro was really present and had the correct value. This is cruelly deceptive!
Because, by "really doesn't work" I mean that the PATH as actually prepared for use when launching your Qt-dependent application from within VStudio doesn't see this macro. Your beautiful PATH string is reduced to "\bin;...". You can confirm this by temporarily copying your Qt DLLs from $(QTDIR)\bin into the folder of your application executable. Your application will launch correctly. And if you examine your PATH from within your program (using e.g. getenv("PATH") in c++, you will see that your program's PATH string is missing QTDIR. (That is, it is what it would be if QTDIR were the empty string.)
FWIW, another symptom of this problem is that if you examine the VStudio list of macros, $(QTDIR) is not in the list.
The solution described above (rearranging the elements in ...vcxproj.user) appears to solve the problem. When you move the definition(s) of QTDIR earlier in that file, the PATH string actually available to the application is correct, and $(QTDIR) is present in the list of macros known to Visual Studio.
HOWEVER, I don't know whether changing the "Qt VS Tools" options, or the "Qt Project Settings," in VStudio causes the .user file to be incorrectly overwritten again.
Changing (or re-selecting) the Qt Version in the solution (Change Solutions Qt Version) fixed the issue for me.
It took many seconds to re-initialize the projects and even then I don't believe the .user file updated until I did a build of the project.
Background: I have several solutions with roughly 300 C++ projects across them, most of them shared. We are using Visual Studio 2013 and have a build script that compiles all of the projects in the correct order, ensuring dependencies are resolved ahead of time. Our development/engineering team builds all of the code through the build script and then attempts to debug using Visual Studio 2013.
Issue: The "build then debug" process results in Visual Studio telling us that the Projects are out of date. This stems from the ProjectEvaluationFingerprint property (in Line 39 Microsoft.CppBuild.targets) including a $(SolutionDir) in the output file. The recommended fix from Microsoft suggests removing the $(SolutionDir) from the file. As our developers tends to transition back and forth between projects, I do not want to manually change this .targets file on every developer's machine (and remember to change it back when they leave the project). I would like to override the property in the .vcxproj by using a .targets file explicitly for this.
The property in Microsoft.CppBuild.targets looks like:
<!-- Global up-to-date check support -->
<PropertyGroup>
<ProjectEvaluationFingerprint>$(Configuration)|$(Platform)|$(SolutionDir)|$(ProjectEvaluationFingerprint)</ProjectEvaluationFingerprint>
</PropertyGroup>
Generally, I have been following Microsoft's How to: Use the Same Target in Multiple Project Files. I have created a .targets file (test.targets) that contains the following code (note the TEST text was to test evaluation of the property in both the build script and building the project in Visual Studio):
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectEvaluationFingerprint>$(Configuration)|$(Platform)|TEST|$(ProjectEvaluationFingerprint)</ProjectEvaluationFingerprint>
</PropertyGroup>
I then import it using the following line in the .vcxproj
<Import Project="..\..\Config\VSPropertySheets\test.targets" />
The project.lastbuildstate file now reads:
#TargetFrameworkVersion=v4.0:PlatformToolSet=v120_xp:EnableManagedIncrementalBuild=false:VCToolArchitecture=Native32Bit
Debug|Win32|D:\views\devbranch\Products\SLN\|Debug|Win32|TEST|
It is appending the new ProjectEvaluationFingerprint to the existing one, so it is not overriding (I can understand this to a degree, but I'm no MSBuild expert).
Question: How can I override this one property using a .targets file? Do I need to use a replaceregexp task or do I have an easier option?
You can override this property, but you have to be careful about two things:
the new setting you want is this:
<ProjectEvaluationFingerprint>$(Configuration)|$(Platform)|TEST/ProjectEvaluationFingerprint>
Note the removal of $(ProjectEvaluationFingerprint), which would contain the previous value of this tag
the location where you put the import is important: you will want to put it at the very end of your project (i.e. after the Microsoft.CppBuild.targets import).
Concretely:
use_custom_fingerprint.targets
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectEvaluationFingerprint>$(Configuration)|$(Platform)</ProjectEvaluationFingerprint>
</PropertyGroup>
</Project>
project.vcxproj
<Project ...>
...
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<Import Project="use_custom_fingerprint.targets" />
</Project>
Note that I also tried the extension .props and this worked just the same.
Note: The new import after importing Microsoft.CppBuild.targets.$(Platform).user.props is not sufficient, it must be after Microsoft.CppBuild.targets.
Disclaimer: tried in Visual Studio 2015
I have the same problem. I was able to progress a step further than you, but I still haven't a full solution.
The reason why you have now the old fingerprint appended to the new one without solution dir is your line
<ProjectEvaluationFingerprint>$(Configuration)|$(Platform)|TEST|$(ProjectEvaluationFingerprint)</ProjectEvaluationFingerprint>
The
$(ProjectEvaluationFingerprint)
Holds the old fingerprint, so just remove this part from the value for ProjectEvaluationFingerprint and your lastbuildstate will have the desired value.
Sadly now (at least for me) Visual Studio always thinks the fingerprint is wrong and will re-link the project with every compile, not only when switching sln file.
I removed the line from the props sheet and the up-to-date check works again as expected as long as solution directory doesn't change. I then modified the Microsoft.CppBuild.targets directly and this works: No more "not up-to-date" projects, even when switching solution directory.
I am attempting to overhaul my project's build processes. We have ~330 Visual C++ projects that we have upgraded in the last year from Visual Studio 2005 to Visual Studio 2013. I would like to take advantage of MSBuild to improve our build time over our very serial build scripts that we have now. I have completed a rough first pass and dropped the build times for a Release build from ~2 hours to ~20 minutes. In the process of doing this, I am consolidating a lot of common project settings into a .props file . In doing so, I have hit a stumbling block.
I wish to inherit the Platform Toolset from one VSProps file to all of the projects that include it. At the top of the new .props file I created, I put the following:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="Configuration">
<PlatformToolSet>v120</PlatformToolSet>
</PropertyGroup>
<PropertyGroup Label="UserMacros" />
I then removed the corresponding <PlatformToolSet>v120</PlatformToolset> from the individual project files.
Alas, things have started to go downhill. The projects (in Visual Studio 2013) now say in the Solution Explorer something like CoreGeometry (Visual Studio 2010) and the projects themselves seem to want to reference the v100 platform toolset. When I build, it then complains at me:
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppBuild.targets(362,5): warning MSB8003: Could not find WindowsSDKDir variable from the registry. TargetFrameworkVersion or PlatformToolset may be set to an invalid version number.
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppCommon.targets(341,5): error MSB6006: "CL.exe" exited with code -1073741515.
The only way I have been able to work around this is to manually set the PlatformToolset on the .vcxproj themselves, which is not terrible, I just am a bit annoyed that every other property seems to inherit, but the PlatformToolset does not.
My question is thus:
Can I use a .props file to inherit a common PlatformToolSet into a .vcxproj that does not specify a platform toolset?
A second question: Should I even be messing with the Platform ToolSet in this manner or am I setting myself up at risk for a maintenance nightmare later?
It is very good practice to extract common settings to a separate .props file and <Import> that from all projects. I am doing the same with my projects, including configuring PlatformToolset property in .props file, and I have no problems building it this way.
Few points related to this:
There is nothing special about PlatformToolset property, or any other property for that matter. Configuring properties inside .props file is identical to setting it inside .vcxproj file directly (however see my point below about ordering). Of course, there are some built-in properties, which you cannot configure at all, but those are always read-only properties.
The only case where you would not be able to override a property, if it the property value is passed directly from command line for the build (e.g. msbuild mysolution.sln /p:Platform=x86 will have everything built with Platform property set to x86 and overrides in projects won't take effect).
There is a difference between msbuild engine interpreting your projects and Visual Studio showing settings for the project. In some cases you might find that after refactoring .vcxproj files some standard project configuration dialogs not showing information you configured in .props file. To alleviate this, make sure that your <Import> command for .props file is always able to locate the .props file, by setting absolute path to .props file. Second, ensure you specify Label attribute for the <PropertyGroup> element in your configuration file like it was specified in your .vcxproj file.
Finally, make sure your <Import> element is in the right place. Usually you want it to be the very first Import, before you import standard .targets and .props, like Microsoft.Cpp.defaults.props, etc. The reason is msbuild works by performing sequential scans through the statements, so order of instructions matter.
To make #3 and #4 easier, here is a trick to specify absolute path to the .props file. Assume that your solution name is MySolution.sln and custom props file is MyCustomProps.props, placed in the same directory where solution is:
<PropertyGroup>
<RootFolder>$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory),MySolution.sln))</RootFolder>
</PropertyGroup>
<Import Project="$(RootFolder)\MyCustomProps.props" />
Are the any MSBuild properties that Visual Studio sets? I'm looking to have some conditional behavior depending on the version (if any) of visual studio.
The property value you should be using is BuildingInsideVisualStudio, when you are building inside of Visual Studio this property will be set to true. Since ProductVersion is declared in the project file you cannot use it because it will have the same value whether building inside of VS or via msbuild.exe.
<PropertyGroup>
<MyProp Condition=" '$(BuildingInsideVisualStudio)' == 'true' ">Foo</MyProp>
<MyProp Condition=" '$(BuildingInsideVisualStudio)' != 'true' ">Bar</MyProp>
</PropertyGroup>
To directly address the question in your title - if you just want to know if you are being built from VS or not, check the value of IsDesktopBuild which will return true or false appropriately.
Yes, <ProductVersion> is listed in a project file. It matches the Visual Studio version number.
<ProductVersion> will give you the version of MSBuild that is running the build process.
Note that in VS 2010 the build process might be targeting either .Net 4.0 or 3.5 You need to consider carefully if your conditional compilation depends on the msbuild version itself or on the target framework of the build and the tools the build is using. If your condition is based on the target framework, use <TargetFrameworkVersion>.
Of course, if your build also might be run under VS 2008, you need to support proper fallback if <TargetFrameworkVersion> is missing.