MSBuild.ExtensionPack.tasks inheritance of variables from MSBuild main project file - visual-studio

Case:
When I build from MSBuild (with VS Build Tools 2017) I don't get any value for $(ExtensionTasksPath) variable
from main msbuild file, when I build with integrated VS MSBuild value is passed from main file to MSBuild.ExtensionPack.tasks, is that expected behavior and why does it happen? I don't use any properties for the sake of testing that particular case.

Is that expected behavior and why does it happen?
I think it's not we expect.As I test on a VM, the msbuild from VS Build Tools2017 get the same value as what we can get in msbuild from VS IDE.
For the reason of this behavior I have some suggestions to help trouble
shooting:
1.First of all, make sure both two scenarios builds successfully.
2.As you mentioned above, you runs them in separate VMs, make sure the two file under test are the same and entire solution folder.(The package folder under solution directory makes sense)
3.Check in the .xxproj file, check if exists <Import Project="..\packages\MSBuild.Extension.Pack.1.9.1\build\net40\MSBuild.Extension.Pack.targets" ...>
I've found the $(ExtensionTasksPath) property is defined in MSBuild.Extension.Pack.targets file, and this file is imported into .xxproj file by <Import> tag.
Have a look at pics below from my sample project which install MSBuild.Extension.Pack by nuget:
After my project install the extension bu nuget, there is an Import sentence in csproj file, open it we can find:
The value of $(ExtensionTasksPath) in defined here. So i guess you may have sth missing with the targets file or the import sentense or have sth corrupt this property.
In summary:
1.keep the entire solution folder could be the best suggestion.
2.And if it not works, add a script below to your .xxproj file can work:
<PropertyGroup>
<ExtensionTasksPath> Absolute path of your MSBuild.ExtensionPack.dll</ExtensionTasksPath>
</PropertyGroup>
It will overwrite values from tag and no matter where you put the assembly, just add the absolute path can work.
It my answer is helpful, please give me a feedback. And any update please feel free to contact me.

Related

Possible to limit the scope of Directory.Build.Props to a single Visual Studio Solution?

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.

OctoPack not populating placeholders in nuspec file

