MSBuild not finding the DLL - msbuild

I emit a console app with Mono.Cecil and I want to integrate MSBuild into the build process. But then when I run dotnet build on my custom project file, MSBuild throws an error saying Expected file "obj\Debug\net5.0\refint\test.dll" does not exist. It's trying to find the generated assembly inside the refint folder. When the assembly gets generated inside obj\Debug\net5.0\test.dll as it should. Is there a way I can change the path where MSBuild looks for the output assembly? Everything on the side of the IL generator works, I even get a runnable exe inside the build folder. Here's my project file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<OutputType>Exe</OutputType>
<DefaultLanguageSourceExtension>.ao</DefaultLanguageSourceExtension>
<OutputPath>C:\Users\filip\source\alto\samples\test\obj\Debug\net5.0\</OutputPath>
</PropertyGroup>
<Target Name="CreateManifestResourceNames" />
<Target Name="CoreCompile" DependsOnTargets="$(CoreCompileDependsOn)">
<Exec Command="dotnet run --project "$(MSBuildThisFileDirectory)\..\..\src\aoc\aoc.csproj" -- #(Compile->'$(MSBuildThisFileDirectory)', ' ') /o "#(IntermediateAssembly)" #(ReferencePath->' /r "%(Identity)"', ' ')"
WorkingDirectory="$(MSBuildProjectDirectory)" />
</Target>
</Project>
Thank you in advance.

I didn't read the whole error message.
C:\Program Files\dotnet\sdk\6.0.100-preview.7.21379.14\Microsoft.Common.CurrentVersion.targets(4527,5): error : Expected file "obj\Debug\net5.0\refint\test.dll" does not exist.
It actually points me to a file where the error was thrown. This is where:
<!-- Copy the reference assembly build product (.dll or .exe). -->
<CopyRefAssembly
SourcePath="#(IntermediateRefAssembly)"
DestinationPath="$(TargetRefPath)"
Condition="'$(ProduceReferenceAssembly)' == 'true' and '$(CopyBuildOutputToOutputDirectory)' == 'true' and '$(SkipCopyBuildProduct)' != 'true'"
>
<Output TaskParameter="DestinationPath" ItemName="ReferenceAssembly"/>
<Output TaskParameter="DestinationPath" ItemName="FileWrites"/>
</CopyRefAssembly>
It's trying to make a reference assembly when I don't need one. So I just set the ProduceReferenceAssembly property to false, since I don't need one.

Related

Stopping Post Build events on project when building directly from MSBuild

I have a project which has some post build events that do some copying around for other projects. I unfortunately cannot change that, and have been asked to write a build script for use on a CI server.
Problem is that the post build steps run off the debug/release bin folders and I compile through the build script to a different folder. So one solution would be to let the project build as is, and then manually copy all files from the bin folders to the output folder I am using. However that feels like a bit of a hack, so I was wondering if there is a way for an MSBuild task to tell the solution it is building to ignore PostBuild events, I believe you could set a property PostBuildEvent='' but it didnt seem to stop them from happening...
Here is an example of the build script target:
<Target Name="Compile" DependsOnTargets="Clean;">
<MSBuild Projects="$(SourceDirectory)\SomeSolution.sln"
Properties="Configuration=Release; OutputPath=$(CompilationDirectory); PostBuildEvent=''" />
</Target>
Anyone had to do anything similar before?
To disable all PostBuildEvents, set the CustomAfterMicrosoftCommonTargets to C:\PostBuild.config (or whatever you name the file) and have PostBuild.config to be:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="PostBuildEvent"/>
</Project>
Add /p:CustomAfterMicrosoftCommonTargets="C:\PostBuild.config" to your msbuild command line
Or update your MsBuild task properties:
<MsBuild Projects="$(ProjectTobuild)" Properties="Configuration=$(Configuration);Platform=$(Platform);CustomAfterMicrosoftCommonTargets='C:\PostBuild.config'" Targets="Build"/>
To disable PostBuildEvents at project level for MSBuild, simply put these codes inside .csproj:
<Target Name="BeforeBuild">
<PropertyGroup>
<PostBuildEvent Condition="'$(BuildingInsideVisualStudio)' == 'false' Or '$(BuildingInsideVisualStudio)' != 'true'"></PostBuildEvent>
</PropertyGroup>
</Target>

Change working directory of msbuild.exe

