rust-lang / rls

Repository for the Rust Language Server (aka RLS)
Other
3.51k stars 257 forks source link

Support cross-compiling and custom targets #104

Open emberian opened 7 years ago

emberian commented 7 years ago

When working on Robigalia, I need to build with xargo build --target i686-sel4-unknown (as an example), to get core etc built for my custom target. This prevents me from using RLS.

oli-obk commented 7 years ago

What needs to be done to get this to work?

I'll do the work, but I'll need some pointers where to start

nrc commented 7 years ago

So, I must admit I am not really sure how Xargo works, so this might all be pretty wrong, but afaik...

AIUI, Xargo manages the build via Cargo and the sysroot. We currently find the sysroot using rustc --print sysroot. However, beyond that I have no idea what would need to change in the RLS. Perhaps @japaric might know?

We are pretty deeply integrated with Cargo - we call its API rather than shelling out to it, so we cannot use Xargo as a drop-in replacement. I'm not sure even what the UI would look like here. I assume we would need a way to specify cross-compilation (in rls.toml to start with, I guess). We would then shell out to Xargo to setup the sysroot and pass some extra parameters to Cargo? I don't know what those extra-parameters might be.

Supporting --target would be much easier! (And probably a good first step to support here). We would just need to add a target option to the config (see config.rs) and then when we call cargo (in build.rs), set the target on our CompileOptions object (if you grep for build_lib you should see all the places we touch that option, I think target would follow that quite closely).

japaric commented 7 years ago

I haven't used the RLS yet so I can't give any pointers about how to integrate it with Xargo. But, I can provide more details about how Xargo works.

xargo build --target $T does two things: It builds a sysroot (using Cargo) for the target $T and then invokes cargo build --target $T with RUSTFLAGS='--sysroot ~/.xargo' (note that the sysroot path doesn't include the target $T in it) to make it use the Xargo sysroot.

Now, sysroots are cached so when you are working on the same project the sysroot will most likely be built once and then be reused for every subsequent Xargo command. The only cases where the sysroot gets rebuilt is when Xargo.toml changes or when you change [profile.release.*] options in Cargo.toml. The Xargo.toml indicates Xargo which crates it should build and put in the custom sysroot. By default, Xargo just builds the core crate.

nrc commented 7 years ago

Thanks @japaric!

So, it sounds like the RLS will have to shell out to Xargo before using Cargo if we are in 'xargo-mode', get the RUSTFLAGS from xargo (this might mean modifying Xargo to not call Cargo if it is not possible to use Xargo in a dry-run mode), then pass these RUSTFLAGS to Cargo. Alternatively, we could link Xargo into the RLS and use it as a library to find the flags (not sure which is easier without knowing the code better). Both approaches feel very doable, although making this a good user experience might be a bit harder.

oli-obk commented 7 years ago

cargo automatically reads the target from ".cargo/config". I think it would be a good first step to support .cargo/config in general.

I'll work on that now

oli-obk commented 7 years ago

Ok. I got it working without modifying rls:

I executed RLS from the rust vscode extension with the following settings

    "rust.rls": {
        "executable": "path/to/rls/target/debug/rls.exe",
        "env": {
            "RUSTFLAGS": "--sysroot your/home/dir/.xargo",
            "PATH": "your/home/dir/.rustup/toolchains/nightly-x86_64-pc-windows-msvc/bin"
        }
    }

but this method only works on windows so far, due to the cargo calls not being able to run rustc:

thread '<unnamed>' panicked at 'could not run cargo: ChainedError { error: failed to run `rustc` to learn about target-specific information, cause: process didn't exit successfully: `rustc - --crate-name ___ --print=file-names -Zunstable-options -Zsave-analysis --error-format=json -Zcontinue-parse-after-error --crate-type bin --crate-type rlib --target stm32f7` (exit code: 101)
--- stderr
{"message":"Error loading target specification: Could not find specification for target \"stm32f7\"","code":null,"level":"error","spans":[],"children":[{"message":"Use `--print target-list` for a list of built-in targets","code":null,"level":"help","spans":[],"children":[],"rendered":null}],"rendered":null}
 }', /checkout/src/libcore/result.rs:859
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
   0: <core::result::Result<T, E>>::expect
             at /checkout/src/libcore/result.rs:761
   1: rls::build::BuildQueue::cargo::{{closure}}
             at ./coding/rls/src/build.rs:433
   2: <std::panic::AssertUnwindSafe<F> as core::ops::FnOnce<()>>::call_once
             at /checkout/src/libstd/panic.rs:296
   3: std::panicking::try::do_call
             at /checkout/src/libstd/panicking.rs:454
   4: __rust_maybe_catch_panic
             at /checkout/src/libpanic_unwind/lib.rs:98
   5: std::panicking::try
             at /checkout/src/libstd/panicking.rs:433
   6: std::panic::catch_unwind
             at /checkout/src/libstd/panic.rs:361
   7: std::thread::Builder::spawn::{{closure}}
             at /checkout/src/libstd/thread/mod.rs:360
   8: <F as alloc::boxed::FnBox<A>>::call_box
             at /checkout/src/liballoc/boxed.rs:640
   9: std::sys::imp::thread::Thread::new::thread_start
             at /checkout/src/liballoc/boxed.rs:650
             at /checkout/src/libstd/sys_common/thread.rs:21
             at /checkout/src/libstd/sys/unix/thread.rs:84
  10: start_thread
  11: clone

