Skip to content

Tracking Issue for proc_macro::{tracked_env, tracked_path} #99515

Open

Description

@m-ou-se

View all comments

Feature gate: #![feature(proc_macro_tracked_env, proc_macro_tracked_path)]

This is a tracking issue for proc_macro::tracked*, to allow adding files and environment variables to the build system's dependency tracking.

Public API

// proc_macro

mod tracked {
    pub fn env_var<K: AsRef<OsStr> + AsRef<str>>(key: K) -> > Result<String, VarError>;
    pub fn path<P: AsRef<Path>>(path: P);
}

Steps / History

Unresolved Questions

  • The full API design.
    • The implementaiton PRs were mostly focussed on the implementation details behind the scenes of proc_macro, but there's barely been any discussion on the public interface.

Activity

  1. added
    T-libs-api[DEPRECATED; DO NOT USE]
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    on Jul 20, 2022
  2. m-ou-se commented on Jul 20, 2022

    @m-ou-se
    MemberAuthor

    This feature is not in a great state. The original PRs were mostly about the implementation details, with almost no discussion on the public API. There's still many unanswered design questions, such as naming, whether path should return something (a File? a String? a TokenStream? a PathBuf? nothing?), how it should be documented, how these functions should relate to each other, whether they should report errors through panics or through Result, whether it should take AsRef<OsStr> or AsRef<str>, and so on.

    Instead of discussing every single detail separately, it'd probably be best to start with a more complete proposal for how these APIs should look, and then discuss that.

    (Usually most of this happens before an unstable feature is merged and tracked, but this has already been merged, hence this tracking issue.)

  3. mitsuhiko commented on Aug 28, 2022

    @mitsuhiko
    Contributor

    Considering these APIs effectively mirror the cargo:rerun-if-changed and cargo:rerun-if-env-changed functionality from build scripts I think it's reasonable to assume they don't return anything but just register interest.

    Right now the main reason you run into this issue is because someone already has functionality in a build script and wants to convert it into a proc_macro. I would also strongly recommend for it to not report an error if the file does not exist as absence and presence of a file is both legitimate for proc macros the same way as it works for build scripts again.

  4. bjorn3 commented on Aug 28, 2022

    @bjorn3
    Member

    Considering these APIs effectively mirror the cargo:rerun-if-changed and cargo:rerun-if-env-changed functionality from build scripts I think it's reasonable to assume they don't return anything but just register interest.

    I don't think that is a good argument. It is relatively common to forget to register interest with build scripts I believe. In addition it is pretty common to write helper functions that register interest and at the same time read the file/env var to prevent forgetting this. The reason that no such function exists by default for build scripts is because there is no way for cargo to provide a crate to build scripts with said functions. Furthermore returning the value is essential for making proc macros work with virtual filesystems and with compiler session local env vars.

  5. mitsuhiko commented on Aug 28, 2022

    @mitsuhiko
    Contributor

    It is relatively common to forget to register interest with build scripts I believe

    Maybe? But that is probably a very different argument to begin with. Today where I'm standing there is functionality available with build.rs that you cannot have with proc_macro and the same arguments for the use of it with build.rs are equally appying to proc macros.

    In addition it is pretty common to write helper functions that register interest and at the same time read the file/env var to prevent forgetting this.

    By coupling these things together this has a high change of turning into a never ending argument because there will always be a disagreement about how this should work. In fact, even today you will find no agreement on how to best use the build script equivalents and if we had to come to an agreement about his this should work there, we probably wouldn't have solution there today with build scripts.

    If there is a need for such an API it can always be added at a later point.

    The reason that no such function exists by default for build scripts is because there is no way for cargo to provide a crate to build scripts with said functions.

    Of course there is. It would always have been possible for cargo to ship a utility library that is linked against build scripts the same way as proc_macro exposes itself.

    Furthermore returning the value is essential for making proc macros work with virtual filesystems and with compiler session local env vars.

    That same argument can be brought up for build scripts.

  6. bjorn3 commented on Aug 28, 2022

    @bjorn3
    Member

    If there is a need for such an API it can always be added at a later point.

    The interest registering version can be trivially implemented in terms of the version that returns the value by discarding the return value, but not the other way around. In addition the interest registering versions may become entirely useless if we start sandboxing proc macros depending on the way we do this.

    That same argument can be brought up for build scripts.

    For build scripts it isn't all that important that changing a file in an editor without saving it reruns them. It is essential for proc macros. In addition rust-analyzer is already having a lot of trouble with proc macros going outside of their implied (unenforced) sandbox, while it doesn't have any issues with build scripts as those run in the same environment as with a regular cargo build due to rust-analyzer using cargo for invoking them.

  7. mitsuhiko commented on Aug 28, 2022

    @mitsuhiko
    Contributor

    I want to leave another piece of input here that I believe are relevant: rerun-if-changed today can track a directory and will in fact track changes to the contents. My expectation as a user would be that I can replicate the same functionality for proc_macros. This is in fact right now what I care about was I'm trying to build something that bundles folders.

    The interest registering version can be trivially implemented in terms of the version that returns the value by discarding the return value, but not the other way around.

    If returning contents turns out to be useful it can always be added as an additional API. I think coupling these things will make this feature stay in not stable land for a lot longer than if those discussions are separated.

  8. est31 commented on Dec 12, 2022

    @est31
    Member

    I think tracked_path::path should be redesigned to also open read access to the specified path, as suggested by RFC 3200, because the current API leaves that question unresolved, which basically begs for the proc macro to use outside methods to access files, which would be a break of current policy that this is unsupported.

  9. wdanilo commented on Feb 18, 2023

    @wdanilo

    Just a note here that the current implementation does not work with relative paths. It works if I use absolute ones though.

  10. ehuss commented on Feb 18, 2023

    @ehuss
    Contributor

    @wdanilo Can you put together a reproduction? It seems to work fine for me. The path will be relative to cwd where rustc is run, which for Cargo is the workspace root (which matches the way a proc-macro would access relative paths).

  11. wdanilo commented on Feb 18, 2023

    @wdanilo

    @ehuss Not this kind of relative path, sorry for not being clear enough here. In my case it was something along the lines of /some/absolute/path/.../.../../../some/other/file and it did not work until I run canonicalize on my PathBuf here. Could you tell me if that was enough for you to repro it, or should I try creating a minimal scene, please? :)

  12. ehuss commented on Feb 19, 2023

    @ehuss
    Contributor

    Yes, please create a minimal reproduction if you can. Also, please post it as a new issue (and cc me). Tracking issues are not a good way to discuss individual issues.

  13. usamoi commented on Mar 29, 2024

    @usamoi
    Contributor

    Can I imitate the behaviors of these two APIs by adding const _: Option<&str> = option_env!("tracked_env"); and const _: &str = include_bytes!("tracked_path"); to returned token streams? Is it guaranteed that the env and the path are tracked even if they do not really make a difference to the program?

  14. 27 remaining items

  15. hanna-kruppe commented on Oct 29, 2025

    @hanna-kruppe
    Contributor

    Make implementations (plural) are not the only consumers of dep-info files, though. For example, Cargo reads them, and Cargo generally doesn't support non-UTF-8 paths (e.g., rust-lang/cargo#6537). I've also written code parsing those files and guess what, that was using String too.

    There is no general, portable solution to what the so-called Makefile problem. It's nice that Rust has the option of supporting Path when only Path manipulation is needed, but as soon as a path is embedded into a larger text file, you're on thin ice at best.

  16. clarfonthey commented on Nov 20, 2025

    @clarfonthey
    Contributor

    I've been interested in this because built-in macros can automatically do this if you call, for example,
    include_str! or env!, so, I think it's reasonable to not require people to add a cargo build script just to mirror that functionality.

    The current crate I've been working on that I'd like to use this is include-pnm, although it currently doesn't use this functionality since it's not stable.

    (It also has its own problems because rust-analyzer's proc_macro server doesn't implement file or local_file, but that's separate from this issue entirely.)

  17. Skgland commented on Nov 27, 2025

    @Skgland
    Contributor

    It was brought up in #87173 (comment) that how relative paths work might not be intuitive. Passing the same path to proc_macro::tracked::path and std::fs::File::open/std::fs::read_dir might result in a different file/directory being opened than is being tracked.
    So would then make sense for proc_macro::tracked::path to return the absolute path that is being tracked by rustc so that it can then be used to correctly access the path?
    I think this could also help somewhat to ensure that a path is not used before its tracked i.e. prevent check if it exists and only track it if it does.

  18. clarfonthey commented on Nov 27, 2025

    @clarfonthey
    Contributor
    this is actually wrong, but leaving for posterity

    I would personally expect tracked::path to work based upon the current directory like File::open does, since the current directory for proc macros is the current directory of the source file in which the macro is called. So, for example, if you were to implement include_str! with a proc macro, you would want File::open on the string passed as an argument to load the file relative to the same source file, and tracked::path to also track that same file.

  19. Skgland commented on Nov 27, 2025

    @Skgland
    Contributor

    I would personally expect tracked::path to work based upon the current directory like File::open does, since the current directory for proc macros is the current directory of the source file in which the macro is called. So, for example, if you were to implement include_str! with a proc macro, you would want File::open on the string passed as an argument to load the file relative to the same source file, and tracked::path to also track that same file.

    Makes sense but also makes implementing include! like macros harder as I don't think it currently easy/possible for a proc_macro to determine the path that it should be relative to.

  20. clarfonthey commented on Nov 27, 2025

    @clarfonthey
    Contributor

    Actually, I was completely wrong so I'm going to just state what I actually did when implementing this:

    1. Span::call_site() gives you the span of the call site.
    2. span.local_file() gives you the path to the relevant source file.
    3. You can easily convert it into a path to any other file via path.pop() followed by path.push(file).

    Probably the simplest option semantically is to say that local_file always returns an absolute path, and thus, you need absolute paths for tracked::path. But it's not 100% clear whether we want that, because for example, what should tracked::path("/dev/stdin") do?

    As an aside, as I mentioned, rust-analyzer does not return anything via local_file (it returns Option, so, R-A just returns None), and I have to work around this to make things work. I think that we can currently ignore R-A here since I think in general folks will probably just need to do work around it like I have until they properly implement this API: just detect when None is returned and return something type-checking-but-wrong from the macro so R-A doesn't detect an error that the compiler doesn't.

  21. added a commit that references this issue on Dec 9, 2025
  22. Amanieu commented on Dec 9, 2025

    @Amanieu
    Member

    The issue of relative paths was discussed in the @rust-lang/libs-api meeting last week. There was a strong consensus that this path should be interpreted the same way as File::open, which is relative to the current working directory in which the proc macro process is executing.

  23. added a commit that references this issue on Dec 10, 2025
  24. added a commit that references this issue on Dec 23, 2025
  25. Skgland commented on Apr 7, 2026

    @Skgland
  26. Amanieu commented on Apr 7, 2026

    @Amanieu
    Member

    Thanks! I've updated the issue description.

  27. added
    T-libsRelevant to the library team, which will review and decide on the PR/issue.
    and removed
    T-libs-api[DEPRECATED; DO NOT USE]
    on Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-proc-macrosArea: Procedural macrosC-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions