dotnet / corert

This repo contains CoreRT, an experimental .NET Core runtime optimized for AOT (ahead of time compilation) scenarios, with the accompanying compiler toolchain.
http://dot.net
MIT License
2.91k stars 508 forks source link

Assembly.GetEntryAssembly().Location could be the single Exe #6947

Closed davidknise closed 5 years ago

davidknise commented 5 years ago

First, is there a way to get the full path to the executing *.exe file?

I see the reasoning that Assembly.GetEntryAssembly() value is an empty string because the assembly which it was built in no longer exists. I actually expected this to be the single executable, no matter where I was, because I wasn't thinking about the code from a pre-compiled/symbols perspective, I was thinking of it from a post-compile. **Should it be the compiled *.exe?

Scenario: I'm building our single-file installer as a small CoreRT CLI. Users can double click it or call it from the command line. The installer sets up a folder structure and drops our latest bits in the right spots. Because of this, I expect the installation directory to be empty, but it would make sense to allow for the installer to be in the directory. In addition, I ask them if they would like to clear the directory. I'd like to skip deleting this file or allow it to be the only file in the directory, but I don't know it's name and can't get a file handle to identify it either.

Related issues: #1773 #5467

jkotas commented 5 years ago

First, is there a way to get the full path to the executing *.exe file?

On Windows, you can PInvoke GetModuleFileName with NULL hModule.

jkotas commented 5 years ago

Also, AppContext.BaseDirectory returns the directory that the app lives in.

MichalStrehovsky commented 5 years ago

AppContext.BaseDirectory in combination with Path.GetFileName(Environment.GetCommandLineArgs()[0]) should be a crossplatform way to get that information in a scenario like this.

We don't want to return the path to the compiled EXE because we want to support compilation modes where some managed code gets compiled into a DLL (e.g. some of the framework code), other code stays in the EXE, but the split might be crossing an assembly boundary (some of the code from a single assembly is in the DLL, some of it is in the EXE). There's no clear answer in such mode.

The other thing is that whether the path to the compiled EXE would be the right answer really depends on what the app does with the string later. If it e.g. wants to roundtrip the string through Assembly.Load, that's not going to work. If it assumes the location is a unique string for each assembly, that's not going to work either.

This topic is coming up often enough that we might want to expose a way to set the location to something sensible through AppContext switches (e.g. expose the "Empty string", "Path to the entrypoint module", and "Module name as defined in assembly metadata without path") and pick a reasonable default.

davidknise commented 5 years ago

AppContext.BaseDirectory in combination with Path.GetFileName(Environment.GetCommandLineArgs()[0]) should be a crossplatform way to get that information in a scenario like this.

That'll do it! Environment.GetCommandLineArgs()[0] is the full path to the executable. If debugging per say in Visual Studio, it's the path to the dll because it's built, not published.

This topic is coming up often enough that we might want to expose a way to set the location to something sensible through...

Yeah there were quite a few threads about it, but most of it was interest in getting the directory of the executing assembly, which AppContext.BaseDirectory provides. I think the scenario I provided was the first I saw that really requires the name of executing file.

Thanks @jkotas and @MichalStrehovsky for the quick responses! CoreRT looks very promising!