MSBuild is strange
I already tried this and another answer and I also tried this one
After that, I changed <IntermediateOutputPath> and <BaseIntermediateOutputPath> and <OutputPath> in the .csproj file but...
It keeps creating this piece of strange stuff in the old obj folder (I don't use nuget)
project.assets.json
project.nuget.cache
project.packagespec.json
...
I have already read about Visual Studio legacy workflow causes this behaviour but do any workarounds exist?
My current .csproj file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<StartupObject>Program</StartupObject>
<IntermediateOutputPath>..\..\obj\</IntermediateOutputPath>
<BaseIntermediateOutputPath>..\..\obj\</BaseIntermediateOutputPath>
<OutputPath>..\..\bin\Build\</OutputPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="foo\dependency.csproj" />
</ItemGroup>
</Project>
Solved by creating Directory.Build.props file in the root of project with:
<Project>
<PropertyGroup>
<MSBUildProjectExtensionsPath>..\..\obj\</MSBUildProjectExtensionsPath>
</PropertyGroup>
</Project>
Very dirty and non-obvious microsoft-style hack
Found here
Is there any good .NET compiler for windows without penetrating youself?
Related
Short: I want to post process IL code after C# code is compiled but before it is outputted by MSBuild and before it is run by IDE
Long: I want to create a game, which will have client and server. Most of code will be shared by them, but some types, fields and methods will be exclusively available only on one side. Such elements will have the Side attribute which will have side parameter and will specify which side does the type, method or field belong to. I want to have two build configurations: client and server and I want to remove types, methods and fields from assemblies, which they don't belong to.
I tried to work with MSBuild tasks. I created test solution with two projects: DynamicCodeTest, which is target for modifications, and Task, which contains MSBuild task class Class1 (naming is very poor but this is a test project). Task csproj file does not have anything unusual except that it depends on Microsoft.Build.
I tried writing this in DynamicCodeTest.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Task\Task.csproj" />
</ItemGroup>
<UsingTask TaskName="Task.Class1" AssemblyName="Task"></UsingTask>
<Target Name="HelloWorld" AfterTargets="AfterCompile">
<Task.Class1></Task.Class1>
</Target>
</Project>
but UsingTask was not able to find Task assembly.
Then I tried writing this it it:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Task\Task.csproj" />
</ItemGroup>
<UsingTask TaskName="Task.Class1" AssemblyFile="..\Task\bin\$(Configuration)\net6.0\Task.dll"></UsingTask>
<Target Name="HelloWorld" AfterTargets="AfterCompile">
<Task.Class1></Task.Class1>
</Target>
</Project>
but msbuild could not copy Task.dll from obj/... to build/... because it was in use by other process.
What is the proper way to do this? If there is a way to do so, I would prefer to make thing with AssemblyName work, because AssemblyFile seems sort of hacky.
I'm building a project with the following in the CSPROJ file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<PlatformTarget>AnyCPU</PlatformTarget>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>basic_example</RootNamespace>
<ImplicitUsings>disable</ImplicitUsings>
<StartupObject>basic_example.LoopThroughInvalidFileChars</StartupObject>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="2.14.0" />
</ItemGroup>
</Project>
I'm interested in debugging a source file in this project using Visual Studio 2019. Here are the details:
When I start the project without debugging, it compiles and runs fine. However when I place a breakpoint in my source code and I try to start with debugging, it basically runs my program and never stops at the breakpoint.
In my output window in Visual Studio, the following message appears:
The target process exited without raising a CoreCLR started event. Ensure that the target > process is configured to use .NET Core. This may be expected if the target process did not > run on .NET Core.
The program '[25444] basic-example.dll' has exited with code 0 (0x0).
However, I am intentionally setting the target framework to netstandard2.0. I.e. I would really like to debug it with the current project file.
Why won't Visual Studio allow me to debug this project?
Thanks to #LukeBriner's and #Dai's comments I was able to solve the problem.
As #LukeBriner mentions:
If you want to debug into it as a netstandard library then just create a dotnet core console app and call into the library in a normal way.
So that's what I did.
I had to rename all methods named Main in my class library to something else (I used Run).
I added a console app to the solution adjacent to the class library and added a project reference to the class library.
I imported the class library in my console apps' Program.cs with a using statement. I called the class I wanted to debug in the Main method of Program.cs
I modified the project file of the console application to look like the following:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>call_basic_example</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\openxml-exceptions\basic-example.csproj" />
</ItemGroup>
</Project>
I modified the project file for the class library to look like the following:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PlatformTarget>AnyCPU</PlatformTarget>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>basic_example</RootNamespace>
<ImplicitUsings>disable</ImplicitUsings>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="2.14.0" />
</ItemGroup>
</Project>
I was then finally able to debug into whichever method I wanted in the class library.
is it possible to run a project with an argument of a dll from another project?
My project structure and dependencies look like this
As you can see there are no direct dependencies between a mod and the game implementation directly.
When I click on Debug -> Start New Instance, F5 or use the button () I want to run ./ExampleGameInEngineA.exe GameModC.dll.
I know that you can set an Executable in the project settings
But I am looking for a more generic way that is automatically compiling ExampleGameInEngineA and putting it in the same directory as GameModC.
Hardcoded directory paths are also not great (tho I could use relative paths for this).
For testing purposes we can safely ignore GameInEngineB but I still don't want any hard references to GameInEngineA.
Okay, I kinda solved it by myself by using a PreBuild-Event-Target:
GameModC.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
</PropertyGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent" Condition="">
<MSBuild Projects="$(SolutionDir)ExampleGameInEngineA\ExampleGameInEngineA.csproj..." />
<ItemGroup>
<GameEngineAOutputFolder Include="$(SolutionDir)ExampleGameInEngineA\$(OutDir)*.*" />
</ItemGroup>
<Copy SourceFiles="#(GameEngineAOutputFolder)" DestinationFolder="$(OutDir)" SkipUnchangedFiles="false" />
</Target>
<ItemGroup>
<ProjectReference Include="..\GameApi\GameModdingApi.csproj" />
</ItemGroup>
</Project>
GameInEngineA.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\GameApi\GameModdingApi.csproj" />
</ItemGroup>
</Project>
Please note the AppendTargetFrameworkToOutputPath to remove the netcoreapp3.1 or netstandard2.1.
But there are still problems with the solution:
It does not recognize changes made in ExampleGameInEngineA (manual rebuild required)
The Condition when to add ExampleGameInEngineA is always met (because I have no good idea for a condition)
I am still open for better solutions.
The issue:
If I change the file extension from the visual studio, the file Build Action will be according to the previous Build Action and not according to the new file extension.
There is a way to enforce the visual studio always takes the Build Action from the file extension?
Example:
Create a new .Net Core 3.1 Class library. There is a single file (Class1.cs) The csproj will be like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
</Project>
Change the name of Class1.cs to Class1.txt from the visual studio. The result, Class1.txt is with Build Action Compile although it is a text file. The content of csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Remove="Class1.txt" />
</ItemGroup>
<ItemGroup>
<Compile Include="Class1.txt" />
</ItemGroup>
</Project>
Additional information:
I'm using Visual Studio 2019.
If I change the file extension from the file system the issue doesn't appear.
Update:
A possible solution is to change the file Build Action after each file rename, but I want an automatic way.
I have code for a bunch of CLI utilities made to test/showcase a network library. The library is compiled into an assembly - DotNet Core DLL.
I have several CLI examples showing how to use the library, for example, one search is using paging functionality and another returns everything etc. Basically, each is a short standalone CLI program.
I have CS source files and csproj file targeting dotnet core. Below is the configuration:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Reference Include="mylib>
<HintPath>../../bin/Debug/netstandard2.0/publish/mylib.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
I want to have one executable for each source file e.g. PGSample.cs will get compiled into PGSample.exe etc. How would I about achieving this?
I'm afraid you can have only one output per csproj, but there are some tricks to manage multiple projects easier.
You can put common build settings into a file named Directory.build.props in the root project folder, e.g.:
<Project>
<PropertyGroup>
<Authors>Your name here</Authors>
<Company>Your company</Company>
<Product>The project name</Product>
<Version>1.6.18</Version>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<!-- e.g. bin/Release_net48/foo_cli/ -->
<OutputPath>$(SolutionDir)bin\$(Configuration)_$(TargetFramework)\$(MSBuildProjectName)</OutputPath>
<TargetFrameworks>net48</TargetFrameworks>
</PropertyGroup>
</Project>
Then, add one subdirectory and minimal csproj file per output, e.g.
libfoo/libfoo.csproj: <Project Sdk="Microsoft.NET.Sdk" /> (really, that's it!)
foo_cli/foo_cli.csproj:
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup><OutputType>Exe</OutputType></PropertyGroup>
<ItemGroup><ProjectReference Include="..\libfoo\libfoo.csproj" /></ItemGroup>
</Project>
Iff you have only one library and a lot of executables, you might even add your executable settings to the Directory.build.props:
[..]
<PropertyGroup Condition=" $(MSBuildProjectName) != 'libfoo'">
<OutputType>exe</OutputType>
</PropertyGroup>
<ItemGroup Condition=" $(MSBuildProjectName) != 'libfoo'">
<ProjectReference Include="..\libfoo\libfoo.csproj" />
</ItemGroup>