rust-lang / cargo

The Rust package manager
https://doc.rust-lang.org/cargo
Apache License 2.0
12.5k stars 2.37k forks source link

New env vars for better support custom targets-spec for build-scripts #14208

Open boozook opened 1 month ago

boozook commented 1 month ago

I propose that cargo shares more information about the target in the case of custom target-spec json file used, such as name of base target (llvm-target) and CPU.

Solving this problem will give the possibility to build-scripts and crates (like cc and bingen) used in the build-script-environment to properly configure underlying non-rust build-pipeline such as build c/c++ dependencies, generating bindings, as well as just asking rustc with the requested target as does autocfg crate. Currently it's impossible in most cases.

Problem

The problem is that it is now impossible to determine all the necessary information about a non-builtin target. In other words they can't properly choose a compiler/linker to use and configure it because they don't know the base target and overlapped parameters, such as CPU, codegen parameters, overridden layout and more.

As we all know, the env var TARGET that is shared by cargo, contains rustc's "short target name", definitely not target-triple. It can be triple only if builtin target is requested. And in case we are using the user's target-spec json file we can interpret it only as a random identifier.

Wrong idea: It could be possible to read and parse a json file, but first of all, for the entire build-pipeline it will be an extra one read-n-parse exercise, and it's a bad thing assuming future changes of unstable format. Anyway, we could try it, even though it's not reliable, and fragile. After getting the path from a user cargo canonicalises it, then shares only the file-stem. What if initially the path is relative, pointing to the outside, and looks like --target=../file.json? We definitely can't realize the path by the stem from the build-script context. It is unreal to properly work with it.

What is needed?

Environment variables: (name are not final)

  1. TARGET_CPU - cpu field from spec or cli-arg, can be empty if not set
  2. TARGET_TRIPLE LLVM-target-triple from the spec file, can be empty or mirror TARGET in case of builtin target used
  3. TARGET_IS_CUSTOM as answer for "Is user custom target currently using? Or otherwise, can I interpret TARGET as triple?"
  4. Could be good to expose c-enum-min-bits, frame-pointer, data-layout, panic strategy and unwinding from the spec
  5. May be more, e.g. path to the spec, questionable - need to discuss

Possible implementation note

TARGET_IS_CUSTOM is the easiest. We already know the full path to the file. unit.kind.name.is_file. Getting other vars (such as TARGET_CPU) require reading-n-parsing json file or asking nightly rustc for it. Second option is much better, but requires nightly compiler. But if we add it to the rustc print cfg as patch, it could be easy to implement on the cargo side. I suppose this is the best option.

Nothing existing is deleted or changed. Only new things are added. So no breaking changes for API and UI.

If we could want to expose path to the spec, I suppose it's not a good idea to share path and trust the build-script with the user's original target file. If I were cargo, I would make a temporary copy of the spec in case the script changes it, before sharing it with the build-script. Because the build-script can do absolutely anything now. Definitely I could be wrong. Or just as an option, take a json source, minify and share it instead of path.

filling envs here


Also about RUSTC_LINKER and linker in a spec I see in the source `RUSTC_LINKER` is for "user-specified linker". It could be useful for purposes described above. Cargo sets this var only if `build_runner.compilation.target_linker(unit.kind)`. However, in my case I have never seen a cargo set RUSTC_LINKER. That is, even if I explicitly specify the linker `RUSTFLAGS="-Clinker=arm-none-eabi-ld"` I don't find the `RUSTC_LINKER` variable available in build-script-environment. I probably don't understand how this works. I tried cargo feature `advanced-env` too, but it is mostly for `CARGO_PROFILE_DEV_PACKAGE_`. __I'm pretty sure that the linker specified by the user in the target spec json file is also a "user-specified linker" and should also be specified if `RUSTC_LINKER` is not already specified.__ Maybe it could be a var with another name, like `TARGET_LINKER`.

Disclaimer: there is problem explanation, questions and my (not only my) thoughts. That's why an issue, not RFC or PR.


I could take some parts, I know what to do as I suppose. One more open question is - should I write issue or RFC before patch rustc print cfg?

cuviper commented 1 month ago

For the purpose of autocfg, I really just need the right value for rustc --target X, whether that's a triple or spec file. The rest of the target specifics don't matter to me, per se, but exposing more in rustc --print cfg sounds natural.

soloturn commented 1 month ago

@boozook what is the use case of this, and what do other build tools do to get this right?