Spinning off from #1906, .NET Core, by design, currently doesn't build AnyCPU exes. However, it uses MSBuild syntax that implies otherwise, such as:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net47</TargetFramework>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
</Project>
In .NET Framework, it made sense to have an OutputType of Library (DLL), Exe (console EXE) or WinExe (non-console EXE), as that directly matched the type of Windows PE produced.
In .NET Core, the output type is always a DLL on Windows (if I understand correctly), which may or may not have code designed to work as an entry point. To eliminate the confusion here, distinct MSBuild syntax could help quite a bit. For example, consider:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<EntryPointType>Console</EntryPointType>
<TargetFramework>net47</TargetFramework>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
</Project>
Where EntryPointType is one of: None, Console, NonConsole
Or maybe:
HasEntryPoint: true/false
IsConsoleApplication: true/false
I think this would have led to less surprise in issues like dotnet/cli#6237. (That issue is still useful as a feature request for building an actual .exe on Windows - this one is about the MSBuild contract when producing a .NET Core application with an entry point.)
Spinning off from #1906, .NET Core, by design, currently doesn't build AnyCPU exes
.NET Core doesn't build a self-contained AnyCPU exe. Making a self-contained AnyCPU exe is impossible or very hard on most platforms (most image formats do not allow you to have 32 and 64-bit code SxS in the same image).
The only reason AnyCPU executables work for the desktop framework is because the Windows Operating System natively recognizes managed executables and has some OS level shims to switch between executing as 32-bit or 64-bit (if the Prefer 32-bit flag is set, it gets run as 32-bit; otherwise 64-bit, on a 64-bit OS. It is always run as 32-bit on a 32-bit OS).
In .NET Core, the output type is always a DLL on Windows
The output for a non self-contained app is a DLL, because the actual host to run it (dotnet or dotnet.exe) exists elsewhere. The output for a self-contained app is an EXE, because the host is embedded into the generated assembly.
On a similar note:
Even though a .dll file is emitted, it still has all the necessary PE data to run as a .NET Framework application.
I swear this came up a few days ago on stack overflow but I can't find it now. But it's easy to reproduce when building a hello world app:
C:\Users\martin.ullrich\Documents\repos\testcons\bin\Debug\netcoreapp2.0>testcons.dll
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'System.Runtime, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
The OP didn't know to run dotnet the.dll instead of the.dll and the error message isn't very helpful if you're not familiar with the ecosystem. I'm afraid (and amused) that once .net 4.7.2 ships all the assemblies with "correct" netstandard2.0 assembly version numbers, some apps may actually run and then crash on something else completely unexpected.
Actually it wasn't SO but a GitHub issue: https://github.com/PeterKottas/DotNetCore.WindowsService/issues/70
Is this actually still a valid issue in .NET Core 3?
The executable that is now produced when a RuntimeIdentifier is not set (so using Framework-dependent executables), is that not AnyCPU?
The wording on the docs page for it says they are target platform dependent, although it's not quite clear how the target platform is selected if none is specified (likely just the current platform I guess).
I can confirm that by default .NET Core seems to produce 64-bit assemblies that refuse to run on 32-bit OS even with framework-dependent deployments. Is there a workaround for this?
K.I.S.S!
Developers has been using Microsoft tools to produce code for windows for decades, and there's an established standard way how stuff work.
When things don't work or behave as the always have, people (including developers) get confused, problems arise and time is wasted trying to figure out what is going on.
So, for the tens of millions of developers out there that has been using VS/MsBuild for decades, they get really confused when see a project with the output type set to "Console Application" and the project file contain <OutputType>Exe</OutputType>, and they then end up with a DLL.
Yes, or MS could produce a project file with a helpful comment. Communication: it's necessaryâ„¢.
<!-- <OutputType>Exe</OutputType> produces a .dll file, but you can run it with dotnet <appname>.dll -->
<OutputType>Exe</OutputType>
P.S. why _not_ use a .exe file extension?
Well, I have quite the opposite problem...
Seems like latest toolchain produces executable (for the current platform) even when you build an app as framework-dependent and there is no way to prevent it from doing so, as far as I can tell. I just wanted to create a cross-platform application package that requires dotnet to be preinstalled, and I have to add an extra step to my build to remove .exe from publish folder, as I don't want to see it on Linux/OS X.
If there is anything this thread was supposed to teach us - that would be necessity for configuration, as there is million of different scenarios that people may have and we can't just do and then un-do things, because half of the population complain about it. If we want to cover a broad spectrum of developers - it should be flexible and well-documented, me thinks.
@nahk-ivanov try setting this in the csproj file:
<PropertyGroup>
<UseAppHost>False</UseAppHost>
</PropertyGroup>
it is documented here
@dasMulli thanks a bunch, it works!
Apparently I was looking at "more information" article, that doesn't mention the flag. 🤦 Let me try to update it to mention the flag...
@nahk-ivanov try setting this in the csproj file:
<PropertyGroup> <UseAppHost>False</UseAppHost> </PropertyGroup>it is documented here
This saved a lot of my time. Thanks.
Most helpful comment
K.I.S.S!
Developers has been using Microsoft tools to produce code for windows for decades, and there's an established standard way how stuff work.
When things don't work or behave as the always have, people (including developers) get confused, problems arise and time is wasted trying to figure out what is going on.
So, for the tens of millions of developers out there that has been using VS/MsBuild for decades, they get really confused when see a project with the output type set to "Console Application" and the project file contain
<OutputType>Exe</OutputType>, and they then end up with a DLL.