dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.64k stars 1.05k forks source link

dotnet new console, publish, makes a dll not an exe #8065

Closed danmoseley closed 4 years ago

danmoseley commented 7 years ago
C:\PLAy\asdf>dotnet --version
2.0.0-preview1-005694

C:\PLAy\asdf>dotnet new console
The template "Console Application" was created successfully.

C:\PLAy\asdf>dotnet restore

...
C:\PLAy\asdf>dotnet run
Hello World!

C:\PLAy\asdf>dotnet publish
Microsoft (R) Build Engine version 15.2.47.30403
Copyright (C) Microsoft Corporation. All rights reserved.

  asdf -> C:\PLAy\asdf\bin\Debug\netcoreapp2.0\asdf.dll

Shouldn't I have a console .exe? How do I run this dll?

omajid commented 7 years ago

Does dotnet bin\Debug\netcoreapp2.0\asdf.dll work?

Edit: dotnet publish --self-contained should generate an exe, though: https://github.com/dotnet/cli/pull/6234

benaadams commented 7 years ago

If you add

<RuntimeIdentifier>win7-x64</RuntimeIdentifier>

you get a apphost.exe as only exe but when you run it it says it

This executable is not bound to a managed DLL to execute. The binding value is: 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2'
A fatal error was encountered. This executable was not bound to load a managed DLL.

and you have to run it with dotnet xxx.dll which isn't expected

e.g. if you were following UsingYourBuild.md#change-project-to-be-self-contained from coreclr

danmoseley commented 7 years ago

@omajid yes,

C:\PLAy\asdf>dotnet bin\Debug\netcoreapp2.0\asdf.dll
Hello World!

The project does contain <OutputType>Exe</OutputType> so I guess the bug is that it doesn't work.

dasMulli commented 7 years ago

.net core apps aren't supposed to be ".exe" files as this is a windows concept. When a portable app is published, the resulting .dll is supposed to be run on the target platform through dotnet app.dll which will then use the platform-specific runtime.

In project.json, the property was emitEntryPoint: true. In csproj, <OutputType>Exe</..> has existed before and should rather be interpreted as Executable rather than .exe file..

Tooling already exists for OutputType, yet it would be more clear if there was <Runnable>true</..> (which would internally just set the output type).

livarcocc commented 7 years ago

The important concepts here are that of a portable app (which is what you get by default) and self-contained apps (which are the ones for which an exe is produced).

A portable app is an application that runs independently of the platform and require that you have the shared framework installed. When you published it, the shared framework bits are not copied to the publish folder, including the native host. So, in order to run it, you need to do dotnet . dotnet in this case is the native piece, the host.

For self-contained apps, when you publish it you need to specify a RID (the distro you want to publish to, so that we know which native pieces to copy). In this case, because we will know your distro, we will generate an exe for you that you can then use for that specific platform.

This is a by design behavior.

danmoseley commented 7 years ago

Can we reduce the confusion somehow? I work on .NET Core and I was confused.

1) <OutputType>Exe</OutputType> reads exe but does not correspond to an exe. That's clearly confusing. Are we really out of options due to back compat? Why? 2) Console Application is the name of the template. For 15 years in .NET that has meant an .exe. Can we call the template something else, that's meaningful?

@terrajobst

livarcocc commented 7 years ago

Sorry for the confusion. The concept of portable and self-contained applications are actually old concepts in the .net core world. We have had it for a while. I think one part of the confusion is the expectation that .NET Core should be similar to .NET Framework, which it is not.

You can read more about portable and self-hosted apps here: https://docs.microsoft.com/en-us/dotnet/articles/core/deploying/.

Also, at this point, I don't see how we could make changes to this without causing breaks for everyone building applications for .NET Core right now.

richlander commented 7 years ago

@danmosemsft This isn't new ... was in 1.x, too. It also isn't a compat thing. We have choices here, but most of them come back to this experience as the best choice. It's one of those "this experience has three awesome characteristics (drawn as a triangle) ... pick 2".

Here are the characteristics you can choose from.

  1. Cross-platform applications (meaning you can take the folder and run on Windows, macOS and Linux), provided .NET Core is installed there).
  2. Produces an exe (whatever "exe" means on your OS) by default (what you are asking for).
  3. Produces an app that doesn't require .NET Core installed.
  4. Small apps.

You can have all of them, but not all of them can be the default. I also lied. You can pick two of the 4. So, today, the default is 1 and 4. Standalone gives you 2 and 3 and you give up and 1 and 4. We could have an experience that was 2 and 4 but we don't. We could do it in such a way that you don't give up on 1 (with scripts). It's all a question of what the base of the process should be.

I'm being somewhat vague because I want you to think about the characteristics and determine for yourself why this is the case. I'm not going to explain it. It's important to have the "a ha" moment on what "dotnet publish" really means.

Thoughts?

danmoseley commented 7 years ago

That all makes sense -- the same project will only make an actual .exe or equivalent iff you choose standalone aka self-contained. Once you make an .exe or equivalent, you made your app runtime specific.

I think @dasMulli 's suggestion that ideally <OutputType>Exe</OutputType> in the 2.0 templates could be <Runnable>true</Runnable> which the targets just translated. But I'm going to guess that would involve a VS update to know to write the new name.

It is unfortunate that I'm not the only person who will have to go through this learning process :) Feel free to close

benaadams commented 7 years ago

Would have gone for 2 for <OutputType>Exe</OutputType> and give a (very informative) publish error if target runtime not specified.

Rather than sticks a bunch of dlls in an output folder and not actually produce an "exe".

Windows world use case: publish; open folder, what to double click on to run?

benaadams commented 7 years ago

Do understand the difficulty that that "exe" wouldn't be portable though 😢

benaadams commented 7 years ago

Could you output multiple?

dotnet publish

outputs

MyApp.dll MyApp.exe MyApp rwxrwxr--

richlander commented 7 years ago

@benaadams Good idea, but I'd rather not. While, this would allow all scenarios by default, I think we'd have a different class of confusion. For example:

That all said, it's very obvious that the current situation is not great.

I'll put one stake in the ground ...

Deployment choices should not be specified in the project file. The corollary of this is that multiple deployment options should be possible from one project file.

I continue to think that the launcher case (and also the cross-plat scenario) should be the default and the exe case should be opt-in. That said, it should be much easier and intuitive to do so than it is now. Also, EXE and standalone don't need to be conflated.

Fair?

richlander commented 7 years ago

@danmosemsft The primary problem isn't VS updates. It's that the EXE output type really means "application". It's the entry point into a variety of publishing types. It doesn't mean ".exe". If we're going to change something, I'd make it "app", which would make it clear that we are talking about a logical concept. Hey, that's a good idea!

The primary issue, as I said above, is that this choice isn't a project-level concern.

benaadams commented 7 years ago

dll launcher is covered; self-contained is covered; however I'd argue that there is an expectation for a targeted shared runtime exe (as you get from full framework and netcoreapp1.0-1.1)

The biggest issue with not having a local exe is the OS limitation on expressing what is running I raised as issues https://github.com/dotnet/cli/issues/6279, https://github.com/dotnet/core-setup/issues/2007

This is where the OS picks up info about what is running from the exe file e.g.

image

The exe provides an entry point for process name, process description and icon which is lost with just the launcher

svick commented 7 years ago

Would it make sense to include a platform-independent launcher with a framework-dependent application?

I can imagine doing that by creating a shell script that calls dotnet (for Unix) with a unique extension (for Windows).

Specifically, running dotnet publish for framework-dependent deployment would create something like MyApp.dotnet with the contents of:

#!/bin/sh
dotnet MyApp.dll

On Linux and macOS, this should run the installed version of .Net Core. On Windows, the .dotnet extension would be registered with dotnet.exe, which would ignore the contents of the file and execute MyApp.dll.

This way, double-clicking MyApp.dotnet on Windows and ./MyApp.dotnet on Unix would both work.

mellinoe commented 7 years ago

It's a clever idea, but I don't know if it's worth it for the relatively small benefit. I'm also worried that getting into the business of OS file associations is going to be clunky and bug-ridden, but maybe that's just my pessimism. 😄

benaadams commented 7 years ago

Actually, still not sure why this doesn't produce an exe

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <IsPackable>false</IsPackable>
    <OutputType>exe</OutputType>
    <NetStandardImplicitPackageVersion>1.6.1</NetStandardImplicitPackageVersion>
    <RuntimeFrameworkVersion>2.0.0-*</RuntimeFrameworkVersion>
    <RuntimeIdentifier>win10-x64</RuntimeIdentifier>
  </PropertyGroup>

</Project>

Really not sure why it also outputs a apphost.exe that errors when you run it

publish>apphost
This executable is not bound to a managed DLL to execute. The binding value is: 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2'
A fatal error was encountered. This executable was not bound to load a managed DLL.
benaadams commented 7 years ago

Ok updating to newest nightly and creating with dotnet new does create the exe

All good...

JoseFMP commented 7 years ago

