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.71k stars 1.06k 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?

btory commented 6 years ago

I'm surprised that there aren't more people complaining about this.

Currently a self-contained deployment appears to be the only option if you want an executable. What if you don't want your deployment to include potentially hundreds of megabytes worth of .NET Core components though? Why is there no ability to generate a RID-specific app host executable that uses shared components?

benaadams commented 6 years ago

Why is there no ability to generate a RID-specific app host executable that uses shared components?

Guessing discovery of the shared components? They are relative to dotnet in path; or relative to exe for selfcontained

ms0713 commented 6 years ago

@btory Why is there no ability to generate a RID-specific app host executable that uses shared components? I agree. I m able to do the same for 32bit RID only. For 64bit RID, it gets build successfully, but I m not able to run it. Let me know if you find any other solution to make it work.

eerhardt commented 6 years ago

Why is there no ability to generate a RID-specific app host executable that uses shared components?

Guessing discovery of the shared components? They are relative to dotnet in path; or relative to exe for selfcontained

Correct, that is what is blocking this scenario - See my comment above

dasMulli commented 6 years ago

We have %PROGRAMFILES% on Windows, but there isn't currently the same well-known global location on Unix.

I guess it could be done similar to how the msbuild sdk resolver works - find a dotnet on the PATH and try from there (IIRC).

ms0713 commented 6 years ago

My .net core 2.0 console application runs properly in Windows OS. But I m having problem running it on RHEL7.

In my .sln file, I have 6-7 projects (.Net Stansard Library 2.0). Some projects depends on some other. But my solution file does not contain any word like postProject.

When I run following command, it gives no error and command prompt comes back without doing anything. Also it gives no error or nothing. $ dotnet AppName.dll 1 1 is command line argument.

My application uses SQL connection, Reflection, Third Party dlls( developed in c++), socket connection etc.

I also tried running a demo application with command line arguments, SQL connection. It works fine in RHEL7. My application dll has version like 1.2.3.4. While Publishing my code, it gives target runtime as Portable. But another sample with target runtime as Portable wotks fine in RHEL7.

What could be the problem? If you have any idea regarding this please share.

danmoseley commented 6 years ago

@ms0713 please open a new issue for this instead. Try setting COREHOST_TRACE (export COREHOST_TRACE=1) and then running again. do you get extra output?

danmoseley commented 6 years ago

Oh, I see you already did.

CharlesOkwuagwu commented 6 years ago

VS2017 should really provide a simple way to generate a console application (.EXE) regardless of the selected framework, .NetCore 2.0, Full, Standard, etc.

Just a thought ...

gbfromhb commented 6 years ago

Did I read this whole thing right? There is no easy way to make a .net core console exe file from Visual Studio without all the .net core files that are already on the machine it is getting deployed to?

I see all this other stuff about other operating systems, and that is good and all, but you have a loyal base of programmers who have been working at this in a completely Windows environment for many years, and if you can't get this to work as easy or close to as easy as it has been, and it is very time consuming to migrate. You open the door for people to look at other solutions besides .net Core.

KathleenDollard commented 6 years ago

Thanks for the ongoing feedback. We're continuing to contemplate improvements to the confusion on Windows.

gbfromhb commented 6 years ago

Thank you for your response @KathleenDollard. figuratively speaking I may have been on the back end of one more thing I could not copy and paste code from an old project since I've been working with .net core. The statement may have been a little over the top. I started a fairly large new project and made the call to jump early thinking the early adventures would still be less then refactoring later. Well it has been a tough haul, and until 2.0 I was concerned I made the wrong choice.

I've been at this core adventure since 1.1 and a big advocate. With more then a few times colleges asking me why something is taking so long as I had to learn a new way of doing something or find a workaround in the early days for more then a few things, and I would say it is all going to be worth it.

I understand the quest of making everyone working on all operating systems feel that an equal effort is being put forward for the operating system they work on, however there is a base of customers that need to be able to feel like what was as easy as before, will be close to being as easy as it was. This experience feels like when John Sculley started running Apple and they had a huge base of customers that were in the Graphic arts and artistic industries and he went after the big business community with a broader swipe, and their base customers felt they were not being listened to and I'm sure this was not the only reason as to why it did not work out for him at Apple, but I think it was a factor. Yes, I've been around this long.

