Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make doctest compile / run cwd consistent with other test kinds #8993

Closed
Swatinem opened this issue Dec 17, 2020 · 20 comments · Fixed by #9105
Closed

Make doctest compile / run cwd consistent with other test kinds #8993

Swatinem opened this issue Dec 17, 2020 · 20 comments · Fixed by #9105
Labels
A-doctests Area: rustdoc --test C-bug Category: bug

Comments

@Swatinem
Copy link
Contributor

Swatinem commented Dec 17, 2020

In #8954 I changed the cwd that rustdoc itself is invoked to be similar to how rustc is invoked.

This is needed to get correct workspace-relative file paths, at least for -Z instrument-coverage purposes (rust-lang/rust#79417) (maybe also debuginfo, but I haven’t checked).

The problem is that this also changes the cwd in which the doctests themselves are executed, which is sadly a regression from stable :-(

CC @jan-auer @alexcrichton @richkadel maybe @jyn514

I have a small example here with unit, integration and doctests, running it with:

stable:

  • rustc --crate-name child --edition=2018 child/src/lib.rs […]
  • rustdoc --edition=2018 --crate-type lib --test /Users/swatinem/Coding/cargo-test-cwd/child/src/lib.rs […]

nightly:

  • rustc --crate-name child --edition=2018 child/src/lib.rs […]
  • rustdoc --edition=2018 --crate-type lib --crate-name child --test child/src/lib.rs […]

Full output below, but it shows that unit and integration tests are run with the crate directory as CWD, not the workspace, but the compiler itself is invoked from the workspace.
I think we need a way to tell rustdoc to use a specific cwd when running the doctests vs when compiling them.

`cargo +stable test --workspace --verbose -- --nocapture > stable.txt 2>&1`
   Compiling root v0.1.0 (/Users/swatinem/Coding/cargo-test-cwd)
   Compiling child v0.1.0 (/Users/swatinem/Coding/cargo-test-cwd/child)
     Running `rustc --crate-name root --edition=2018 src/lib.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 -C metadata=b9fe8482c61999e8 -C extra-filename=-b9fe8482c61999e8 --out-dir /Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C incremental=/Users/swatinem/Coding/cargo-test-cwd/target/debug/incremental -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C target-cpu=native`
     Running `rustc --crate-name child --edition=2018 child/src/lib.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 -C metadata=51b38cc0eeaf6f95 -C extra-filename=-51b38cc0eeaf6f95 --out-dir /Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C incremental=/Users/swatinem/Coding/cargo-test-cwd/target/debug/incremental -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C target-cpu=native`
     Running `rustc --crate-name root --edition=2018 src/lib.rs --error-format=json --json=diagnostic-rendered-ansi --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --test -C metadata=8d2e496c07b655ba -C extra-filename=-8d2e496c07b655ba --out-dir /Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C incremental=/Users/swatinem/Coding/cargo-test-cwd/target/debug/incremental -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C target-cpu=native`
     Running `rustc --crate-name child --edition=2018 child/src/lib.rs --error-format=json --json=diagnostic-rendered-ansi --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --test -C metadata=2c1e3a1656f1d0d3 -C extra-filename=-2c1e3a1656f1d0d3 --out-dir /Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C incremental=/Users/swatinem/Coding/cargo-test-cwd/target/debug/incremental -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C target-cpu=native`
     Running `rustc --crate-name integration --edition=2018 tests/integration.rs --error-format=json --json=diagnostic-rendered-ansi --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --test -C metadata=d55edb18df8de4ee -C extra-filename=-d55edb18df8de4ee --out-dir /Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C incremental=/Users/swatinem/Coding/cargo-test-cwd/target/debug/incremental -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps --extern root=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/libroot-b9fe8482c61999e8.rlib -C target-cpu=native`
     Running `rustc --crate-name integration --edition=2018 child/tests/integration.rs --error-format=json --json=diagnostic-rendered-ansi --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --test -C metadata=a20222878ab3a217 -C extra-filename=-a20222878ab3a217 --out-dir /Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C incremental=/Users/swatinem/Coding/cargo-test-cwd/target/debug/incremental -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps --extern child=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/libchild-51b38cc0eeaf6f95.rlib -C target-cpu=native`
    Finished test [unoptimized + debuginfo] target(s) in 1.19s
     Running `/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/child-2c1e3a1656f1d0d3 --nocapture`

running 1 test
unit test child: /Users/swatinem/Coding/cargo-test-cwd/child
test unit_cwd ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running `/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/integration-a20222878ab3a217 --nocapture`

running 1 test
integration test child: /Users/swatinem/Coding/cargo-test-cwd/child
test integration_cwd ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running `/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/root-8d2e496c07b655ba --nocapture`

running 1 test
unit test root: /Users/swatinem/Coding/cargo-test-cwd
test unit_cwd ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running `/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/integration-d55edb18df8de4ee --nocapture`

running 1 test
integration test root: /Users/swatinem/Coding/cargo-test-cwd
test integration_cwd ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests child
     Running `rustdoc --edition=2018 --crate-type lib --test /Users/swatinem/Coding/cargo-test-cwd/child/src/lib.rs --crate-name child -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps --test-args --nocapture --extern child=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/libchild-51b38cc0eeaf6f95.rlib -C embed-bitcode=no`

running 1 test
test src/lib.rs - (line 1) ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests root
     Running `rustdoc --edition=2018 --crate-type lib --test /Users/swatinem/Coding/cargo-test-cwd/src/lib.rs --crate-name root -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps --test-args --nocapture --extern root=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/libroot-b9fe8482c61999e8.rlib -C embed-bitcode=no`

running 1 test
test src/lib.rs - (line 1) ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

`cargo +nightly test --workspace --verbose -- --nocapture > nightly.txt 2>&1`
   Compiling root v0.1.0 (/Users/swatinem/Coding/cargo-test-cwd)
   Compiling child v0.1.0 (/Users/swatinem/Coding/cargo-test-cwd/child)
     Running `rustc --crate-name root --edition=2018 src/lib.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 -C metadata=763164469cdcead1 -C extra-filename=-763164469cdcead1 --out-dir /Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C incremental=/Users/swatinem/Coding/cargo-test-cwd/target/debug/incremental -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C target-cpu=native`
     Running `rustc --crate-name root --edition=2018 src/lib.rs --error-format=json --json=diagnostic-rendered-ansi --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --test -C metadata=9644a0ca393294d3 -C extra-filename=-9644a0ca393294d3 --out-dir /Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C incremental=/Users/swatinem/Coding/cargo-test-cwd/target/debug/incremental -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C target-cpu=native`
     Running `rustc --crate-name child --edition=2018 child/src/lib.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 -C metadata=3da7cb1692c9969f -C extra-filename=-3da7cb1692c9969f --out-dir /Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C incremental=/Users/swatinem/Coding/cargo-test-cwd/target/debug/incremental -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C target-cpu=native`
     Running `rustc --crate-name child --edition=2018 child/src/lib.rs --error-format=json --json=diagnostic-rendered-ansi --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --test -C metadata=b1c958d1677c12d4 -C extra-filename=-b1c958d1677c12d4 --out-dir /Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C incremental=/Users/swatinem/Coding/cargo-test-cwd/target/debug/incremental -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C target-cpu=native`
     Running `rustc --crate-name integration --edition=2018 tests/integration.rs --error-format=json --json=diagnostic-rendered-ansi --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --test -C metadata=3efdbdc44398e0ef -C extra-filename=-3efdbdc44398e0ef --out-dir /Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C incremental=/Users/swatinem/Coding/cargo-test-cwd/target/debug/incremental -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps --extern root=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/libroot-763164469cdcead1.rlib -C target-cpu=native`
     Running `rustc --crate-name integration --edition=2018 child/tests/integration.rs --error-format=json --json=diagnostic-rendered-ansi --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --test -C metadata=f9944916cab4691d -C extra-filename=-f9944916cab4691d --out-dir /Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -C incremental=/Users/swatinem/Coding/cargo-test-cwd/target/debug/incremental -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps --extern child=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/libchild-3da7cb1692c9969f.rlib -C target-cpu=native`
    Finished test [unoptimized + debuginfo] target(s) in 1.12s
     Running `/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/child-b1c958d1677c12d4 --nocapture`

running 1 test
unit test child: /Users/swatinem/Coding/cargo-test-cwd/child
test unit_cwd ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running `/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/integration-f9944916cab4691d --nocapture`

running 1 test
integration test child: /Users/swatinem/Coding/cargo-test-cwd/child
test integration_cwd ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running `/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/root-9644a0ca393294d3 --nocapture`

running 1 test
unit test root: /Users/swatinem/Coding/cargo-test-cwd
test unit_cwd ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running `/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/integration-3efdbdc44398e0ef --nocapture`

running 1 test
integration test root: /Users/swatinem/Coding/cargo-test-cwd
test integration_cwd ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests root
     Running `rustdoc --edition=2018 --crate-type lib --crate-name root --test src/lib.rs -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps --test-args --nocapture --extern root=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/libroot-763164469cdcead1.rlib -C embed-bitcode=no`

running 1 test
test src/lib.rs - (line 1) ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.25s

   Doc-tests child
     Running `rustdoc --edition=2018 --crate-type lib --crate-name child --test child/src/lib.rs -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps -L dependency=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps --test-args --nocapture --extern child=/Users/swatinem/Coding/cargo-test-cwd/target/debug/deps/libchild-3da7cb1692c9969f.rlib -C embed-bitcode=no`

running 1 test
test child/src/lib.rs - (line 1) ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.24s

@Swatinem Swatinem added the C-bug Category: bug label Dec 17, 2020
@Swatinem
Copy link
Contributor Author

I think @jan-auer and me were both very eager to create this, this is basically a duplicate of: #8992

Since one workaround for this is to use env!("CARGO_MANIFEST_DIR") inside the doctest, maybe that is something that rustdoc itself can use as the cwd when running the tests, does that sound like a good solution? @jyn514

bors added a commit that referenced this issue Dec 18, 2020
Revert #8954 - changing rustdoc's cwd

This PR reverts #8954 in reference to #8993 and #8992 where there's still definitely a bug to be fixed but we should probably avoid regressing in the meantime.

Closes #8992
@jyn514
Copy link
Member

jyn514 commented Dec 30, 2020

Can you explain why -Z instrument-coverage needs workspace relative paths, and why rustdoc behaves differently from rustc?

@Swatinem
Copy link
Contributor Author

Can you explain why -Z instrument-coverage needs workspace relative paths, and why rustdoc behaves differently from rustc?

I don’t know exactly why workspace relative paths are needed, just that the llvm-based tools need them to have proper coverage mappings.

For example when I run my testcases from https://github.com/Swatinem/fucov, I get the following lcov output:

SF:src\lib.rs
FN:1,_RNvNvCs4fqI2P2rA04_8rust_out4main28__doctest_main_src_lib_rs_1_0
FN:4,_RNvNvCs4fqI2P2rA04_8rust_out4main28__doctest_main_src_lib_rs_3_0
[…snip…]

Note however that the test on line 3 comes from crate-d, and there is a doctest on line 1 of crate-a, crate-b and crate-c, but those are not being destinguished.

When I switch the llvm tools to html output, I get the following:

error: src\lib.rs: no such file or directory
warning: The file 'src\lib.rs' isn't covered.
error: src\mod_with_file_doctest.rs: no such file or directory
warning: The file 'src\mod_with_file_doctest.rs' isn't covered.
error: src\somemod\mod.rs: no such file or directory
warning: The file 'src\somemod\mod.rs' isn't covered.
error: src\somemod\someothermod\mod.rs: no such file or directory
warning: The file 'src\somemod\someothermod\mod.rs' isn't covered.

Especially the src\lib.rs exists basically 4 times in the workspace, so the llvm tools have no idea whats going on.

Other test types are covered properly in the workspace setting, just not doctests.

@jyn514
Copy link
Member

jyn514 commented Dec 30, 2020

Ok, so basically rustdoc has always behaved differently from rustc and people depended on that fact? That's really unfortunate :/ I think doing this only when running the test would still run into the same issue: people could be opening relative file system paths at runtime, and that would break if you changed the working directory. I still think the best path forward is to figure out why LLVM depends on the current working directory and maybe tell it to use paths relative to the workspace instead.

@jan-auer
Copy link

I think the crucial detail is the difference between compiling and then running the doctest. For coverage, it is apparently required to have the doc tests compiled from the workspace root. I'm not that familiar with the LLVM tooling myself, but I'm assuming they are using DWARF's relative paths, which are always based on the "compilation directory", which is more-or-less the CWD of the compiler invocation. This is all defined at compile time.

Contrary to this, cargo already runs all other tests in the respective crate root, which may be a workspace member. That means, for unit and integration tests, there is already an expectation that by default relative file paths are always evaluated from Cargo.toml, and I think the same should hold for doc tests.

@Swatinem please correct me if I'm wrong in any of the above.

@jyn514
Copy link
Member

jyn514 commented Dec 31, 2020

Contrary to this, cargo already runs all other tests in the respective crate root, which may be a workspace member. That means, for unit and integration tests, there is already an expectation that by default relative file paths are always evaluated from Cargo.toml, and I think the same should hold for doc tests.

Sure, but that would be a breaking change. At the very least it would need an edition, but I'm still not convinced there's not a way to pass this information to LLVM in another way.

@Swatinem
Copy link
Contributor Author

I would propose to maybe add a new CLI flag to rustdoc that controls the runtime cwd, while keeping the current compile-time cwd behavior.
As the next step, re-land #8954 that uses this new flag to have a different compile-time and runtime cwd, making code-coverage happy without breaking current runtime cwd expectations.

Does that sound good? @jyn514

Also, I think @jan-auer is correct that the llvm tools probably use DWARF and similar debuginfo for all this. I haven’t looked at how this all works in detail, but that would at least explain why you need to provide all your compiled objects (executables) to the coverage tools.

@jyn514
Copy link
Member

jyn514 commented Dec 31, 2020

As the next step, re-land #8954 that uses this new flag to have a different compile-time and runtime cwd, making code-coverage happy without breaking current runtime cwd expectations.

If there's a way to do this so that changing the directory is opt-in and only happens when collecting coverage information, I would be ok with this. Otherwise, it's still a breaking change IMO.

@Swatinem
Copy link
Contributor Author

Otherwise, it's still a breaking change IMO.

Explain please.

Also, is all of this specified/documented somewhere how these things should behave?

@jyn514
Copy link
Member

jyn514 commented Dec 31, 2020

Explain please.

Previously, rustdoc would run tests in the crate directory, and the behavior of that was observable in doc tests (with std::fs, etc). After your proposed change, it will run in the workspace root, which could break doctests.

This is probably more on the T-cargo side than the T-rustdoc side, and if the cargo team is willing to make this change I'll defer to them, but I'm still concerned about the breaking change.

Also, is all of this specified/documented somewhere how these things should behave?

Probably not, one of the issues of rustdoc is that a lot of people depend on the implementation rather than the documented behavior; this is one of the reasons intra-doc links had to be stabilized, because even though they were unstable half the ecosystem was using them: rust-lang/rust#63305.

@Swatinem
Copy link
Contributor Author

After your proposed change, it will run in the workspace root, which could break doctests.

Thats why my original PR was reverted. My proposal would be to keep the current runtime behavior, while changing the compile-time cwd, specifically to not break this.

@Swatinem
Copy link
Contributor Author

btw, changing the compile-time cwd would probably be observable when using the unstable --persist-doctests flag, which is a requirement for code coverage anyway because you need the executables.

@richkadel
Copy link

@Swatinem is there a way to get the relative path from the workspace root to the doctest root via API, during the InstrumentCoverage MIR transform, like you get the line offset?

Unless I'm mistaken, nothing in the coverage map implementation really cares what the actual filename is during compile time.

What's important is that llvm-cov can find the files, so relative paths only depend on where llvm-cov is run from, and that should be the workspace root.

You could force absolute paths for doctests, but I think it's cleaner to just prepend the doctest root path with the path from workspace root to doctest root, the same way you offset the line numbers, for example:

    let start_line = source_map.doctest_offset_line(&source_file.name, start_line);
    let end_line = source_map.doctest_offset_line(&source_file.name, end_line);
    let file_name = source_map.doctest_offset_file_name(&source_file.name, file_name);
    CodeRegion {
        file_name,
        start_line: start_line as u32,
        start_col: start_col.to_u32() + 1,
        end_line: end_line as u32,
        end_col: end_col.to_u32() + 1,
    }

I don't think anything else needs to change.

Swatinem added a commit to Swatinem/cargo that referenced this issue Jan 2, 2021
To avoid regressions to the test runtime directory, this asserts that
all test types (unit, integration, doctest) are executed in the crate
(manifest) directory, no matter where that crate is in relation to the
workspace root.

See rust-lang#8992 / rust-lang#8993
bors added a commit that referenced this issue Jan 4, 2021
Assert that tests are run in the crate directory

To avoid regressions to the test runtime directory, this asserts that
all test types (unit, integration, doctest) are executed in the crate
(manifest) directory, no matter where that crate is in relation to the
workspace root.

See #8992 / #8993
@ehuss ehuss added the A-doctests Area: rustdoc --test label Jan 7, 2021
@Swatinem
Copy link
Contributor Author

Swatinem commented Jan 14, 2021

So after thinking very hard about the comment above and a discussion on zulip that we had, I still disagree with the proposed solutions here. Let me explain.

What issues / implications do we have:

  1. doctest cwd People want to write std::fs::read_to_string("tests/fixtures/file.txt").unwrap() into their doctests, just like they do with their unit tests. Breaking this is an absolute no-go.
  2. --persist-doctests filenames These are based on the relative path to the doctests and look like .../src_lib_rs_20_0/rust_out. However different rustdoc invocations can create files with the same name, essentially overwriting each other. I kind of fixed this in Fix persisted doctests on Windows / when using workspaces rust#79413 by just prefixing the name with the --crate-name, but reverted that again in Remap instrument-coverage line numbers in doctests rust#79762 anticipating a better solution. This was broken before, and it is still broken now.
  3. unique main function names Coverage (or rather, the llvm tools) needs unique function names, because otherwise they will overwrite each other. This actually uses the same logic as the --persist-doctests filenames, and this is broken now.
  4. coverage mappings Code coverage also works with filenames. Right now it just gets src/lib.rs and is confused because well, which one of your src/lib.rs files are you talking about in a workspace with multiple crates? This is broken now.
  5. libtest output When running doctests, the CLI output will list each one as for example test src/lib.rs - (line 3) ... ok. When scrolling through your console, developers might go "which src/lib.rs is rustdoc talking about?" Well yes, cargo will output a corresponding header that says which crate is being doc-tested. Arguably, there might be tools out there that parse the CLI output, however I doubt there are, and either way the stdout should not be considered stable. If not really a bug, I would call this an annoyance at least.

Proposal 1

Introduce a new --run-directory to rustdoc which controls the cwd of test executable invocations. No other changes in rustdoc are needed. Cargo can re-land #8954, of course taking care to provide that --run-directory.

  1. doctest cwd This is controlled explicitly and will not break.
  2. persisted filenames These will be fixed.
  3. unique main fn Fixed as well.
  4. coverage mappings Fixed.
  5. libtest stdout This will change, but IMO for the better. You will see at a glance which exact doctest/file is run. But yes, it is a behavior change.

Also this proposal is forward compatible if rustdoc better seperates the compile from the run step, and maybe hands the responsibility off to cargo.

Proposal 2

If I understand correctly, the proposal here is to pass a --workspace-directory to rustdoc, and do all kinds of internal re-mapping.

  1. doctest cwd No change here.
  2. persisted filenames These would have to be adjusted specifically.
  3. unique main fn These as well.
  4. coverage mappings Rustdoc calls rust out-of-process to compile the executable, and passes a UNSTABLE_RUSTDOC_TEST_PATH env var. That would need to be massaged in a way that the mapping is correct.
  5. libtest stdout No change here. Although the current output is confusing.

Conclusion

I really do think that proposal 1 would result in a simpler, more straight forward implementation and implicitly fix a few issues at once, while being more forward compatible.

@jyn514
Copy link
Member

jyn514 commented Jan 14, 2021

@Swatinem for proposal one, what happens if a doctest has include_str! in the test? Won't it be relative to a different directory after the CWD changes, and cause the test to break?

@richkadel
Copy link

@Swatinem - Thank you for the well thought out proposals. I'll defer to the more experienced compiler team members on what the best approach is.

One correction: With -Zinstrument-coverage, LLVM does not use debuginfo. (LLVM does have an alternative coverage implementation, enabled via rustc -Zprofile, that uses debuginfo.)

You should remove item 4 from your issues list.

@Swatinem
Copy link
Contributor Author

LLVM does not use debuginfo

so the profile counters use a different mechanism? Either way, it is something thats embedded in the produced executable, I will rename accordingly

@Swatinem
Copy link
Contributor Author

what happens if a doctest has include_str! in the test?

I will add a test for this. I think these are relative to the current file, but I will double check.

@Swatinem
Copy link
Contributor Author

@jyn514

what happens if a doctest has include_str! in the test?

Those are always relative to the current file, which seems to work fine for doctests as well.

ec000e6

I added a test which succeeds locally. I will commit that once I try to re-land my cargo changes.

@jyn514
Copy link
Member

jyn514 commented Jan 21, 2021

Ok, this seems good to me then.

Swatinem added a commit to Swatinem/rust that referenced this issue Jan 23, 2021
This option will allow splitting the compile-time from the run-time
directory of doctest invocations and is one step to solve
rust-lang/cargo#8993 (comment)
bors added a commit that referenced this issue Feb 23, 2021
Run rustdoc doctests relative to the workspace

By doing so, rustdoc will also emit workspace-relative filenames for the doctests.

This was first landed in #8954 but later backed out in #8996 because it changed the CWD of rustdoc test invocations.

The second try relies on the new `--test-run-directory` rustdoc option which was added in rust-lang/rust#81264 to explicitly control the rustdoc test cwd.

fixes #8993
@bors bors closed this as completed in b4c4028 Feb 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-doctests Area: rustdoc --test C-bug Category: bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants