My .csproj defines the following post build event in the .csproj file that regenerates a symbolic link. This works fine inside with a manual Visual Studio build and the symlink gets regenerated without issue:
<PostBuildEvent>
del C:\foo\foo\bin\debug\my.config
mklink C:\bar\bar\bar\bar\bar\bar\bin\debug\my.config c:\baz\baz\my.config
</PostBuildEvent>
However, I am trying to set up continuous integration using TFS2015 with automated builds using MSBuild, however in this case, the build fails with 'the command mklink C:\bar\bar\bar\bar\bar\bar\bin\debug\my.config c:\baz\baz\my.config exited with code 1'.
How do I go about regenerating a symbolic link via an automated build?
I resolved this by setting the variable $(BuildingInsideVisualStudio) to true inside my csproj file in the following way:
<PropertyGroup Condition="'$(BuildingInsideVisualStudio)' == 'true'">
<PostBuildEvent>
del C:\foo\foo\bin\debug\my.config
mklink C:\bar\bar\bar\bar\bar\bar\bin\debug\my.config c:\baz\baz\my.config
</PostBuildEvent>
</PropertyGroup>
I had seen this as a possible answer elsewhere, however the posts I saw showed incorrect syntax and did not clearly illustrate how to use the variable within the context of the csproj build script. Hopefully this will clarify for someone.
This MSDN article was useful:
https://msdn.microsoft.com/en-us/library/ms171468(v=vs.140).aspx
Related
How can I, through the .csproj file, specify environment variables to apply during the build, such as when building with Rider?
Specifically, I want to set DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 so that I can build from within the IDE, without resorting to the command line (see below).
Adding <InvariantGlobalization>true</InvariantGlobalization> to the project file did not work, since that does not affect the underlying/imported build target, but executing export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 before dotnet build NAME.csproj worked.
Background: A recent distro upgrade on openSuse Tumbleweed bricked MonoGame project builds with the following error message when invoking mgcb (re-installing ICU with Zypper did not fix the issue):
Couldn't find a valid ICU package installed on the system. Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support.
(...)
error MSB3073: The command "dotnet (...) exited with code 134
Edit: I have finally gotten a Target to run before the Nopipeline target using InitialTargets. The problem now is the Exec task runs in a discarded scope.
Depending on which task fails, you can hope that the target author added an option to set the environment variables.
E.g. for C# compilation, you could set:
<PropertyGroup>
<CscEnvironment>$(CscEnvironment);DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1</CscEnvironment>
</PropertyGroup>
If the tool is run by a custom target, you would need to author a replacement target that allows setting the environment variable.
I'm harvesting a directory for my Visual Studio solution.
It works on my local system so far probably because the project build order is being respected.
When I run the installer on a build server it finds the right directory but it has not been created at the time of building the setup file. It throws a HEAT5052 error saying The directory 'a:\b\c' could not be found.
Is there any way to "wait" until or to execute the heat command after all project references are built?
OK so I've spent hours to figure out how to fire Heat AFTER all references are resloved. I only found solutions for the <PreBuildEvent> and <PostBuildEvent> using the Heat command line and the BeforeBuild and AfterBuild targets.
So I found all kind of targets inside the wix2010.targets file located in my
Program files (x86)\MSBuild\Microsoft\Wix\ folder. It contains a target called AfterResolveReferences and it does exactly that. So here's my code I ended up with (in case someone is interested):
<Target Name="AfterResolveReferences">
<HeatDirectory
ToolPath="$(WixToolPath)"
OutputFile="Product.Binaries.wxs"
SuppressFragments="$(HarvestDirectorySuppressFragments)"
Transforms="Filter.xslt"
Directory="$(HarvestFolder)"
DirectoryRefId="MY_FOLDER"
ComponentGroupName="Binaries"
GenerateGuidsNow="true"
SuppressRootDirectory="true"
SuppressRegistry="true"
PreprocessorVariable="var.App.TargetDir">
</HeatDirectory>
</Target>
I had the same problem and it was solved by combining the accepted answer and this answer to ensure that my post build event, which was copying files, always runs:
<RunPostBuildEvent>Always</RunPostBuildEvent>
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
Also, my build server was using the MSBuild command line, and I used this answer to locate my local MSBuild.exe so I could test my changes locally without having to push to the build server.
I have a csproj that I would like to have trigger the opening of a particular file in Visual Studio, only if the target was executed from within Visual Studio, but not from the MSBUILD command line. How do I do this?
Quote from MSDN page:
When building inside Visual Studio, the property $(BuildingInsideVisualStudio) is set to true. This can be used in your project or .targets files to cause the build to behave differently.
Example how it could be used in your .*proj or .targets file:
<PropertyGroup>
<MyProperty Condition="'$(BuildingInsideVisualStudio)' == 'true'">This build is done by VS</MyProperty>
<MyProperty Condition="'$(BuildingInsideVisualStudio)' != 'true'">This build is done from command line of by TFS</MyProperty>
</PropertyGroup>
Add a property to the .csproj project file, example:
<PropertyGroup>
<FromMSBuild>false</FromMSBuild>
</PropertyGroup>
Then in the task you want to run, put a condition that evaluates that property. For example, i f you want to open notepad.exe whenever the build is executed from command line and NOT visual studio:
<Target Name="BeforeBuild">
<Exec Command="C:\Windows\Notepad.exe" Condition="$(FromMSBuild)" />
</Target>
Of course, this is dependent on setting the $(FromMSBuild) property correctly when you run the build via command line, like so:
MSBuild myProject.csproj /p:FromMSBuild=true
If I understand you correctly, you want to open a file when building in visual studio but not from command line with MSBuild?
If that is the case, specify a PreBuild or PostBuild in Visual Studio.
Right click on the project in the solution explorer and select Properties
Select the Events tab
Add either a Pre or Post Build event to open the desired file
I have a simple class library project (with Class1) and have enabled NuGet Package Restore for the solution.
That imports the restorepackages task into the .csproj file.
I can compile the project with
C:>msbuild myproj.csproj /t:compile
And I can call the restorepackages task successfully before adding packages with
C:>msbuild myproj.csproj /t:restorepackages
However, adding any package will cause the restorepackages task to fail with an error 3.
It seems that the NuGet task is called with a wrong working directory, and you may actually fix the behavior by removing the workingdir attribut in the NuGet.targets file, that was added to the solution.
Edit the task like this:
<Exec Command="$(RestoreCommand)"
LogStandardErrorAsError="true"
Condition="Exists('$(PackagesConfig)')"
WorkingDirectory="$(NuGetToolsPath)" />
and remove the working dir:
<Exec Command="$(RestoreCommand)"
LogStandardErrorAsError="true"
Condition="Exists('$(PackagesConfig)')"
/>
It seems to work as expected both from commandline msbuild and within VS2010.
Does anyone know if this change might break any tooling?
Can it be related to the issue "Package Restore's $(SolutionDir) goes too far"?
Did you check the injected SolutionDir property in your project file? It might be that the generated relative path won't point to the actual solution dir.
To an earlier question of mine, invovling VBC and NAnt with WinForms, I have since come up with a better way of stating this.
Within vbproj file, you have the following:
<ItemGroup>
<None Include="My Project\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<CustomToolNamespace>My</CustomToolNamespace>
<LastGenOutput>Settings.Designer.vb</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<Content Include="My Project\Application.myapp">
<Generator>MyApplicationCodeGenerator</Generator>
<LastGenOutput>Application.Designer.vb</LastGenOutput>
</Content>
</ItemGroup>
When one runs build from within Visual Studio (Debug Verbosity set to Normal), one of the lines produces is:
Target CoreCompile:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Vbc.exe ...
Which includes all of the settings required for vbc.exe to run. However, taking that string from Visual Studio, and running it directly on the command line yields:
... My Project\Settings.Designer.vb(67) : error BC30002: Type 'My.MySettings' is not defined.
Friend ReadOnly Property Settings() As Global.My.MySettings
...\My Project\Settings.Designer.vb(69) : error BC30456: 'My' is not a member of '<Default>'.
Return Global.My.MySettings.Default
How does one get the above Generators to run from a command line, or is there a call somewhere that will generate the correct temp files that are needed for vbc.exe to run the command string correctly?
The problem with looking at the build string within visual studio is that it's not actually calling vbc.exe to build from visual studio. All builds in visual studio happen with the in-memory compiler instead of the command line compiler (true for C# as well).
The command that looks like vbc.exe ... is a generated string that isn't actually executed. If you want to find out the correct string to build your project run the following code from a visual studio command prompt.
msbuild /v:diag myproject.vbproj
This will produce an msbuild log file (it will be quite long so I suggest piping to a file). Once the build is completed search for vbc.exe within that file. It will have the actual command line needed to build your project.
I spent a while working on this today. I'd like to know a proper answer as to how to get the vbc compiler to work properly in regard to the "My" namespace, but I managed to get my NAnt script working using NAnt contrib (http://nantcontrib.sourceforge.net/).
NAnt contrib allows you to build using the .NET msbuild, which at least allowed me to set up automated builds, notifications, etc. It does not give quite the granular control I would like, but it serves its purpose.
The reference on this task is:
http://nantcontrib.sourceforge.net/release/latest/help/tasks/msbuild.html
And the pertinent snippet from my build script:
<target name="build" depends="clean">
<msbuild project="ProjectName.vbproj" />
</target>
I've used NAnt quite a bit for CS applications, but this is the first for a VB.NET application.