Don't think I'm not going to embrace being able to port my code to other operating systems. I have about 12 Raspberry Pis around the house doing everything from Media players, a MySql database server for the media players, security cameras, a security hub, to running Samba as domain controllers with Active Directory. When I have time I'm going to be putting together my first .net core app to run on a Raspberry Pi, and I can't wait. I guess what I'm saying is this has to be easier and more productive for existing .net users to move from the old .net to the new.

tamusjroyce commented 6 years ago

So .net core console app does not package any native executable launchers? Without being able to directly launch anything, it is not a console app. You could, however, include a OS specific script to act as a launcher. Could also include OS specific executable to launch it. Or change Mac, Win, and Linux to recognize and launch it as an assembly through a runtime.

But as-is, this project type's intended purpose is broken. I am hoping someone sees this as an oversight and corrects it.

benaadams commented 6 years ago

So .net core console app does not package any native executable launchers?

It does if you specifically target a platform as a standalone app; but then it also includes the whole runtime so increases the size 40-90mb (depending if you illink it or not)

tamusjroyce commented 6 years ago

If you target .NET framework standard, often using preprocessor directives, it is no longer .NET core. Still broken. Unless you mean something different?

tamusjroyce commented 6 years ago

Possible work-around: Would it be possible to have three separate .NET standard projects, each targeting Linux, Mac, and Windows respectively? And those each reference your .NET core console app? Will this add the native launchers?

manigandham commented 6 years ago

@tamusjroyce

.NET Core being cross-platform means the final executable varies and is excluded from the normal build. This allows the output to be used across any platform and run via the dotnet command.

If you definitely know the platform you want (ie: Windows), then you can generate the executable by specifying this in the build command: dotnet.exe publish -r win-x64 will give you an executable file for Windows. You can pick the "RID" for the platform(s) you want to generate executables for from the full catalog available here: https://github.com/dotnet/docs/blob/master/docs/core/rid-catalog.md

The side effect is that the runtime is also included (more DLLs) along with the executable, so the published output folder will be larger.

dasMulli commented 6 years ago

There already is a host that can run a non-selfcontained RID-specific build output. If a user does a dotnet build -r win-x64, the bin/{Configuration}/{TFM} folder already contains a {project}.exe and "only" a hostfxr.dll and hostpolicy.dll.

While a dotnet publish -r win-x64 --self-contained false creates a RID-specific build, it does not include this host, --self-contained true (default) adds that host but also the full framework.

Maybe this can be extended to allow something like dotnet publish -r win-x64 --self-contained false --include-apphost to perform a RID-specific build with publish semantics that includes a host (exe + hostfxr/hostpolicy) but not the entire framework.

The current workaround would be to do a dotnet publish -r win-x64 --self-contained false followed by dotnet build -r win-x64 and then manually copying the .exe and hostfxr/hostpolicy to the publish output.

gbfromhb commented 6 years ago

From within Visual Studio was what I was talking about, not command line.

AdamJamesNaylor commented 6 years ago

Just wanted to add to the demand here. I was surprised to see no .exe in the output folder.

My ideal use case would be a console app that gets compiled to an .exe (when requested) and runs against the shared framework. (Appreciate your comments above about the difficulty in locating the framework outside of windows)

agnibos commented 6 years ago

everything described here makes sense, including the necessity to do a dotnet bootsrapper for cross-platform dll entry point, however, a PRACTICAL solution would have been an option in tooling to auto-generate myapp.exe for win and myapp(sh) for *.nix automatically, in this case you would have generated:

KathleenDollard commented 6 years ago

@agnibos,

Clarification: Do you want two outputs? Do you want better switches so you have these options via switch? Do you want all three by default?

Thanks, We have this on our mind as well, but we want to get this right.

dasMulli commented 6 years ago

@agnibos any reason to have the .exe instead of a bat/cmd file like the sh script for *nix? That way the PATH on windows will also affect the resolution of the framework which is useful for build scripts or custom ENV setups when you just add some local copy / dev build etc. to the PATH and get going. Same for 32 vs 64 bit - whichever is on the PATH first will be chosen.

