September 6, 2024

Build an EXE file using "dotnet"

I have used VS-code to create a .cs file that I can run using using either "Run -- Run without debugging" using that the menu along the top, or using the triangle on the left and selecting "Run and debug:. This works. I am developing a console application, so I see the output in a "pane" that appears at the bottom of VS-code that is some kind of place for basic output. However, when I look for an EXE file, nothing of the sort can be found. I expect to start with hello.cs for example and then find hello.exe.

This is how things are with mono on linux. I can use the following commands from the bash command line and these two commands are all I need:

mcs -out:hello.exe hello.cs
mono hello.exe

What does a VS-code leave me with?

On my linux setup I put one of my projects into the c-sharp/Vscode directory. I see the following. Where I indicate a wildcard there are a bunch of other files.
c-sharp/Vscode/ConsoleApp1.sln
c-sharp/Vscode/ConsoleApp1 (directory)
c-sharp/Vscode/ConsoleApp1/ConsoleApp1.csproj
c-sharp/Vscode/ConsoleApp1/Program.cs
c-sharp/Vscode/ConsoleApp1/obj
c-sharp/Vscode/ConsoleApp1/obj/*
c-sharp/Vscode/ConsoleApp1/bin
c-sharp/Vscode/ConsoleApp1/bin/Debug/net8.0/ConsoleApp1.dll
c-sharp/Vscode/ConsoleApp1/bin/*
As a side note, some people call VS-code an editor, others call it an IDE. I call it an IDE given all this complexity. Of course I have also added the extension called C# Dev kit, so maybe that turns it into a sort of IDE.

I have another project in the vscode directory, namely:

vscode/Socket.sln
vxcode/Socket/*
It has pretty much the same layout as above.

Comments on the C# Dev kit

They say this includes te "Roslyn-powered language service", but oddly enough they don't call this a compiler. I can type Ctrl-Shift-P to get the VS-code menu, then select .NET build or .NET rebuild. The end result of this is /home/tom/vscode/Socket/bin/Debug/net8.0/Socket.dll, so it is nothing more that I have done up to now using the VS-code buttons described above.

But I can avoid VS-code alogether and build a project as follows:

cd c-sharp/Vscode
dotnet build
MSBuild version 17.8.5+b5265ef37 for .NET
  Determining projects to restore...
  Restored /u1/home/tom/c-sharp/Vscode/ConsoleApp1/ConsoleApp1.csproj (in 305 ms).
  ConsoleApp1 -> /u1/home/tom/c-sharp/Vscode/ConsoleApp1/bin/Debug/net8.0/ConsoleApp1.dll
I still end up with the same .dll file, and it still depends on the .sln and .csproj files that VS-code set up for me.

Using dotnet without VS-code

Perhaps the ".NET New project" thing will set up a project for me? I try using "dotnet new" from the bash command line. It tells me that it wants to create a .NET project using a template, and suggests "console" as a C# template. And to learn more it suggests:
dotnet new console -h
Based on this, I try:
cd vscode
dotnet new console -n fish
dotnet build fish
And this works! I compiles what is fish/Program.cs and gives me fish/bin/Debug/net8.0/fish.dll. So far I have avoided VS-code -- to run it is as easy as this:
cd fish/bin/Debug/net8.0
dotnet fish.dll
Or better yet:
dotnet fish/bin/Debug/net8.0/fish.dll
As a note, I get no .sln file doing this (with suits me just fine, thank you).

A peeks at fish.csproj shows me that this is an XML file. It tells me this is net8.0 and I see no mention of Program.cs or any .cs file at all. Also it indicates that the OutputType is "Exe", but that declaration seems meaningless.

A build with multiple files

This is actually easy and requires no fiddling with the .csproj file. You just add an addition file (or files) alongside Program.cs and build away.

The only thing to sort out are C# details themselves. I keep Program.cs and add Fish.cs. Inside Fish.cs I have "namespace Tom" and in Program.cs I have "using Tom". The class inside should be called something else (like Fish)> The class name should not be the same as the namespace name apparently.

A simple makefile

With the following makefile, I can now use just "make" to build and run!
# Makefile for a dotnet C# project

DLL=bin/Debug/net8.0/fish.dll

all:	run

build:
		cd .. ; dotnet build fish

run:	build
		dotnet $(DLL)
This is real progress. I can build, make, and run a new project via:
cd vscode
dotnet new console -n fish
cd fish
# copy makefile into place and edit
make
Of course I have to put the makefile into place before I can do the above. This allows me to use vim to edit Program.cs

Cross platform building

Now for another experiment. I use "ssh" to copy this to my Windows 10 machine and try:
dotnet fish.dll
A fatal error was encountered. The library 'hostpolicy.dll' required to execute the application was not found in 'C:\Users\Tom\'.
Failed to run as a self-contained app.
  - The application was run as a self-contained app because 'C:\Users\Tom\fish.runtimeconfig.json' was not found.
  - If this should be a framework-dependent app, add the 'C:\Users\Tom\fish.runtimeconfig.json' file and specify the appropriate framework.
That is too bad. Maybe the phrase "self contained app" will yield some kind of answer other than dragging along a bunch of extra dll files and .json files. There are useful tips here:

Let's try a build that specifies a runtime

This is all per the "self contained" blog post above. I go back to my "Fish" project, now with two .cs files, but that is not relevant for what we are doing. We edit the fish.csproj file, looking for a "platform" -- but don't see anything like that. We dig around to discover what runtime RID might be what we want: It looks like "win-x64" or "linux-x64" are what we want. We try this:
dotnet build -r linux-x64
dotnet publish -c release -r linux-x64
The first generates the dll in the same place as always. And while the second puts things into the "bin" directory, we get no exe file. Ah, but wait!
cd Fish/bin/release/net8.0/linux-x64
ls -l
-rwxr-xr-x 1 tom tom 72520 Sep  6 15:07 fish
-rw-r--r-- 1 tom tom  4096 Sep  6 15:07 fish.dll
file fish
fish: ELF 64-bit LSB pie executable, x86-64
And indeed, typing "./fish" runs the executable, givng the output I expect.

Now let's try that for a win-x86 runtime

dotnet build -r win-x64
dotnet publish -c release -r win-x64
Things go badly downhill from here and spiraled into a bunch of issues on my Windows machine that I have not yet unravelled. For the ongoing story, use this link:
Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org