Build csproj for MONO that requires dlls - dll

I have a line of code that I got from a site called Zetcode, and in this to build the first example, I compile the code like this:
gmcs -r:System.Windows.Forms.dll -r:System.Drawing.dll 01-simple-cs-example.cs -out:simple-sample.exe
This builds the exe that draws my window, but I don't think my csproj file is correct.
<Project DefaultTargest="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- This Property will make a variable named MSBuildSample, then you can use it to
assign to whatever in the script.
Properties are variables inside the script.
-->
<SrcPath>src\</SrcPath>
<AssemblyName>01-simple-cs-example</AssemblyName>
<OutputPath>bin\</OutputPath>
</PropertyGroup>
<ItemGroup>
<!-- This Compile statement, gathers all the source files listed in an item called Compiled
ItemGroups interact with the source code.
-->
<Compile Include="$(SrcPath)01-simple-cs-example.cs" />
</ItemGroup>
<!-- In the Build target, the Inputs and Outputs targets which looks to see if the files have been updated,
or if the files are existent. If the files have not been changed, then the Build target is skipped.
-->
<Target Name="Build" Inputs="#(Compile)" Outputs="$(OutputPath)$(AssemblyName).exe" >
<!-- The MakeDir directive will create the directory in the property group above, if it meets the
condition stated in the Condition= statement.
-->
<Message Text="Creating the output path $(OutputPath)." />
<MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
<!-- This Csc is the .NET C# compiler, which then uses the ItemGroup of collected sources called, Compile
-->
<Message Text="Compiling the source code." />
<Csc Sources="#(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
</Target>
</Project>
This is the result from trying to run xbuild, and msbuild.
C:\Users\User01\Dropbox\programming\csharp\zetcode-csharp-winforms\01-simple-cs-example>xbuild
XBuild Engine Version 3.3.0.0
Mono, Version 3.3.0.0
Copyright (C) Marek Sieradzki 2005-2008, Novell 2008-2011.
Build started 7/25/2014 2:47:41 PM.
__________________________________________________
Project "C:\Users\User01\Dropbox\programming\csharp\zetcode-csharp-winforms\01-simple-cs-example\01-simple-cs-example.csproj" (default target(s)):
Target Build:
Created directory "bin\"
Tool C:\mono\Mono-3.2.3\bin\gmcs.bat execution started with arguments: /out:bin\01-simple-cs-example.exe src\01-simple-cs-example.cs
src\01-simple-cs-example.cs(1,22): error CS0234: The type or namespace name `Forms' does not exist in the namespace `System.Windows'. Are you missing `System.Windows.Forms' assembly reference?
src\01-simple-cs-example.cs(2,14): error CS0234: The type or namespace name `Drawing' does not exist in the namespace `System'. Are you missing `System.Drawing' assembly reference?
src\01-simple-cs-example.cs(4,23): error CS0246: The type or namespace name `Form' could not be found. Are you missing an assembly reference?
Task "Csc" execution -- FAILED
Done building target "Build" in project "C:\Users\User01\Dropbox\programming\csharp\zetcode-csharp-winforms\01-simple-cs-example\01-simple-cs-example.csproj".-- FAILED
Done building project "C:\Users\User01\Dropbox\programming\csharp\zetcode-csharp-winforms\01-simple-cs-example\01-simple-cs-example.csproj".-- FAILED
Build FAILED.
Errors:
C:\Users\User01\Dropbox\programming\csharp\zetcode-csharp-winforms\01-simple-cs-example\01-simple-cs-example.csproj (default targets) ->
(Build target) ->
src\01-simple-cs-example.cs(1,22): error CS0234: The type or namespace name `Forms' does not exist in the namespace `System.Windows'. Are you missing `System.Windows.Forms' assembly reference?
src\01-simple-cs-example.cs(2,14): error CS0234: The type or namespace name `Drawing' does not exist in the namespace `System'. Are you missing `System.Drawing' assembly reference?
src\01-simple-cs-example.cs(4,23): error CS0246: The type or namespace name `Form' could not be found. Are you missing an assembly reference?
0 Warning(s)
3 Error(s)
Time Elapsed 00:00:01.5341534
This is the result from the MSBuild run. MSBuild completed successfully, but I imagine that's because MSBuild knows where to look without me having to specify it in the csproj file.
C:\Users\User01\Dropbox\programming\csharp\zetcode-csharp-winforms\01-simple-cs-example>MSBuild
Microsoft (R) Build Engine version 4.0.30319.18408
[Microsoft .NET Framework, version 4.0.30319.18444]
Copyright (C) Microsoft Corporation. All rights reserved.
Build started 7/25/2014 2:48:04 PM.
Project "C:\Users\User01\Dropbox\programming\csharp\zetcode-csharp-winforms\01-simple-cs-example\01-simple-cs-example.csproj" on node 1 (default targets).
Build:
C:\Windows\Microsoft.NET\Framework\v2.0.50727\Csc.exe /out:bin\01-simple-cs-example.exe src\01-simple-cs-example.cs
Done Building Project "C:\Users\User01\Dropbox\programming\csharp\zetcode-csharp-winforms\01-simple-cs-example\01-simple-cs-example.csproj" (default targets).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:04.36
I don't know what to put into the csproj file to make it load those DLL's that I used in the command line to compile using gmcs. Any clues?
-- EDIT 2014-08-20 --
After using the answer from knocte, I was able to see how the References are added in a csproj file. Its as simple as adding an item group, and adding the References you listed with using in the C# source file.
<ItemGroup>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Drawing" />
<Reference Include="System" />
</ItemGroup>
This is the manual way to do it if you're building the csproj file manually.

Just use an IDE (MonoDevelop or Visual Studio) to add a GAC-reference to System.Windows.Forms and System.Drawing libraries.

Related

How do I get msbuild /restore to work for a standalone/non-SDK project file?

I want to use msbuild /restore with my project file. However, my project file is more like a script which orchestrates building multiple projects with particular properties, etc. Thus, it doesn’t make sense for me to set Sdk="Microsoft.NET.Sdk" because that causes weird errors to show up. However, if I don’t specify the Sdk, the /restore is ignored and it fails to actually restore anything.
Here is my example standalone project:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="RoslynCodeTaskFactory" Version="2.0.7" />
</ItemGroup>
<Target Name="Build">
<HelloWorld/>
</Target>
<UsingTask AssemblyFile="$(RoslynCodeTaskFactory)" Condition="'$(RoslynCodeTaskFactory)' != ''" TaskFactory="CodeTaskFactory" TaskName="HelloWorld">
<Task>
<Code Type="Fragment" Language="cs">
<![CDATA[
Console.WriteLine("Hello, world!");
]]>
</Code>
</Task>
</UsingTask>
</Project>
My invocation and output:
C:\Users\binki\AppData\Local\Temp>"\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\amd64\MSBuild.exe" /restore helloworld.proj
Microsoft (R) Build Engine version 15.7.177.53362 for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.
Build started 2018-05-15 01:23:28.
Project "C:\Users\binki\AppData\Local\Temp\helloworld.proj" on node 1 (default targets).
C:\Users\binki\AppData\Local\Temp\helloworld.proj(8,5): error MSB4036: The "HelloWorld" task was not found. Check the following: 1.) The name of the task in the project file is the same as the name of the task class. 2.) The task class is "public" and implements the Microsoft.Build.Framework.ITask interface. 3.) The task is correctly declared with <UsingTask> in the project file, or in the *.tasks files located in the "C:\Program Files 9x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\amd64" directory.
Done Building Project "C:\Users\binki\AppData\Local\Temp\helloworld.proj" (default targets) -- FAILED.
Build FAILED.
"C:\Users\binki\AppData\Local\Temp\helloworld.proj" (default target) (1:2) ->
(Build target) ->
C:\Users\binki\AppData\Local\Temp\helloworld.proj(8,5): error MSB4036: The "HelloWorld" task was not found. Check the following: 1.) The name of the task in the project file is the same as the name of the task class. 2.) The task class is "public" and implements the Microsoft.Build.Framework.ITask interface. 3.) The task is correctly declared with <UsingTask> in the project file, or in the *.tasks files located in the "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\amd64" directory.
0 Warning(s)
1 Error(s)
Time Elapsed 00:00:01.71

Referencing macros on msbuild (12.0) command line property assignment

I am curious, is it possible to reference a macro on a command line property assignment for MSBuild?
E.g:
msbuild.exe MySolution.sln /p:CustomBeforeMicrosoftCSharpTargets="$(SolutionDir)\custom.targets"
Would this also work when specified as "MSBuildArguments" from an "Edit Build Definition"/"Queue New Build" from Visual Studio connected to TFS?
E.g:
/p:CustomBeforeMicrosoftCSharpTargets="$(SolutionDir)\custom.targets"
Because it doesn't appear to be importing these targets for me. But the targets file is definitely there, alongside the solution, in the build workspace.
I don't want to have to specify an absolute path. Not sure how working with relative paths is meant to work here, can't find any advice on the internet, and debugging it is quite difficult, as it is called on a build agent using a workflow. The workflow logging is definitely reporting it is calling MSBuild with these arguments, but nowhere in the verbose logging output can I see it is making reference to the CustomBeforeMicrosoftCSharpTargets target, or calling it.
EDIT
I wrote a little test build project buildme.proj to further my understanding.
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SetMe>NotInTheSandbox</SetMe>
</PropertyGroup>
<PropertyGroup>
<SomeMacroValue>c:\Sandbox\BuildTest</SomeMacroValue>
</PropertyGroup>
<PropertyGroup>
<AlreadySet>$(SomeMacroValue)\InTheSandbox</AlreadySet>
</PropertyGroup>
<Target Name="Build">
<Message Text="I am building!" />
<Message Text="Some macro value: $(SomeMacroValue)" />
<Message Text="$(SetMe)" />
<Message Text="$(AlreadySet)" />
</Target>
</Project>
When I execute with the command:
msbuild buildme.proj /p:SetMe="$(SomeMacroValue)\StillNotInSandbox"
I get the following output:
Microsoft (R) Build Engine version 12.0.31101.0
[Microsoft .NET Framework, version 4.0.30319.42000]
Copyright (C) Microsoft Corporation. All rights reserved.
Build started 10/12/2015 22:12:08.
Project "C:\Sandbox\BuildTest\buildme.proj" on node 1 (default targets).
Build:
I am building!
Some macro value: c:\Sandbox\BuildTest
$(SomeMacroValue)\StillNotInSandbox
c:\Sandbox\BuildTest\InTheSandbox
Done Building Project "C:\Sandbox\BuildTest\buildme.proj" (default targets).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.02
So clearly, it is not behaving how I expected: The macro identifier appears in the output message text.
Is there a solution to this?
A "macro" like $(SolutionDir) exists only in VisualStudio and VS passes the value to MSBuild.
Instead MSBuild makes Environment variables available as properties, so a batch file like this
set SomeMacroValue=foo
msbuild buildme.proj /p:SetMe="$(SomeMacroValue)\StillNotInSandbox"
is probably what you are looking for.
And you can set environment variables per-user or per-machine (Control Panel\All Control Panel Items\System Advanced System Settings, Environment variables).

Inherit Parent MsBuild file

I have a project structure that looks like this:
Parent
-- ChildProjects1
-- ChildProjects2
-- ChildProjects3
I have an msbuild file under each ChildProjects node that builds the relevant projects, creates zip files, tags them in subversion etc
However most of this logic is common between ChildProjects. I'm wondering if I can refactor this common logic to sit in another msbuild file at the parent level and have each child inherit this?
Any ideas on this appreciated.
You can put common Targets inside an a file that you include using the following syntax, you will also see it in your proj files:
<Import Project="path to file.targets"/>
Things to note:
The convention is to use a .targets extension but it doesn't matter.
Where you place the import is important depending on if you want to be able to override properties or targets in the imported targets file.
Targets are not like methods, you cannot call them more than once but you can influence the order in which they are called.
If you require reusable chunks that you want to call multiple times create a custom task library but check out the MSBuildExtensionPack first to see if it has what you want.
Call Target
In relation to the question about CallTarget. CallTarget will invoke the specified target(s) the same way that DependsOnTargets, BeforeTargets and AfterTargets do. The target will only be run if it has not already been run. See the following example:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Foo">
<Target Name="Foo" DependsOnTargets="Bar">
<Message Text="Foo" />
<CallTarget Targets="Bar" />
<CallTarget Targets="Bar" />
</Target>
<Target Name="Bar" AfterTargets="Foo" BeforeTargets="Foo">
<Message Text="Bar" />
</Target>
</Project>
Which will output the following:
Microsoft (R) Build Engine version 4.0.30319.17929
[Microsoft .NET Framework, version 4.0.30319.18449]
Copyright (C) Microsoft Corporation. All rights reserved.
Build started 24/02/2014 12:06:59.
Project "D:\Dev\Test.proj" on node 1 (default targets).
Bar:
Bar
Foo:
Foo
Done Building Project "D:\Dev\Test.proj" (default targets).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.69

Running XUnit tests with TeamCity using MSBuild

I am trying to get TeamCity to run XUnit tests as part of the build process. So I created a separate file - MyProject.msbuild - living in the same folder as the .sln file, which looks like this:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask AssemblyFile="$(MSBuildProjectDirectory)\..\bin\xunit.net\xunit.runner.msbuild.dll" TaskName="Xunit.Runner.MSBuild.xunit"
/>
<Target Name="Build">
<MSBuild Projects="MyProject.sln" Targets="Build" Properties="Configuration=Release">
<xunit Assembly="MyProject.Utility.Tests\bin\Release\MyProject.Utility.Tests.dll" />
</MSBuild>
</Target>
</Project>
However, no matter what I do, VS2010 hates me having the element inside the element. If I run MSBuild on the file, it tells me a little bit more:
P:\MyProject\src>c:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe MyProject.msbuild /tv:4.0 /v:d
Microsoft (R) Build Engine Version 4.0.30319.1
[Microsoft .NET Framework, Version 4.0.30319.225]
Copyright (C) Microsoft Corporation 2007. All rights reserved.
Build started 08.11.2011 21:08:46.
Project "P:\MyProject\src\MyProject.msbuild" on node 1 (default targets).
Building with tools version "4.0".
P:\MyProject\src\MyProject.msbuild(8,9): error MSB4067: The element <xunit> beneath element <MSBuild> is unrecognized.
Done Building Project "P:\MyProject\src\MyProject.msbuild" (default targets) -- FAILED.
Build FAILED.
"P:\MyProject\src\MyProject.msbuild" (default target) (1) ->
P:\MyProject\src\MyProject.msbuild(8,9): error MSB4067: The element <xunit> beneath element <MSBuild> is unrecognized.
0 Warning(s)
1 Error(s)
Time Elapsed 00:00:00.01
So my current guess is that it doesn't successfully load the xunit.runner.msbuild.dll somehow - or I have done something else strange.
However, I would think that if it couldn't load xunit.runner.msbuild.dll, it would tell me about it. I made sure the file is not blocked (by unpacking the xunit distribution with 7zip).
Any ideas what I can do to get MSBuild to swallow my build file and run the tests?
You don't want to nest the calls, try this:
<Target Name="Build">
<MSBuild Projects="MyProject.sln" Targets="Build" Properties="Configuration=Release">
</MSBuild>
<xunit Assembly="MyProject.Utility.Tests\bin\Release\MyProject.Utility.Tests.dll" />
</Target>
The items within a target are executed in sequence.

MSBuild.Community.Tasks.Attrib on x64 machine failing

I'm having an issue with the Attrib task from the MSBuild Community Tasks Project when running on a 64 bit build machine.
I've put together this small test project to show what the problem is:
<Project ToolsVersion="3.5" DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath32)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<Target Name="PrintProperties">
<Message Text="MSBuildCommunityTasksPath: $(MSBuildCommunityTasksPath)"/>
<Message Text="MSBuildCommunityTasksLib: $(MSBuildCommunityTasksLib)"/>
<Message Text="MSBuildNodeCount: $(MSBuildNodeCount)"/>
<Message Text="MSBuildExtensionsPath: $(MSBuildExtensionsPath)"/>
<Message Text="MSBuildExtensionsPath32: $(MSBuildExtensionsPath32)"/>
<Message Text="MSBuildProjectDirectoryNoRoot: $(MSBuildProjectDirectoryNoRoot)"/>
<Message Text="MSBuildToolsPath: $(MSBuildToolsPath)"/>
<Message Text="MSBuildToolsVersion: $(MSBuildToolsVersion)"/>
<Message Text="MSBuildBinPath: $(MSBuildBinPath)"/>
<Message Text="MSBuildExtensionsPath: $(MSBuildExtensionsPath)"/>
<Message Text="MSBuildProjectDefaultTargets: $(MSBuildProjectDefaultTargets)"/>
<Message Text="MSBuildProjectDirectory: $(MSBuildProjectDirectory)"/>
<Message Text="MSBuildProjectExtension: $(MSBuildProjectExtension)"/>
<Message Text="MSBuildProjectFile: $(MSBuildProjectFile)"/>
<Message Text="MSBuildProjectFullPath: $(MSBuildProjectFullPath)"/>
<Message Text="MSBuildProjectName: $(MSBuildProjectName)"/>
<Message Text="MSBuildStartupDirectory: $(MSBuildStartupDirectory)"/>
</Target>
<Target Name="TestAttrib" DependsOnTargets="PrintProperties">
<Attrib Files="Test.txt" ReadOnly="false" />
</Target>
</Project>
when I attempt to build this project with MSBuild using TestAttrib as the Target I get the following results
C:>msbuild "C:_Source Code\Test.vbproj" /t:TestAttrib
Microsoft (R) Build Engine Version 3.5.30729.1
[Microsoft .NET Framework, Version 2.0.50727.4016]
Copyright (C) Microsoft Corporation 2007. All rights reserved.
Build started 7/09/2009 2:50:12 PM.
Project "C:_Source Code\Test.vbproj" on node 0 (TestAttrib target(s)).
MSBuildCommunityTasksLib: C:\Program Files\MSBuild\MSBuildCommunityTasks\MSBu
ild.Community.Tasks.dll
MSBuildNodeCount: 1
MSBuildExtensionsPath: C:\Program Files\MSBuild
MSBuildExtensionsPath32: C:\Program Files (x86)\MSBuild
MSBuildProjectDirectoryNoRoot: _Source Code
MSBuildToolsPath: c:\Windows\Microsoft.NET\Framework64\v3.5
MSBuildToolsVersion: 3.5
MSBuildBinPath: c:\Windows\Microsoft.NET\Framework64\v3.5
MSBuildExtensionsPath: C:\Program Files\MSBuild
MSBuildProjectDefaultTargets: Build
MSBuildProjectDirectory: C:_Source Code
MSBuildProjectExtension: .vbproj
MSBuildProjectFile: Test.vbproj
MSBuildProjectFullPath: C:_Source Code\Test.vbproj
MSBuildProjectName: Test
MSBuildStartupDirectory: C:\
C:_Source Code\Test.vbproj(26,5): error MSB4062: The "MSBuild.Community.Tasks.Attrib" task could not be loaded from the assembly C:\Program Files\MSBuild\MSBuildCommunityTasks\MSBuild.Community.Tasks.dll. Could not load file or assembly 'file:///C:\Program Files\MSBuild\MSBuildCommunityTasks\MSBuild.Community.Tasks.dll' or one of its dependencies. The system cannot find the file specified. Confirm that the declaration is correct, and that the assembly and all its dependencies are available.
Done Building Project "C:_Source Code\Test.vbproj" (TestAttrib target(s)) -- FAILED.
Build FAILED.
"C:_Source Code\Test.vbproj" (TestAttrib target) (1) ->(TestAttrib target) -> C:_Source Code\Test.vbproj(26,5): error MSB4062: The "MSBuild.Community.Tasks.Attrib" task could not be loaded from the assembly C:\Program Files\MSBuild\MSBuildCommunityTasks\MSBuild.Community.Tasks.dll. Could not load file or assembly 'file:///C:\Program Files\MSBuild\MSBuildCommunityTasks\MSBuild.Community.Tasks.dll' or one of its dependencies. The system cannot find the file specified. Confirm that the declaration is correct, and that the assembly and all its dependencies are available.
0 Warning(s)
1 Error(s)
Time Elapsed 00:00:00.05
Why is the MSBuild searching for the Attrib task in C:\Program Files\MSBuild\MSBuildCommunityTasks\MSBuild.Community.Tasks.dll when I've explicitly imported the tasks using the (MSBuildExtensionsPath32) variable?
I seem to have fixed the issue by editing line 6 of "C:\Program Files (x86)\MSBuild\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"
Originally it was:
<MSBuildCommunityTasksPath Condition="'$(MSBuildCommunityTasksPath)' == ''">$(MSBuildExtensionsPath)\MSBuildCommunityTasks</MSBuildCommunityTasksPath>
and I altered it to:
<MSBuildCommunityTasksPath Condition="'$(MSBuildCommunityTasksPath)' == ''">$(MSBuildExtensionsPath32)\MSBuildCommunityTasks</MSBuildCommunityTasksPath>
note the change of $(MSBuildExtensionsPath) to $(MSBuildExtensionsPath32)
While this seems to have sorted out my issue for now, I'm not sure why I had to edit the MSBuild.Community.Tasks.Targets file in the first place - I assumed the installer would have made sure the file was correct. So perhaps editing the MSBuild.Community.Tasks.Targets file isn't the best idea in the world, so be careful if you decide to follow my lead.
This is obviously far too late an answer, but I thought I would add to this in case anyone else is having this problem. Instead of editing the MSBuild.Community.Tasks.Targets file, you can just define the MSBuildCommunityTasksPath property in a property group in your build file. For example, I have something like this at the top of my build script:
<PropertyGroup>
<ToolsDirectory>$(MSBuildProjectDirectory)\tools</ToolsDirectory>
<MSBuildCommunityTasksPath>$(ToolsDirectory)\MSBuildCommunityTasks</MSBuildCommunityTasksPath>
</PropertyGroup>
I then store the MSBuildCommunityTasks folder in a tools directory in source control. It means that other folk can pull out the source and build it straight away without installing anything.
Cheers,
Adam
This is very out of date help. The ms build process has changed since this ticket, best to follow the instructions here https://github.com/loresoft/msbuildtasks
For my project, I used a Build folder in my solution and in the solution I create a MSBuildTasks Folder where I copy the latests MBBuild.Community.Task files in the Zip file release. and put the following lines in my msbuild file
<PropertyGroup>
<MSBuildCommunityTasksPath>.\MSBuildTasks</MSBuildCommunityTasksPath>
</PropertyGroup>
<Import Project=".\MSBuildTasks\MSBuild.Community.Tasks.Targets" />