itadapter commented 6 years ago

@dasMulli the only thing to be careful about, and maybe it is not an issue at all (which I cant judge about of the top): if you do a .bat/.cmd wrapper then gotta make sure that all args and stdio streams get handled as-if cmd did not exist, that is, consider something like: tool.exe a1 a2 -abcd | tool2.exe --fast < myanswers.txt

still it would have been awesome to have a native stub a-la .NETf *.exe named the same as "exe" dll,

agnibos commented 6 years ago

@KathleenDollard let me give some practical reasoning based on net core adoption patterns.

what we have seen in our dev user group - the first and primary "shock" of net core vs/tooling demo (for seasoned .NET devs) is not the lack of some win-specific stuff but that folks can not get exes to appear. It is a culture shock!!! especially for legacy windows devs who have been around since 2000s.

What would be nice is a msbuild step/target (or whatever is the proper MSBuild lingo) that would pack the win-specific entry point AND it does not have to be as complex as RID-specific "publish" process. Basically, in java there are cli bundlers for making an exe out of jar files. Can we just not create this as a build step? it is important to have this as a part of "f5" in VS :) This is very important to curb the initial netcore adoption fear for businesses. It is silly, but it is what it is.

There gotta be some kind of quick EXE gen way especially for scenarious like we have: we build whole solution using msbuild/vs, deploy the /out/fx folder without any dotnet steps. And everything works. What sucks is req to type-in dotnet mytool.dll every time, whereas in /out/netf we just type tool -abc

However, there are other issues in case of EXE stub to be concerned about. Firstly, the EXE header flags, stack size, linking address all of that stuff. If we use EXE merely as a shortcut to dotnet *.dll then we need to think what this EXE and consequential process attributes are going to be... i.e. we can not just create a 32bit process that forks to 64 bit dotnet host.... so probably the msbuild task/step has to take some exe-specific options. On the other hand, someone mentioned that win-specific EXE would contradict *nix etc.. it does not, as we can take the files built on Linux and put it on Windows to run.... otherwise dot include the EXE option in build

KathleenDollard commented 6 years ago

@agnibos Thanks for your input.

The dotnet foo approach runs a patched version if available. The .NET Full Framework (.NET 4.x) also runs patches. This seems important, do you agree?

One solution to the dotnet version issue is a script (batch file). But would that solve the confusion you describe?

gbfromhb commented 6 years ago

No.

dasMulli commented 6 years ago

@KathleenDollard even the rid-specific host that is put into the RID-specific build (not publish) output should also roll forward since that logic is afaik implemented in the hostfxr.dll that is included in the build output.

Maybe core-setup could produce a statically linked version of the hosts so you don't need to copy the two dlls (hostfxr.dll, host policy.dll) around.

To be clear, the dotnet flags (-r win-x64 etc.) I posted earlier can all be set as defaults in the csproj files (=> <RuntimeIdentifier>win-x64</…>), VS just doesn't have UI for most of them.

warrenrumak commented 6 years ago

Batch files can't have an icon, can't be used as a Windows Service, can't be pinned to Start, can't be a Taskbar item, can't have Compatibility settings, can't have a version number applied to it, can't be digitally signed, can't be the target of a call to ShellExecute()......

It's not a solution.

itadapter commented 6 years ago

When we run classic .NET exes, how does the system load proper CLR? Why can't that be the case with centrally-installed dotnet core? I think there is confusion with self-contained runtime deploys. What most of devs want is similar behavior to regular NET: you have a machine wide core installed, and have exe that you run it locates the latest entry point and launches it, and yes, it is Win-specific, would be nice to have symmetrical ELF stub on Linux

dasMulli commented 6 years ago

The current exe stub is linked against a dll shipped in windows which finds&loads a CLR or prints an error message.

Problem is that "a machine-wide" install isn't how .net core works. "a" > multiple side-by-side versions, "machine-wide" > a folder with a dotnet.exe somewhere that is in the PATH

I hope I don't confuse "self-contained" with "RID-specific" too much.