I have a solution with many projects, about a dozen of which have Octopack installed and packages are being produced correctly when TeamCity runs msbuild /p:RunOctoPack=true /p:OctoPackEnforceAddingFiles=true. As you can probably tell from the p:/OctoPackEnforceAddingFiles flag, each project with Octopack installed also has a nuspec file.
The problem we're having is that Octopack is not honouring the nuspec placeholders as specified at https://learn.microsoft.com/en-gb/nuget/reference/nuspec#replacement-tokens. The one we want to use right now is $id$ which should equal the assembly name of the project being packaged. Instead, when we run Octpack, that $id$ token is empty.
I can see at https://octopus.com/docs/packaging-applications/creating-packages/nuget-packages/using-octopack#UsingOctoPack-Replacementtokens that Octopack allows one to manually override these tokens, but that doesn't help me since Octopack is run on the solution, but I need the name of the project that is being packaged.
What can I do to get around this issue? At the moment we essentially have the project name hardcoded in the nuspec files, but this is becoming brittle and unwieldy and we'd like to fix it.
I have this working by adding the following to the csproj file
<PropertyGroup>
<OctoPackNuGetProperties>id=$(AssemblyName)</OctoPackNuGetProperties>
</PropertyGroup>
This passes the assembly name through as id to Octo.exe, which will in turn pass it through to NuGet.exe via its -Properties argument.
Have you tried not providing the $id$ section at all in NuSpec? Octopack should try and generate it (it knows what it is being applied to)?
Alternative could be to use the pre-build event with the $(ProjectName) macro to update the relevant nuspecs. In your case, depending on your build process, potentially sticking to a solution wide pre-build process to update all nuspec's.
P.S. I personally stepped away from using Octopack and currently employ Fake (F# Make).

Using the solution's configuration name as a test condition for MSBuild Target

I finally realized why my BeforeBuild Target is no longer executing as expected -- it's so silly, it's because the project's configuration names had changed. But what I really want to do is test for the solution's configuration name, not the project's.
I know that the project's configuration name is stored in $(Configuration). Is there one for the solution's configuration name? Or is this simply not possible because (presumably) the solution names are only known to the configuration manager? If so, can anyone recommend a good method for managing configurations? I'd hate to have to add duplicate project configuration names everywhere...
UPDATE: after searching and reading some docs, I haven't been able to find any proof that MSBuild is aware of the solution's configuration name when its individual project files are compiled. I went ahead and build the solution from the command line, passing /v:diag, and dumped the output to a file. I searched through the file to find any signs of it knowing that the solution's configuration name is "Deployment", but the only occurences of that string appear when the BeforeBuild condition is checked.
See my other answer. I was able to create a VS extension to get the solution configuration name as a build macro ($(variable) notation).
The only solution I've come up with so far is to create my own environment variable on the TeamCity server, and have MSBuild check for its presence in the BeforeBuild target.
EDIT: I couldn't use my own environment variable because it wasn't getting passed to the build runner for some reason. But when I used /v:n in the TeamCity MSBuild settings, I noticed that there is $(COMPUTERNAME), which is exactly what I wanted anyway. I ended up trying this and it totally did the trick.
There is property SolutionConfigurationContents witch is created by Msbulid during soluton file processing it contains solution configuration in it. When building from VS it will contains project (not solution) configuration.

How to prevent the copy of XML documentation files in a release mode build?

I have a Visual Studio 2010 project which references some third-party components. Their assemblies are accompanied by XML documentation files, which are useful for us (and only us) developers. And whenever the project is built (either in Debug or Release modes) these XML files are copied to the build directory.
I can't seem to find a setting or switch to disable the copy of those XML files to the build directory, either within Visual Studio or though MSBuild. A post-build script may be an option, but a smelly one. Any ideas? Thank you.
When you build a project the .xml/.pdb files are gathered through the ResolveAssemblyReference task. When ResolveAssemblyReference is called it is passed a list of file extensions for related files. That list of file extensions is captured in the MSBuild property AllowedReferenceRelatedFileExtensions. By default that list will contain ".pdb;.xml".
If you want to exclude all related reference files from being picked up then just override the value of the property to something which related files won't have extensions of. For example you can set AllowedReferenceRelatedFileExtensions to "-".
You can also customize the list of file which are returned by that. If you only want to find only .pdb files then you will need to pass in AllowedReferenceRelatedFileExtensions=".pdb". In that case any references which have .pdb file next to the .dll/.exe they will be copied as well. You can also use this to copy other related files which may not end in .pdb/.xml. For example if you have a referenced assembly named, MyAssembly.dll and in that same folder there exists MyAssembly.pdb and MyAssembly.foo If you set AllowedReferenceRelatedFileExtensions=".pdb;.foo" then both the .pdb and .foo file will be copied to the output directory.
Visual studio project file has the same format as any msbuild file. So you can manually add the condition into corresponding section to not copy your xml files if configuration name is 'Release'.
It should be changing
<ItemGroup>
to
<ItemGroup Condition="'$(CONFIG)'=='RELEASE'">
or something like this.
If the .xml/.pdb are marked as build-action "Content" (etc), you can change them to "None". You should also ensure they copy-to-build-output is false.
Are both of those set?
What is the problem with having the XML files get copied into the folder on release builds? It seems to me that this is fine and that the real problem is with the code that picks up files to place them in the installer. Picking up third party dlls from your own bin\release folder is not a good practice in my opinion. I'd have my installer pick up third party dlls from their own folder in my source tree.
The setting is in the Properties of the project in question, under the "Build" tab, uncheck "XML documentation file". It's also an MSBuild property called <DocumentationFile> under the applicable <PropertyGroup> for your build configuration in the .*proj file.

Visual Studio msbuild

I have a question regarding the commandline options of msbuild. I am
currently using msbuild to build projects using the existing solution
files. These solution files have references to external dll which have
different paths on each machine. I am currently writing a build script
and passing the specific path to the project file via the /p: switch of
msbuild.
My current build line is:
msbuild test.sln /p:ReferencePath="c:\abc" /p:ReferencePath="c:\rca"
What i have noticed that Reference Path now contains only c:\rca and
not c:\abc. this is causing problems for me since, the external dlls
lie in two different directorys. I am allowed to keep multiple
reference paths via visual studio, but not via the commandline.
Is there any known way by which i can do this
I believe you can use this /p:ReferencePath="c:\abc;c:\rca"
At least that is what that link is hinting at, they are using %3B to encode the ";" within the build file.
Although the correct syntax for providing more the one reference path is listed above, I would suggest solving the root cause which in my opinion is the different locations of your referenced assembly. I would suggest you put all thirdparty dependencies, apart from the framework assemblies in your source code repository for the following reasons:
Relatitve paths are consistent across computers
The source code is always in sink with the correct version of your thirdparty assembly (if you for instance need to build an old version of your software 2 years from now).
Upgrading your thirdparty assembly is as easy as upgrading on one machine and then committing your changes to the repository. (In a previous project we even went as far as checking in the entire java runtime environment and were quite happy with the given setup.)
Try seperating your pathes with a semi-colon (;)
Like this:
c:\abc;c:\rca
You may be better off by synchronizing your libraries across machines. I have found that Visual Studio makes this easy. Simply add a solution folder, and add your libraries there. Then, in each project, reference the libraries from this common place. This way, each developer has them in the same place.
This will remove one of variables you have when trying to script out builds.
The command line options for setting the reference path will work just fine (assuming you escape the semi colon, it seems both %3B and ; will work). However, when the argument was passed in from nant (and I needed multiple paths), creating a 'Visual Studio Project User Options file' seemed to work better.
I just emit (echo) a file to the file system with the following format:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ReferencePath>
C:\abc;c:\rca
</ReferencePath>
</PropertyGroup>
I give the *.user file an appropriate name (given a project file MyProject.csproj, my user file would be MyProject.csproj.user)

Resources