VisualStudioVersion="VersionLatest" is not being picked up - visual-studio

I've created an MSBuild proj file that contains the following header:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0" TargetFrameworkVersion="4.5" VisualStudioVersion="VersionLatest">
This proj file is used to trigger an MSBuild on a number of SSDT projects, couples with a Deploy.
For most developers, this is fine. However, one dev encounters a Deploy72002 exception when trying to run the build. According to this answer, this is due to the VisualStudioVersion not being set. Sure enough, adding
set VisualStudioVersion="12.0"
in the batch file prior to the MSBuild call fixes the problem.
However, I was under the impression (I can't find the source now) that setting VisualStudioVersion="VersionLatest" in the xml of the proj file was sufficient to make it use the highest version of VS installed. I've even tried setting it from VersionLatest to 12.0, and also moving it from the root node, into a node of it's own in <PropertyGroup>.
I'd rather not have a hardcoded reference to 12.0 in the batch file. Am I missing something obvious to make VersionLatest work?

Try this: run MsBuild with the command line option to generate a preprocessed single file. Do the same on a working computer with the same version. Diff the files produced.
It might be picking up different contents for some .props or .targets file. These have been known to change due to installing or updating some or another. I recall following a msdn article to fix such a file when I looked up a problem.

Related

Cannot load WiX projects after installing the VS2010 Web Publishing Updates

I installed the VS2010 web publishing updates yesterday, and now whenever I try to load a WiX setup project (all showing as unloaded in solution explorer) I'm getting the error:
The imported project "PROJECTNAME.wpp.targets" was not found. Confirm that the path in the declaration is correct, and that the file exists on disk. C:\Program Files\MSBuild\Microsoft\VisualStudio\v10.5\Web\Microsoft.Web.Publishing.targets
Where PROJECTNAME is the path to my setup wixproj file, without the .wixproj extension. I've checked through the project file and there is no reference to a wpp.targets file anywhere. I decided to try and create a blank targets file in that location and so added one with just this in it:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>
But got exactly the same error - a not found exception despite the file being there!
I then dug into the Microsoft.Web.Publishing.targets file and had a look for any ".wpp.targets" text, which gave me this:
<PropertyGroup Condition="'$(EnableWebPublishProfileFile)'=='true' And
'$(WebPublishProfileFile)' != '' And Exists($(WebPublishProfileFile)) ">
<WebPublishProfileCustomizeTargetFile Condition="'$(WebPublishProfileCustomizeTargetFile)'==''">
$([System.IO.Path]::ChangeExtension($(WebPublishProfileFile), '.wpp.targets'))
</WebPublishProfileCustomizeTargetFile>
...
So that looks to be setting up a filename of PROJECTNAME.wpp.targets, but only when the EnableWebPublishProfileFile property is set to true. I added this to my wixproj file's main propertygroup:
<EnableWebPublishProfileFile>False</EnableWebPublishProfileFile>
Again though, it made no difference at all to the error. I'm running out of ideas here now!
Further update
I've been trying to repo this on a blank project (so far without success), and the messing about has narrowed the error down to this line (186) in the Microsoft.Web.Publishing.targets file:
<Import Project="$(WebPublishPipelineCustomizeTargetFile)"
Condition="'$(WebPublishPipelineCustomizeTargetFile)' != ''"/>
This is set at the top of the file:
<WebPublishPipelineCustomizeTargetFile
Condition="'$(WebPublishPipelineCustomizeTargetFile)'==''">
$(WebPublishPipelineProjectDirectory)\*.wpp.targets
</WebPublishPipelineCustomizeTargetFile>
I'm not sure how this is getting changed to PROJECTNAME.wpp.targets though?
I tried overriding this in my project file, but once again, it makes no difference at all.
Next I added an Exists() condition to the line in the targets file, now some projects are working and others are not, instead failing (on build) with the error:
The "DisableEscapeMSBuildVariable" parameter is not supported by the "ImportParametersFile" task. Verify the parameter exists on the task, and it is a settable public instance property.
My journey continues...
I experienced the same issue when trying to open a standard web project.
The proj file was referencing the following import for v10.0 targets but throwing the import error in the question which referred to v10.5 targets.
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets" />
The same was true when I referenced a hard coded path - I still got v10.5 error
My solution was to simply back up and remove that version located at:
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\10.5
I'm really not sure what other programs and projects need this version or why import paths were not followed but it go this project open for me seeming falling back to the correct version.

What is incremental clean in msbuild and when is it triggered?

I am debugging a bug in my build process that happens occasionally but I can't directly reproduce it. I'm using msbuild with teamcity.
I have a dependency hierarchy like this:
Some.Interop.dll
Dependency-> SharedDllABC.dll
SomeService.exe
Depenendcy-> Some.Interop
Usually the final service exectuable gets in its release directory:
Some.Interop
SharedDllABC.Dll
ServiceExectuable.exe
However I can see in our msbuild logs that sometimes the tertiary dependency gets deleted during an Incremental Clean after everything is built resulting in:
Some.Interop
ServiceExectuable.exe
You can see it here in the msbuild log:
[src\SomeService\SomeService.csproj] _TimeStampAfterCompile
[12:32:43]: [src\SomeService\SomeService.csproj] Compile
// some other targets
[12:32:43]: [src\SomeService\SomeService.csproj] _CopyFilesMarkedCopyLocal
[12:32:43]: [_CopyFilesMarkedCopyLocal] Copy
[12:32:43]: [Copy] Copying file from "C:Projects\trunk\src\Some.Interop\bin\Release\Some.Interop.dll" to "bin\Release\Some.Interop.dll".
// some other targets
[src\Project\SomeService\SomeService.csproj] IncrementalClean
[18:54:42]: [IncrementalClean] Delete
[18:54:42]: [Delete] Deleting file "C:\Projects\trunk\src\Project\SomeService\bin\Release\SharedDllABC.dll".
[18:54:42]: [Delete] Deleting file "C:\Projects\trunk\src\Project\SomeServiceService\bin\Release\SharedDllABC.pdb".
[18:54:42]: [src\Project\SomeService\SomeService.csproj] CoreBuild
[18:54:42]: [src\Project\SomeService\SomeService.csproj] AfterBuild
[18:54:42]: [src\Project\SomeService\SomeService.csproj] Build
This is my direct msbuild output, I just changed the project names/dll names to match my example. By the time this Incremental Clean has occurred the SomeService.csproj has already been built. You can see that its not getting copied. However in other msbuild logs it does properly get copied and then the incremental clean doesn't delete it.
I think incrementeal clean from this post is supposed to clean dll's that were created from previous builds, but that doesn't explain how this dll didn't get built when most of the time it does. In visual studio this always works as well.
I guess I just want to know what exactly is Incremental clean, what causes it to kick in, and maybe what things I should look for when debugging a situation like this (assembly versions, timestamps, etc?)
Try the following:
Add:
<Target Name="IncrementalClean" />
to a .targets file that's included in all projects.
From --> https://github.com/Microsoft/msbuild/issues/1054
#Kebabbi recommends a good fix by editing a csproj file. As of MSBuild 15, there is a simple way to make this apply to all CSPROJ files, instead of editing each csproj file.
https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2017
Directory.Build.props and Directory.Build.targets
Prior to MSBuild version 15, if you wanted to provide a new, custom property to projects in your solution, you had to manually add a reference to that property to every project file in the solution. Or, you had to define the property in a .props file and then explicitly import the .props file in every project in the solution, among other things.
However, now you can add a new property to every project in one step by defining it in a single file called Directory.Build.props in the root folder that contains your source. 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. Directory.Build.props is a user-defined file that provides customizations to projects under a directory.
Create a file Directory.Build.props, and place it adjacent to the SLN file.
<Project>
<Target
Name="ForceAssignProjectConfigurationBeforeSplitProjectReferencesByFileExistence_KLUDGE"
BeforeTargets="_SplitProjectReferencesByFileExistence"
DependsOnTargets="AssignProjectConfiguration" />
</Project>
This could be caused by a bug in MsBuild: https://github.com/Microsoft/msbuild/issues/1054.
A fix is proposed in the comments: https://github.com/Microsoft/msbuild/issues/1054#issuecomment-406438561
When MsBuild determines which items to copy from referenced projects, it should do this recursively but does not properly do this.
As a workaround the following can be added to each csproj.
<Target
Name="ForceAssignProjectConfigurationBeforeSplitProjectReferencesByFileExistence_KLUDGE"
BeforeTargets="_SplitProjectReferencesByFileExistence"
DependsOnTargets="AssignProjectConfiguration"
/>
I just spent a few days trying to figure this out with a similar pattern. In our case it was nuget files that were being removed from the output folder.
NugetPackage (that drops files in x86/x64 subfolders in output folder)
LibraryA.dll
Dependency-> NugetPackage
LibraryB.dll
Dependency-> LibraryA.dll
In our case, we have a number of solution files that are built as part of an msbuild script in a certain order.
The problem was that LibraryB.csproj was included in two solution files.
Solution1 builds and output files are all present.
Solution2 builds and sees that LibraryB.dll is present and up to date, so for some reason triggers the IncrementalClean that removes the NugetPackage files from the output folder.
Once I removed the LibraryB.csproj from solution 2, the problem is solved and the files are present in the output folder.

How do I compile a single source file within an MSVC project from the command line?

I'm about to start doing some benchmarking/testing of our builds, and I'd like to drive the whole thing from a command line. I am aware of DevEnv but am not convinced it can do what I want.
If I could have a single file built within a single project, I'd be happy.
Can this be done?
The magical incantation is as follows. Note that this has only been tested with VS 2010 - I have heard this is the first version of Visual Studio with this capability:
The Incantation
<msbuild> <project> <settings> <file>
Where
msbuild is a path to MSBuild.exe. Usually this should be set up for you by the VS2010 bat file so the right one will end up in your PATH, but if not I found one at C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe
project is the path to the vcxproj file within which your source file resides.
settings include the following:
/p:Configuration="Debug" // or whatever your Configuration is
/p:Platform=x64 // or x86
/t:ClCompile // to specify specifically you're looking to compile the file
file is actually another setting:
/p:SelectedFiles="path_to_file"
Notes
For <project> I had to specify a project (vcxproj) file instead of a solution (sln) file. The sln I would have used has multiple projects within it, so there would have been extra work to go that route anyhow (if it can even be done).
For the /p:Platform=x64 setting, there are several environment variables that pivot on what platform you are targeting (x64 v. x86) so make sure you set those up properly via Visual Studio's vcvarsall.bat.
Regarding path_to_file in the SelectedFiles parameter, this path must be the path as specified in the project file. If the path does not match the path used in the project file to reference the source, it doesn't seem to work.

Fetching labeled files into a TFSBuild

I am sure there is a simple answer to this, but my google-fu fails me.
I have a team project in TFS 2008 that builds OK when using the latest code, however I now have a need to fetch the previous versions of a subset of the files at build time. The subset of files are all labeled with the same label ("MyLabel" in the snippet below).
The snippet of XML I have added to be TFSBuild.proj file looks like this:
<PropertyGroup>
<BuildLabel>LMyLabel</BuildLabel>
</PropertyGroup>
<Target Name="BeforeCompile">
<Get
TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
Condition=" '$(SkipGet)'!='true' "
Workspace="$(WorkspaceName)"
Recursive="$(RecursiveGet)"
Force="$(ForceGet)"
Version ="$(BuildLabel)"
Preview="false"
/>
</Target>
This successfully fetches the subset of files into the source area, however it also deletes all other files in the source area.
i.e. the build process does the following:
fetch latest versions of all files into the source area
fetch labeled version of subset of files into the source area
delete all non-labeled files from the source area
run build
The build fails with the following error:
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets(997,5): error MSB3491: Could not write lines to file "[build directory]\Sources\MySolution.sln.x64.Release.vsprops". Could not find a part of the path '[build directory]\Sources\MySolution.x64.Release.vsprops'.
(which basically indicates that it can't find the solution, because it's been deleted)
I've tried adding the following snippet to the bottom of the XML:
<PropertyGroup>
<SkipClean>true</SkipClean>
<SkipInitializeWorkspace>true</SkipInitializeWorkspace>
<ForceGet>false</ForceGet>
</PropertyGroup>
</Project>
but the result is the same.
So, my question is: how do I build my solution when it is a mixture of latest versions and older, labeled versions? What am I missing?
(I realize I could just branch the baseline but for various reasons I would like to explore this approach first)
Thanks in advance!
Just a simple approach that come to mind:
Get your latest version to workspace1
Get your labeled version to workspace2
XCopy workspace1 content over workspace2 as a post-get action
What do you think? Worth the try?
Looking at C:\Program Files\MSBuild\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets, it appears that the version fetched for the build is controlled by the GetVersion property. And that ForceGet is true by default.
I haven't tested it, but that implies to me that if you put
/property:GetVersion=*versionspec*
in the MSBuild Command Line Arguments textbox when you queue the build, it should fetch the specified version (look here for versionspec syntax. If this fails for some reason, read Aaron Hallberg's blog until you understand msbuild better than I do:-)

Anyone else notice that $(SolutionDir) resolves to ProjectDir when loading Wix projects into Vs2010?

I'm using Vs2010 and Wix 3.6.0917.0, for the record. I use the $(SolutionDir) property quite a bit in my .wixproj file, since I only ever build the installer as part of a solution build or as part of a team build, and never by itself. However, while building from the command line works just fine (both from cmd on the desktop and when building on build agents), when I attempt to reload the .wixproj file into the IDE, I get errors because all the $(SolutionDir) variables are resolving to the project directory, not the solution directory. Consider:
C:\workspace\projectCollection\teamProject\branch\solution.sln
C:\workspace\projectCollection\teamProject\branch\source\installer\installer.wixproj
and assume a shared custom targets file:
C:\workspace\projectCollection\teamProject\branch\build\shared.targets
which is referenced inside installer.wixproj with:
<Import Project="$(SolutionDir)build\shared.targets">
Command line builds work fine...
C:\workspace\projectCollection\teamProject\branch\> MSBuild /t:build /property:Platform=x64;Configuration=Debug solution.sln
0 Errors
0 Warnings
Build succeeded!
But load into vs2010 and you see...
The imported project
"C:\workspace\projectCollection\teamProject\branch\source\installer\build\shared.targets" was not found.
Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.
C:\workspace\projectCollection\teamProject\branch\source\installer\installer.wixproj
You can see here that the resolved result of $(SolutionDir)build\shared.targets is getting the project directory and not the solution directory. What gives?
My guess would be that $(SolutionDir) resolves to nothing when the wixproj is being loaded into VS2010. In this case the imported file becomes "build\shared.targets". Since the path is relative it is assumed to be relative to the project directory. Using ".." or some other path could get you around the problem.
I verified this failed with WiX 3.5.2222.0 in VS2010. A C# console application project (csproj) worked as expected.
Have you filed a bug against WiX for this?
I looked at the WiX vs2010 addin code a little bit and the Solution properties are only created when doing a build and not when the project is loaded.

Resources