I am executing MSBuild from a batch file. The MSBuild script is in a different directory than the directory I want MSBuild to consider the working directory when running the script. When invoking MSBuild.exe, how do I change its working directory?
Edit: More details
Let's say I have an MSBuild script located on some other server. I want to run a command thusly:
msbuild.exe \\my_server\c$\My\Path\To\Scripts\TestScript.msbuild
I run that command with my command prompt at c:\temp. Let's say my TestScript.msbuild has a task to create a file. The file has no path just a filename. I would expect that the file gets created inside c:\temp. But it doesn't it gets created next to the msbuild file that is sitting on the server. This is the behavior I want to change.
Edit #2
Here is the script I'm using in my test:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Files Include="HelloWorld.txt" />
</ItemGroup>
<Target Name="TouchFiles">
<Touch Files="#(Files)" AlwaysCreate="True" />
</Target>
</Project>
I am going into a command shell CDing into c:\temp and then executing the script. With or without the /p:OutDir switch that #Nick Nieslanik mentions, the HelloWorld.txt file appears in the folder where the *.msbuild file is and not c:\temp.
I ran across this while looking for a solution to my problem. Here's my solution (build script):
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Default">
<Exec Command="build.bat" WorkingDirectory="..\[your dir]\" />
</Target>
</Project>
I believe that's more what you were originally looking for?
My problem was that my batch file called another that it expected to be in the same directory, but since my ms build script was being run elsewhere, the batch file failed to find the second batch file.
#jkohlhepp - I see now. You are doing the opposite of what I described in my comment to some degree.
MSBuild common targets use the MSBuildProjectDirectory to determine the output folder unless you override that. So in your case, you could run
msbuild.exe \\my_server\c$\My\Pat\To\Scripts\TestScript.msbuild /p:OutDir=c:\temp
to force the output to be dropped in that location.
EDIT:
Given the project file above, you'd need to edit it to do something like the following for this to work:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<OutDir Condition=" '$(OutDir)' == '' ">bin\debug\</OutDir>
</PropertyGroup>
<ItemGroup>
<!-- Without prefacing files with paths, they are assumed relative to the proj file -->
<FilesToCreate Include="$(OutDir)HelloWorld.txt" />
</ItemGroup>
<Target Name="TouchFiles">
<Touch Files="#(FilesToCreate)" AlwaysCreate="True" />
</Target>
</Project>
In current versions of MSBuild the well-known property MSBuildStartupDirectory can be used in the msbuild file to retrieve the absolute path of the folder where MSBuild is called.
https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-reserved-and-well-known-properties?view=vs-2019
This option perhaps did not exist in msbuild around the time when the question was asked. I didn't want to spend too much time investigating it.

Property scope using msbuild extension pack detokenise

Im trying to use the msbuild extensions pack to fix up the configuration of our app on deploy,
i want to be able to pass a property (ENV) which will load my environment specific config file to use with the detokeniser, and fix up my application configs.
Like this:
<UsingTask TaskName="MSBuild.ExtensionPack.FileSystem.Detokenise"
AssemblyFile=".\Tools\MSBuild Extension Pack 4.0.3.0\MSBuild.ExtensionPack.dll"/>
<Import Project=".\Environments\$(Env).properties"/>
<Target Name="Build" >
<ItemGroup>
<SourceTemplates Include=".\Templates\**\*.*"/>
</ItemGroup>
<RemoveDir Directories=".\Temp"/>
<MakeDir Directories=".\Temp"/>
<Message Text="#(SourceTemplates)"/>
<Copy SourceFiles="#(SourceTemplates)"
DestinationFolder=".\Temp\%(RecursiveDir)" />
<ItemGroup>
<TargetTemplates Include=".\Temp\**\*.*"/>
</ItemGroup>
<MSBuild.ExtensionPack.FileSystem.Detokenise
TaskAction="Detokenise"
TargetFiles="#(TargetTemplates)"/>
</Target>
So i call this using
msbuild Detokenise.msbuild /p:Env=Prod
Msbuild knows about my file and i have access to its properties, but when the detokeniser runs i get the error:
Detokenise Task Execution Completed [15:07:50]
C:\Source\1.2\Build\Detokenise.msbuild(27,3):
error : InvalidProjectFileException: The imported project "C:\Source\1.2\Build\Environments\.properties" was not found.
Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.
C:\Source\1.2\Build\Detokenise.msbuild\r
C:\Source\1.2\Build\Detokenise.msbuild(27,3): error :
All works fine if i hard code it-
Any ideas how to solve this. I thought of doing some text replacement on the msbuild before i execute...
You could try to assign this parameter to a local property:
<PropertyGroup Condition="'$(Env)'=='Prod'">
<TargetEnv>Prod</TargetEnv>
</PropertyGroup>
<!-- add other environments as needed -->
<PropertyGroup Condition="'$(Env)'=='Test'">
<TargetEnv>Test</TargetEnv>
</PropertyGroup>
<Import Project=".\Environments\$(TargetEnv).properties"/>
You could also try to enclose your parameter value in quotes:
msbuild Detokenise.msbuild /p:"Env=Prod"
As is your problem can't be reproduced, so it may be a side effect of other parameters not shown in your sample code.
I've seen a number of other questions where a similar problems was happening:
Visual Studio Ignoring MSBuild file (csproj) Customizations