itadapter commented 6 years ago

@dasMulli thats all understood, but in many cases this complexity (side-by-side fxs) is not needed. In many case you want to have one core on machine a-la one clr. that simple. Is this not how .core install works now? This is how we use it. Install the runtime, test everything and use it. Then the EXE/ELF stub should work exactly as classic .NET worked - it should find the dotnet in path and use that, whatever version it is. Otherwise, override your DOTNET-PATH var or something.

dasMulli commented 6 years ago

Agreed, this is what the current RID-specific non-self-contained host does (.exe with the 2 dlls that) does (and what doesn't work with dotnet publish well right now).

At the moment, the side-by-side install is probably most needed for .net core 1. vs 2.. Major versions don't roll-forward at the moment. In Full .NET, this is similar to the 2.0 vs 4.0 CLRs, but now that 2.0 isn't really used anymore and 4.0 has a good level of compatibility, it hasn't caused much dev concerns lately.

It's going to get a little more complicated now that ASP.NET Core is moving from a runtime store to a shared framework similar to .net core itself (So you'd get another folder next to Microsoft.NETCore.App in the shared folder next to dotnet.exe) which has similar loader concerns. Since this will be transparent with an update to dotnet.exe/hostfxr/hostpolicy in the global install, apps run with dotnet foo.dll won't notice any difference but the RID-specific host I talked about will need an update. So as long as parts like this change every year or so, it's going to be difficult to ship native binaries that work against the "global install".

agnibos commented 6 years ago

The "one central core" logically is what many users need. same way it was in .net, t4 it makes sense to create a entry exe without all those rid complexities. Also, please make it an option that it creates it on build from VS/vscode without having to run any command line packers manually

Genbox commented 6 years ago

Self-contained applications should produce an EXE file on Windows which replaces the DLL file entirely. There is no need for distributions to have both, and it only creates problems like this one https://github.com/dotnet/cli/issues/7452

Similarly, it should be ELF on Linux and Mach-O on Mac OS.

gforceg commented 6 years ago

I can generate an exe easily enough w/ a command like: dotnet publish -o pub --self-contained -r win10-x64, but unfortunately when I move that "self-contained" binary into a folder in my path and try to run it I get the error: A fatal error occurred, the required library hostfxr.dll could not be found at <a directory in my path>

I guess self-contained means "self contained across many files in the same directory?" I don't want to pollute the folder with a bunch of .dll files. Publishing as a dll doesn't seem to help either. If the dll is placed into my path, dotnet can't find it ('dotnet myApp.dll') unless myApp.dll is in the same folder I'm working in.