I'll investigate what causes the failure to run rustc on linux

oli-obk commented 7 years ago

I think the relevant parts are

Error loading target specification: Could not find specification for target \"stm32f7\"

Which I can reproduce by running

RUSTFLAGS="--sysroot path/to/home/.xargo" cargo build

Ah no, just a typo... it works fine when running cargo directly with RUSTFLAGS set to "--sysroot some/path"

oli-obk commented 7 years ago

So the RUSTFLAGS env var is not used:

rustc - --crate-name ___ --print=file-names -Zunstable-options -Zsave-analysis --error-format=json -Zcontinue-parse-after-error --crate-type bin --crate-type rlib --target stm32f

related to https://github.com/rust-lang-nursery/rls/issues/238 ?

nrc commented 7 years ago

Unrelated to #238, I think. But things are kind of complex here.

In the last comment I'm not sure what you're quoting. I suspect the calls from Cargo to rustc for dependent crates? We set RUSTFLAGS ourself before calling Cargo (search build.rs for RUSTFLAGS). The easy solution is to combine our flags with anything the user has set already. However, note that we also set the sysroot explicitly when calling rustc, so I think you'll have to do something there too.

oli-obk commented 7 years ago

Indeed these were the relevant locations! Thanks

It works mostly now. The only issue left is that sometimes we pass --sysroot twice

DEBUG:rls::server: Language Server Starting up
TRACE:rls::server: reading: 154 bytes
TRACE:rls::server: command(init): InitializeParams { process_id: Some(25020), root_path: Some("/home/oliver/Projects/rust/blinky"), initialization_options: None, capabilities: Object({}) }
DEBUG:rls::server: response: "Content-Length: 487\r\n\r\n{\"jsonrpc\":\"2.0\",\"id\":0,\"result\":{\"capabilities\":{\"textDocumentSync\":2,\"hoverProvider\":true,\"completionProvider\":{\"resolveProvider\":true,\"triggerCharacters\":[\".\",\":\"]},\"signatureHelpProvider\":{\"triggerCharacters\":[]},\"definitionProvider\":true,\"referencesProvider\":true,\"documentHighlightProvider\":true,\"documentSymbolProvider\":true,\"workspaceSymbolProvider\":true,\"codeActionProvider\":false,\"documentFormattingProvider\":true,\"documentRangeFormattingProvider\":true,\"renameProvider\":true}}}"
DEBUG:rls::server: response: "Content-Length: 72\r\n\r\n{\"jsonrpc\":\"2.0\",\"method\":\"rustDocument/diagnosticsBegin\",\"params\":null}"
DEBUG:rls::actions: build "/home/oliver/Projects/rust/blinky"
TRACE:rls::build: cargo - `"/home/oliver/Projects/rust/blinky"`
TRACE:rls::build: manifest_path: "/home/oliver/Projects/rust/blinky/Cargo.toml"
TRACE:rls::server: reading: 76 bytes
TRACE:rls::server: parsing invalid message: ParseError { kind: InvalidData, message: "setTraceNotification", id: None }
TRACE:rls::server: reading: 112 bytes
TRACE:rls::server: parsing invalid message: ParseError { kind: InvalidData, message: "didChangeConfiguration", id: None }
TRACE:rls::server: reading: 281 bytes
TRACE:rls::server: notification(open): DidOpenTextDocumentParams { text_document: TextDocumentItem { uri: "file:///home/oliver/Projects/rust/blinky/src/main.rs", language_id: Some("rust"), version: Some(1), text: "#![no_std]\nextern crate stm32f7_discovery as stm32f7;\n\nfn main() {\n    let x = 5;\n    x = 6\n}\n" } }
TRACE:rls::actions: on_open: "/home/oliver/Projects/rust/blinky/src/main.rs"
DEBUG:rls::server: response: "Content-Length: 72\r\n\r\n{\"jsonrpc\":\"2.0\",\"method\":\"rustDocument/diagnosticsBegin\",\"params\":null}"
DEBUG:rls::actions: build "/home/oliver/Projects/rust/blinky"
TRACE:rls::build: intercepted rustc, args: ["--crate-name", "blinky", "src/main.rs", "--color", "never", "--crate-type", "bin", "--emit=dep-info,metadata", "-C", "debuginfo=2", "-C", "metadata=699e03a8048af6a0", "-C", "extra-filename=-699e03a8048af6a0", "--out-dir", "/home/oliver/Projects/rust/blinky/target/rls/stm32f7/debug/deps", "--target", "stm32f7", "-L", "dependency=/home/oliver/Projects/rust/blinky/target/rls/stm32f7/debug/deps", "-L", "dependency=/home/oliver/Projects/rust/blinky/target/rls/debug/deps", "--extern", "stm32f7_discovery=/home/oliver/Projects/rust/blinky/target/rls/stm32f7/debug/deps/libstm32f7_discovery-bee06a8a5940ae81.rmeta", "--sysroot", "/home/oliver/.xargo", "-Zunstable-options", "-Zsave-analysis", "--error-format=json", "-Zcontinue-parse-after-error"]
TRACE:rls::build: envs: {"CARGO_PKG_DESCRIPTION": Some(""), "CARGO_MANIFEST_DIR": Some("/home/oliver/Projects/rust/blinky"), "CARGO_PKG_VERSION_PATCH": Some("0"), "LD_LIBRARY_PATH": Some("/home/oliver/Projects/rust/blinky/target/rls/debug/deps:/home/oliver/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib"), "CARGO_PKG_VERSION_MINOR": Some("1"), "CARGO": Some("/home/oliver/Projects/rust/rls/target/debug/rls"), "CARGO_PKG_VERSION_PRE": Some(""), "CARGO_PKG_VERSION_MAJOR": Some("0"), "CARGO_PKG_HOMEPAGE": Some(""), "CARGO_PKG_NAME": Some("blinky"), "CARGO_PKG_VERSION": Some("0.1.0"), "CARGO_PKG_AUTHORS": Some("Oliver Schneider <git-no-reply-9879165716479413131@oli-obk.de>")}
TRACE:rls::build: rustc - args: `["rustc", "--crate-name", "blinky", "src/main.rs", "--color", "never", "--crate-type", "bin", "--emit=dep-info,metadata", "-C", "debuginfo=2", "-C", "metadata=699e03a8048af6a0", "-C", "extra-filename=-699e03a8048af6a0", "--out-dir", "/home/oliver/Projects/rust/blinky/target/rls/stm32f7/debug/deps", "--target", "stm32f7", "-L", "dependency=/home/oliver/Projects/rust/blinky/target/rls/stm32f7/debug/deps", "-L", "dependency=/home/oliver/Projects/rust/blinky/target/rls/debug/deps", "--extern", "stm32f7_discovery=/home/oliver/Projects/rust/blinky/target/rls/stm32f7/debug/deps/libstm32f7_discovery-bee06a8a5940ae81.rmeta", "--sysroot", "/home/oliver/.xargo", "-Zunstable-options", "-Zsave-analysis", "--error-format=json", "-Zcontinue-parse-after-error", "--test", "--sysroot", "/home/oliver/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu"]`, envs: {"CARGO_PKG_DESCRIPTION": Some(""), "CARGO_MANIFEST_DIR": Some("/home/oliver/Projects/rust/blinky"), "CARGO_PKG_VERSION_PATCH": Some("0"), "LD_LIBRARY_PATH": Some("/home/oliver/Projects/rust/blinky/target/rls/debug/deps:/home/oliver/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib"), "CARGO_PKG_VERSION_MINOR": Some("1"), "CARGO": Some("/home/oliver/Projects/rust/rls/target/debug/rls"), "CARGO_PKG_VERSION_PRE": Some(""), "CARGO_PKG_VERSION_MAJOR": Some("0"), "CARGO_PKG_HOMEPAGE": Some(""), "CARGO_PKG_NAME": Some("blinky"), "CARGO_PKG_VERSION": Some("0.1.0"), "CARGO_PKG_AUTHORS": Some("Oliver Schneider <git-no-reply-9879165716479413131@oli-obk.de>")}, build dir: "/home/oliver/Projects/rust/blinky"
error: Option 'sysroot' given more than once.