msbuild exec task call msbuild

I need to call exec and build a wix setup project.
Currently I have the following in my TFSbuild.proj
<PropertyGroup>
<WebRoot>$(DropLocation)\Latest\x86\Release\_PublishedWebsites\Web</WebRoot>
<DBRoot>$(DropLocation)\Latest\x86\Release\Database</DBRoot>
</PropertyGroup>
<PropertyGroup>
<Msbuildexe>"msbuild"</Msbuildexe>
<Configuration>"/p:Configuration:"Release""</Configuration>
<DefineConstants>" /p:DefineConstants:"WebRoot=$(WebRoot);DBRoot=$(DBRoot)""</DefineConstants>
<WixSolution>"$(MSBuildProjectDirectory)\Setup\Setup.sln"</WixSolution>
</PropertyGroup>
<Message Text="Bulding setup solution" />
<Message Text="$(Msbuildexe) $(Configuration) $(DefineConstants) $(WixSolution)" />
<Exec Command="$(Msbuildexe) $(Configuration) $(DefineConstants) $(WixSolution)" />
I've tried to simply as much as possible so I don't get confused where the " are meant to be. When I run this the debug message (2nd last command) outputs
"msbuild"
"/p:Configuration:"Release"" "
/p:DefineConstants:"WebRoot=\server\drops\app\Installer Build\Latest\x86\Release_PublishedWebsites\Web;DBRoot=\server\drops\app\Installer Build\Latest\x86\Release\Database""
"f:\builds\app\Installer Build\BuildType\Setup\Setup.sln"
And I get the following error in the log
'"msbuild"' is not recognized as an
internal or external command,
operable program or batch file.
f:\builds\app\Installer
Build\BuildType\TFSBuild.proj(538,5):
error MSB3073: The command ""msbuild"
"/p:Configuration:"Release"" "
/p:DefineConstants:"WebRoot=\server\drops\app\Installer Build\Latest\x86\Release_PublishedWebsites\Web;DBRoot=\server\drops\app\Installer Build\Latest\x86\Release\Database""
"f:\builds\app\Installer
Build\BuildType\Setup\Setup.sln""
exited with code 9009.
I'm not sure if this is being caused by not being able to call the msbuild command from the command line or a " issue. If it is because I can't call msbuild from the command line like this how would I go about referencing it, is there a property that points to it?
To start with, you don't need most of the quotes, especially if the paths you are using don't contain spaces, but I'd trim it down to this, allowing for spaces in the paths for $(WebRoot), $(DbRoot) and $(MSBuildProjectDirectory):
<PropertyGroup>
<WebRoot>$(DropLocation)\Latest\x86\Release\_PublishedWebsites\Web</WebRoot>
<DBRoot>$(DropLocation)\Latest\x86\Release\Database</DBRoot>
</PropertyGroup>
<PropertyGroup>
<MsbuildExe>{still-needs-a-path-to}\msbuild</MsbuildExe>
<Configuration>/p:Configuration:Release</Configuration>
<DefineConstants>/p:DefineConstants:"WebRoot=$(WebRoot);DBRoot=$(DBRoot)"</DefineConstants>
<WixSolution>"$(MSBuildProjectDirectory)\Setup\Setup.sln"</WixSolution>
</PropertyGroup>
<Message
Text="Bulding setup solution"
/>
<Message
Text="$(MsbuildExe) $(Configuration) $(DefineConstants) $(WixSolution)"
/>
<Exec
Command="$(MsbuildExe) $(Configuration) $(DefineConstants) $(WixSolution)"
/>
However, you still won't be able to execute MSBuild with this, since the path to MSBuild isn't specified. It is typically found in the $(WINDIR)\Framework\Microsoft.Net\v4.0.30319 folder. There are a few ways to get this, either encode it directly, rely on an environment variable (that has to be set up somehow), use the predefined $(MSBuildBinPath), or extract it from the registry using the MSBuild registry syntax, which would look like this:
$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0\MSBuildToolsPath)
However, it isn't clear why you are running MSBuild using Exec rather than just using the MSBuild task. Change the line with Exec to this:
<MSBuild
Project="$(WixSolution)"
Properties="$(DefineConstants)"
/>
removing your declaration for <Configuration> and changing <DefineConstants> to this:
<DefineConstants>Configuration=$(Configuration);WebRoot=$(WebRoot);DBRoot=$(DBRoot)</DefineConstants>
Following up on my comment I'd suggest you try using the MSBuild Task instead of Exec:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="BuildWiXSolution">
<!-- Include the custom build targets installed with WiX -->
<Import Project="$(MSBuildExtensionsPath)\Wix\Wix.targets"/>
<PropertyGroup>
<WebRoot>$(DropLocation)\Latest\x86\Release\_PublishedWebsites\Web</WebRoot>
<DBRoot>$(DropLocation)\Latest\x86\Release\Database</DBRoot>
</PropertyGroup>
<ItemGroup>
<WiXSolution Include="$(MSBuildProjectDirectory)\Setup\Setup.sln">
<Properties>Configuration=Release</Properties>
<AdditionalProperties>WebRoot=$(WebRoot);DBRoot=$(DBRoot)</AdditionalProperties>
</WiXSolution>
</ItemGroup>
<Target Name="BuildWiXSolution">
<MSBuild Projects="#(WiXSolution)" />
</Target>
</Project>
It allows you to keep configuration properties and additional properties together with your Wix solution.

