rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
96.84k stars 12.51k forks source link

Need to re-fix Windows manifest embedding. #11207

Closed vadimcn closed 4 years ago

vadimcn commented 10 years ago

The previous attempt (#10878) to fix #10512 has a couple of problems:

  1. Sometimes UpdateResource corrupts executables produced by binutils. (The executable still runs, however tools like dumpbin report corrupted PE header, and gdb crashes when trying to read debug info).
  2. More importantly, this approach does not work for cross-compilation, because, well, you can't call Windows API if the host system is not Windows.
alexcrichton commented 10 years ago

So that's why I haven't been able to use gdb recently! That also explains why a recent attempt at objdump didn't succeed.

Sounds like we may need to revert the manifest embedding for now?

vadimcn commented 10 years ago

@alexcrichton: Yes, probably.

vadimcn commented 10 years ago

Regarding fixing this, I see a few approaches:

Currently we have no need to alter .exe manifests, and if really needed this can always be done afterwards using windres tool, so I am leaning towards option 2.

alexcrichton commented 10 years ago

Do you know the format of the COFF file? LLVM certainly has the ability to write a COFF file, and we might be able to just use their bindings to emit our own COFF file ourselves.

They seem to have lots and lots of header files and defines related to COFF object files, so seems promising? Of the options, using LLVM to generate an object and then passing that to the linker sounds the most appealing to me.

vadimcn commented 10 years ago

COFF format is well-documented, but yes, it's complicated.

Regarding LLVM: as far as I know, it is not possible to create PE COFF resource section even in native assembly, much less in LL code. I actually investigated this approach, but ran into inability to emit RVA offsets. Apparently this can only be done by writing .obj file directly.

yuriks commented 10 years ago

As an additional option, could a combination of options 1 and 2 work? Ship a default compiled resource file with rustc, but allow it to be overriden by the user if he wants to. (In which case he must pay the "cost" of requiring windres for that to work.)

vadimcn commented 9 years ago

FWIW, UAP installer detection heuristics may be suppsessed by setting this environment variable: __COMPAT_LAYER=RunAsInvoker.

alexcrichton commented 8 years ago

@vadimcn I'm not sure I ever really fully understood what manifests were or why we were embedding them, but given today's landscape of Rust-on-Windows does this still make sense? Is this something we should do on MSVC as well as MinGW?

vadimcn commented 8 years ago

Manifests are just metadata about the executable that tells Windows more about its requirements and capabilities. One of the most frequent uses is to specify whether the program expects to run with admin privileges (otherwise Windows will try to guess - for compatibility with pre-Vista executables), but there other features beyond that.

MSVC linker will embed a default manifest by, um, default. As for MinGW - see above.

alexcrichton commented 8 years ago

Ah ok, so in that case should is the MSVC manifest that's automatically embedded a well known manifest? If so then it sounds like this is still relevant for MinGW and it'd just be one of the strategies you outlined above.

taralx commented 8 years ago

As a note - rustup-setup was just renamed rustup-init because of this issue.

steveklabnik commented 5 years ago

Triage: not aware of any changes here

jonas-schievink commented 4 years ago

I suggest closing this in favor of https://github.com/rust-lang/rfcs/issues/721 and the embed_resource crate.

jpoles1 commented 4 years ago

@jonas-schievink can you please elaborate on the steps required to embed a manifest using the embed_resource crate?

jonas-schievink commented 4 years ago

@jpoles1 I've never used it, but you can check the docs and crates that use it

jpoles1 commented 4 years ago

@jonas-schievink I read the docs and still unsure of how to embed the manifest. Are you aware of any crates that use the library in this manner? Understand if not, and thanks for your assistance.

jonas-schievink commented 4 years ago

cargo-update (by the same author) uses it: https://github.com/nabijaczleweli/cargo-update/blob/master/build.rs

jpoles1 commented 4 years ago

@jonas-schievink, that's perfect, thanks for the tip!

My specific use case was to programatically enable admin permissions on my .exe file, the steps I used to get this working are as follows: 1) Add the following to your cargo.toml:

[build-dependencies]
embed-resource = "1.3"

2) In your project root directory, add a file named build.rs with the following:

extern crate embed_resource;
fn main() {
    embed_resource::compile("app-name-manifest.rc");
}

3) In your project root directory, add a file named app-name-manifest.rc with the following:

#define RT_MANIFEST 24
1 RT_MANIFEST "app-name.exe.manifest"

4) In your project root directory, add a file named app-name.exe.manifest with the following:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
            </requestedPrivileges>
        </security>
    </trustInfo>
</assembly>

5) Build your project!

steveklabnik commented 4 years ago

Great! Let's close in favor of those.