So what is the key tag to get the exe? I really do not care to run "dotnet acool.dll" but legacy tools are expecting my application to have an exe file.

borgdylan commented 7 years ago

@benaadams On Linux, I am getting an apphost binary that fails as mentioned previously.

What happened to just renaming the coreconsole binary to get a working self-contained app? This new apphost methodology is a regression :/ .

damircolak commented 7 years ago

Same question here, I do dotnet publish -c Release -r win7-x64 and I get ONLY DLL.

How to create an EXE file?

If I target win10-x64 I do get an .EXE file but it won't run on Windows 7 because of this error:

Error: assembly specified in the dependencies manifest was not found -- package: 'microsoft.codeanalysis.common', version: '1.3.0', path: 'lib/netstandard1.3/Microsoft.CodeAnalysis.dll'

After googling for hours I still don't know how to fix that error.

Does building a simple EXE file really have to be this complicated?

What have become of the mighty Microsoft?

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>

    <RuntimeIdentifiers>
        <RuntimeIdentifiers>win10-x64;osx.10.11-x64;win7-x64;ubuntu.14.04-x64</RuntimeIdentifiers>
    </RuntimeIdentifiers>

  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
  </ItemGroup>
</Project>
danmoseley commented 7 years ago

@livarcocc for feedback above (since issue is closed)

damircolak commented 7 years ago

Why did you close issue when it was not fixed? See my post for more details. I did check @livarcocc and it did not help at all.

danmoseley commented 7 years ago

@damircolak I cited @livarcocc so he could see your comments. I think it would be better for you to open a new issue for what you're encountering.

mattcanty commented 7 years ago

@damircolak did you open a new issue for this? I am experiencing the same problem.

AronParker commented 7 years ago

Same problem here, is there a new issue regarding this yet?

mattcanty commented 7 years ago

@AronParker try the following:

dotnet publish -c Release

Now navigate to bin/Release/netcoreapp1.x/publish and you should see the exe in there.

Alternatively see if it's worth going up to .Net Core 2.0 as it appears to be supporting standalone applications as a flag on publish: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?tabs=netcore2x

AronParker commented 7 years ago

@AronParker try the following:

dotnet publish -c Release

Now navigate to bin/Release/netcoreapp1.x/publish and you should see the exe in there.

Alternatively see if it's worth going up to .Net Core 2.0 as it appears to be supporting standalone applications as a flag on publish: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?tabs=netcore2x

@mattcanty Thanks for your response! Although I still see .dll files even when compiling with dotnet publish -c Release, could that be because I'm on .NET core 2.0? And yes indeed I've seen that you can make a standalone package which does an exe, however it contains the entire .NET core files which I don't really want.

ghost commented 6 years ago

I agree with @AronParker . Exactly the same things happen to me. Why is this closed?

danmoseley commented 6 years ago

Reopening just so @livarcocc and @richlander can see the feedback. Although, this is by design - see @richlander 's explanation: https://github.com/dotnet/cli/issues/6237#issuecomment-293425139

tasoss commented 6 years ago

sigh...thanks @danmosemsft

dasMulli commented 6 years ago