DEBUG:rls::actions: build - Success
TRACE:rls::actions: reload analysis: "/home/oliver/Projects/rust/blinky"
INFO:rls_analysis: reload "/home/oliver/Projects/rust/blinky" "/home/oliver/Projects/rust/blinky"
INFO:rls_analysis::lowering: Total lowering time: 0.00s
INFO:rls_analysis::lowering: Diff in rss: 0.00KB
DEBUG:rls::server: response: "Content-Length: 70\r\n\r\n{\"jsonrpc\":\"2.0\",\"method\":\"rustDocument/diagnosticsEnd\",\"params\":null}"
TRACE:rls::build: rustc - args: `["rustc", "--crate-name", "blinky", "src/main.rs", "--color", "never", "--crate-type", "bin", "--emit=dep-info,metadata", "-C", "debuginfo=2", "-C", "metadata=699e03a8048af6a0", "-C", "extra-filename=-699e03a8048af6a0", "--out-dir", "/home/oliver/Projects/rust/blinky/target/rls/stm32f7/debug/deps", "--target", "stm32f7", "-L", "dependency=/home/oliver/Projects/rust/blinky/target/rls/stm32f7/debug/deps", "-L", "dependency=/home/oliver/Projects/rust/blinky/target/rls/debug/deps", "--extern", "stm32f7_discovery=/home/oliver/Projects/rust/blinky/target/rls/stm32f7/debug/deps/libstm32f7_discovery-bee06a8a5940ae81.rmeta", "--sysroot", "/home/oliver/.xargo", "-Zunstable-options", "-Zsave-analysis", "--error-format=json", "-Zcontinue-parse-after-error", "--test", "--sysroot", "/home/oliver/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu"]`, envs: {"CARGO_PKG_DESCRIPTION": Some(""), "CARGO_MANIFEST_DIR": Some("/home/oliver/Projects/rust/blinky"), "CARGO_PKG_VERSION_PATCH": Some("0"), "LD_LIBRARY_PATH": Some("/home/oliver/Projects/rust/blinky/target/rls/debug/deps:/home/oliver/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib"), "CARGO_PKG_VERSION_MINOR": Some("1"), "CARGO": Some("/home/oliver/Projects/rust/rls/target/debug/rls"), "CARGO_PKG_VERSION_PRE": Some(""), "CARGO_PKG_VERSION_MAJOR": Some("0"), "CARGO_PKG_HOMEPAGE": Some(""), "CARGO_PKG_NAME": Some("blinky"), "CARGO_PKG_VERSION": Some("0.1.0"), "CARGO_PKG_AUTHORS": Some("Oliver Schneider <git-no-reply-9879165716479413131@oli-obk.de>")}, build dir: "/home/oliver/Projects/rust/blinky"
error: Option 'sysroot' given more than once.
nrc commented 7 years ago

It works mostly now. The only issue left is that sometimes we pass --sysroot twice

Is this even the case with your PR? (It looks like that should fix the double systroot issue).

oli-obk commented 7 years ago

Nope, the PR fixes this

nrc commented 7 years ago

To summarise: setting the sysroot and RUSTFLAGS now work. We can't yet set --target. I'm not sure about .cargo/config - I assume that works though?

oli-obk commented 7 years ago

Yes, it's possible to add sysroot = "/home/user/.xargo" so rls can use a sysroot built by xargo. There's no way currently to run xargo automatically, but once it has been run, rls can use the artifacts built by it.

nrc commented 7 years ago

--target works now as an rls.toml option

oli-obk commented 6 years ago

double sysroot is back :(

matthew-a-thomas commented 5 years ago

double sysroot is back :(

I'm curious what the status of this is? I'm also running into a double sysroot issue in the context of https://github.com/rust-lang/rls/issues/904

Nils-TUD commented 4 years ago

Apart from #1578, I got it working now. There are two important points:

If you run rustup run nightly rls it will set RUSTUP_HOME and other environment variables, so that rls does not consider SYSROOT.

Therefore, the command line I'm using is:

LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH SYSROOT=<mysysroot> RUST_TARGET_PATH=<target-json-dir> $(rustc --print sysroot)/bin/rls