The work around seems to be, create a whole new folder and add THAT folder to my path then publish to that folder. (this is messier than I'd like)

is there another publish flag I can use to get an exe that will run in windows w/o any dependencies that live in the same folder?

benaadams commented 6 years ago

Could install of runtime/sdk set the common path in an environment variable? Then use the environment variable for platform specific exes; that aren't self contained? (e.g. where the common/shared runtime dlls are)

Genbox commented 6 years ago

@gforceg self-contained just means the runtime is published with your application. You have to go to the publish folder within the win10-x64 folder to see the self-contained version. For now, .NET Core does not officially support static compilation (compiling all the DLL files to a single EXE file).

You might find this blogpost helpful: https://ianqvist.blogspot.com/2018/01/reducing-size-of-self-contained-net.html

The only other alternative is to create an installer for your application.

tamusjroyce commented 6 years ago

I still see having compiled code without an individual launcher is not a usable program. And thus an issue. The launcher could be a script or executable. Those are details I would rather leave up to the person(s) who to resolves this.

Whatever is decided, I would like it to be robust? And I really like the idea of being able to targeting one or more systems based on a selection. Or even with each targeted system, being able to select a scripted launcher, an executable launcher, or both. To be fully featured. Not necessary to resolve this issue. But would be greatly appreciated.

I also appreciate that there is a desired feature for .NET core to combining multiple assemblies into one. I don't believe that has bearing on this issue. But good to know!

Note: Powershell could be a cross compatible dependency to the launcher. Or bash, with msys or bash for windows.

livarcocc commented 6 years ago

@benaadams if the runtime could be acquired only through an installer, that would solve the problem, but what about the archive scenario? I am not sure we want to build a runtime experience for things that work only when the PATH is set in a particular way.

warrenrumak commented 6 years ago

@Genbox Of course, one of the many problems of doing static linking is that security issues (like the one released this month for .NET Core) require you to recompile and redistribute your application. The unpatched vulnerability might also not be picked up by various scanner tools.

Also, more significantly, it cannot take advantage of the Windows NT memory manager's capability to share pages between multiple processes. It's fine if you're running multiple copies of the same program, but if you had, say, a dozen different utilities installed that each took a dependency on their own local copy of .NET Core, memory usage will be massively higher and load times will be longer.

livarcocc commented 6 years ago

cc @steveharter

Genbox commented 6 years ago

@warrenrumak You are completely right. However, every piece of software has different use cases, and in some of them, it does not make sense to deploy a bulky set of assemblies. I'm not at all a proponent of doing things inefficiently like having all applications statically compiled, but I have run into many environments and deployments where I had to find a workaround to deploy a .NET application, where static compilation would have been the right solution.

Static compilation is not the subject of this issue though, so let's keep it on topic.

Genbox commented 6 years ago

@livarcocc Java chose to create a handler for .jar and setting the environment variable JAVA_HOME. It is far from optimal but as long as applications are not registered in an ecosystem with an identity you can count on (like UWP apps) on different platforms, it is going to be a problem that can't be solved in a way that supports all use cases.

itadapter commented 6 years ago

can we just return the traditional .Net behavior with a simple exe stub loading whatever FX is on the machine? make this optional, just like a build step - a wrapper that calls dotnet under the hood

fanoI commented 6 years ago

I think the idea to simply create .net / .dotnet archive as does Java with .jar files has merits:

  1. It is not biased on Windows, a .exe file on Linux / Mac OSX it is not "elegant" to see
  2. Creating a stub .elf for any Linux distribution will be hell as any release of the kernel make the executable incompatible (it libc changes for example)
  3. It is simple: net core on installation adds to the OS to execute .net files the OS must call "dotnet run .net". Side by side installations of dotnet should work in the same way they would do if I did "dotnet run .net" on the shell

I add another scenario in which a simple executable format will be needed: Cosmos OS. A "self-contained" application would not have sense there as the .NET run time is part of the OS itself we will have a file of 3 MB for a simple "dir" command and we should discard / ignore the 90% of it.

FrederickBrier commented 6 years ago

A lot of this confusion seems to come from Microsoft documentation that tells how to generate an exe. Or this one that explicitly shows how to write and then register a ASP.NET Core app exe as a Windows service. Until I started reading this github issue, I was puzzled (and a bit frustrated) why all the doc about inserting and XML elements was not generating an EXE.

Since my interest is in deploying my .NET Core web app as a Windows service, and if generating an EXE is not an option, I tried to create my service with a command line that looks like this:

sc create MyWebApp binPath= "C:\Program Files\dotnet\dotnet.exe c:\MyAppDir\MyWebApp.dll"

So far, it seems to work.

FrederickBrier commented 6 years ago

I do like the idea of Self-Contained Deployments. I am currently using preview releases to gain access to the owned type facility in EF Core. Unfortunately, while EnsureCreated() works in my Visual Studio environment, when I deploy to the server, it seems to be using an older EF Core assembly included in the .NET Core SDK 2.1.0/2.0.5 installer and throws exceptions. Beyond the:

    <OutputType>Exe</OutputType>
    <RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>

What else do I need to do to have the app deployed as an SCD? Thank you.

livarcocc commented 6 years ago

@FrederickBrier You can either have RuntimeIdentifier (singular), which will make your app always self-contained. Or, you can pass -r win10-x64 (or some other rid) to the publish command when publishing your app.

eerhardt commented 6 years ago

See https://github.com/dotnet/core-setup/issues/3720 for the proposal on making the runtime support this scenario.

Note that there will need to be additional SDK/tooling work on top of the runtime support to enable the feature end-to-end. But having the runtime support is the first step.