I wonder if sth simple can be done here to help out. The scenario seems to be "I want to double-click something" (correct me if I'm wrong) which can be easily done by creating a .cmd and .sh file calling dotnet foo.dll..

mattcanty commented 6 years ago

Am I missing any special reason why everything cannot be bundled up inside the executable somehow.

Coming at this from a totally naive viewpoint...

If you wanted an executable package containing the supporting libraries, why would you ever want those as individual files that you also have to lug around.

On Mon, 28 Aug 2017 at 20:10 Martin Andreas Ullrich < notifications@github.com> wrote:

I wonder if sth simple can be done here to help out. The scenario seems to be "I want to double-click something" (correct me if I'm wrong) which can be easily done by creating a .cmd and .sh file calling dotnet foo.dll..

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/dotnet/cli/issues/6237#issuecomment-325449456, or mute the thread https://github.com/notifications/unsubscribe-auth/AB_ibRjTwEa5udh5x8USruiqfIHkziDQks5scxCRgaJpZM4MyTtj .

warrenrumak commented 6 years ago

Gotta say, I'm scratching my head over this one too.

This isn't a new problem. Wrapper creators for .jar files that package them into Windows/Linux/macOS executables have existed for 15 years.... JSmooth, Jar2exe, launch4j, and others are all are actively developed and used in the Java world.

These tools exist because it has long been understood that it is necessary to provide a smooth execution experience for end-users. This is doubly true for people who write command-line utilities. If that tool isn't easy to reach, folks just won't use it.

Asking people to type "dotnet" before running my command-line tool would be like asking a gamer to type "directx" or "unity" before running my game.

Ideally, "dotnet publish" would provide these wrappers based on the requested RID(s).

mellinoe commented 6 years ago

Asking people to type "dotnet" before running my command-line tool would be like asking a gamer to type "directx" or "unity" before running my game.

Ideally, "dotnet publish" would provide these wrappers based on the requested RID(s).

This does happen. If you publish for "win-x64", you will get a native Windows executable which can be run by double-clicking it. If you publish for "linux-x64", you will get a native Linux executable (extensionless ELF file) that can be run directly.

livarcocc commented 6 years ago

@mattcanty that is not possible because an executable that works in one platform won't necessarily work in another (like a windows executable and a linux one).

@warrenrumak If you provide a RID and are building a self-contained application, we will publish an executable with the application name in the publish output folder.

livarcocc commented 6 years ago

See now that @mellinoe posted with me!

cc @KathleenDollard

danmoseley commented 6 years ago

Maybe it's just a discoverability/convenience issue. I didn't originally discover dotnet.exe publish -r win-x64 and we don't seem to expose the list of RID's in the help.

benaadams commented 6 years ago

Or the just to be sure: dotnet.exe publish -c Release -r win-x64 -f netcoreapp2.0

RIDs in help TFM in help

Maybe cli should offer common selection on a help param; with link to look up more?

danmoseley commented 6 years ago

Yeah, I meant -? help.

dasMulli commented 6 years ago

There is probably a distinct scenario here: wrappers to allow calling ./theapp in a RID-specific but not self-contained publish. While it is currently possible to creat such a deployment (dotnet publish -r RID --self-contained false), there is room for a few extras here:

  1. .bat file for windows which just calls dotnet exec theapp.dll and an extensionless shell script to do the same on *nix
    • These can also be used for portable applications since they don't conflict with each other.
  2. RID-specific executable (PE/ELF/mach-o) that contains a build of core-setup that acts like the muxer assembly to use hostfxr to boot the desired runtime. This could work similar to the current msbuild sdk resolver which looks for the muxer in the PATH.

That could be called via dotnet publish -c Release -r win-x64 --self-contained false --create-launcher.

warrenrumak commented 6 years ago

@mellinoe

It sure does, then I have to package, what, 60MB of DLLs with each executable? No thank you. You cannot convince me that this is a good path forward, especially if I want to build several command-line tools or small GUIs. Now instead of asking the user for, say, 1MB of disk space for ten small tools, I'm asking for 600MB?

What's being asked for here is a middle-ground between -f and -r: An executable that uses the installed runtime. You know, like we did successfully for 15 years....

mellinoe commented 6 years ago

@livarcocc Isn't there a way to produce a framework-dependent deployment but still get an executable launcher?

livarcocc commented 6 years ago

@eerhardt will the feature you implemented address this?

eerhardt commented 6 years ago

No unfortunately not. Even when you publish '-r RID --self-contained false', you still run on the shared framework. And today to run on the shared framework, you need to be invoked with the 'dotnet' host executable.

We could add a feature to the apphost executable to know where to find the shared framework when it is invoked and the coreclr doesn't exist in the same directory. An issue with that is there is no "global" location on non-Windows. We have %PROGRAMFILES% on Windows, but there isn't currently the same well-known global location on Unix.

AronParker commented 6 years ago

How about adding a custom file extension called .dotnet, which will be registered to run the runtime with the specified file?

sporty81 commented 6 years ago

How about on any build or publish you just automatically create a ".bat", ".ps1" or some other file that does the "dotnet myfile.dll".

It could even be named myfile.exe.ps1

On publish if you wanted to auto-create a Linux flavored one, you could do that too.

keith-miller commented 6 years ago

Might be a dumb question, but is there a .Net Core 2.0 version of this document?

https://docs.microsoft.com/en-us/dotnet/core/deploying/

We're working on cross-platform standalone build and would like to know the right way to keep dotnet build working and building a proper DLL and have dotnet publish create the standalone executable. As it stands right now I can only seem to make a DLL that works fine with dotnet my_app.dll or a standalone executable with dotnet publish but the build DLL complains about missing libraries.

Thanks!

keith-miller commented 6 years ago

Ok, so part of my issue was that dotnet restore wasn't being called. That solves the dotnet build issue. But running dotnet publish -r osx.10.12-x64 with OutputPath set builds a standalone executable without dependencies in the OutputPath that doesn't work, and under that in publish a standalone executable with dependencies that does. I can work around that but it seems odd to have both.