Problems using MsBuild using command line for Publish Click Once

I have Windows application in csproj in my solution, and I want generate Publish using command line (bat, cmd).
My script is (I put \r\n for better reading):
SET MSBUILD="%SystemRoot%\Microsoft.NET\Framework\v3.5\MSBuild.exe"
SET CARWIN="..\..\Security.CarWin.csproj"
rem msbuild para publish
%MSBUILD% /target:rebuild;publish %CARWIN%
/p:ApplicationVersion="1.0.0.0"
/p:Configuration=release
/p:PublishUrl="C:\ClickOnce\CarWin.WebInstall\Publicacion\"
/p:InstallUrl="http://desserver/carwinclickonce/Publicacion/"
/p:PublishDir="C:\ClickOnce\CarWin.WebInstall\Publicacion\"
note: I'll try too using /target:publish
But in path PublishDir or PublishUrl (C:\ClickOnce\CarWin.WebInstall\Publicacion) not generates any files.
I have seen many posts in this site and google but I not found any solution.
Use PublishDir instead of PublishUrl when running from command line.
msbuild /target:publish /p:Configuration=Release;PublishDir=c:\playground\
You can also change version, like ApplicationRevision=666;MinimumRequiredVersion=1.1
Take a look at this Stack Overflow question. Basically the PublishUrl property is ignored when running ClickOnce from the command line. But you can easily add the behaviour with an additional MSBuild-task.
I've created an additional MSBuild-File, for example a build.csproj. This contains a publish-task. This task first invokes the regular MS-Build of the target-project. Afterwards it copies the result to the publish-directory. Now I invoke the 'build.csproj' instead of the reguar project-file from the command-line:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Publish" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- project name-->
<ProjectName>MyExampleProject</ProjectName>
<!--properties for the project-build-->
<DefaultBuildProperties>Configuration=Release</DefaultBuildProperties>
<!-- location of the click-once stuff, relative to the project -->
<ProjectPublishLocation>.\bin\Release\app.publish</ProjectPublishLocation>
<!-- Location you want to copy the click-once-deployment. Here an windows-share-->
<ProjectClickOnceFolder>\\TargetServer\deployments</ProjectClickOnceFolder>
</PropertyGroup>
<Target Name="Publish" DependsOnTargets="Clean">
<Message Text="Publish-Build started for build no $(ApplicationRevision)" />
<!-- run the original build of the project -->
<MSBuild Projects="./$(ProjectName).csproj"
Properties="$(DefaultBuildProperties)"
Targets="Publish"/>
<!-- define the files required for click-once-->
<ItemGroup>
<SetupFiles Include="$(ProjectPublishLocation)\*.*"/>
<UpdateFiles Include="$(ProjectPublishLocation)\Application Files\**\*.*"/>
</ItemGroup>
<!-- and copy them -->
<Copy
SourceFiles="#(SetupFiles)"
DestinationFolder="$(ProjectClickOnceFolder)\"/>
<Copy
SourceFiles="#(UpdateFiles)"
DestinationFolder="$(ProjectClickOnceFolder)\Application Files\%(RecursiveDir)"/>
</Target>
<Target Name="Clean">
<Message Text="Clean project" />
<MSBuild Projects="./$(ProjectName).csproj"
Properties="$(DefaultBuildProperties)"
Targets="Clean"/>
</Target>
</Project>
I don't know if this is a problem, but I noticed that you pass the /target parameter twice?
you could you use a semi-colon delimited example:
/target:rebuild;publish
MSDN Documentation on command line parameters and MSBuild
If that also does not work you could perhaps try to debug it by passing
/verbosity:diag