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

How to include the generated header? #98

Closed
ales-tsurko opened this issue Apr 10, 2020 · 8 comments · Fixed by tonikasoft/fpsdk#5 or #116
Closed

How to include the generated header? #98

ales-tsurko opened this issue Apr 10, 2020 · 8 comments · Fixed by tonikasoft/fpsdk#5 or #116
Labels
integration How cxx fits into the big picture of an organization's codebase and builds

Comments

@ales-tsurko
Copy link

ales-tsurko commented Apr 10, 2020

Sorry if it's a duplicate, but I didn't find anything helpful.

I use cargo build script. I included the generated header using this path: target/cxxbridge/src/lib.rs.h. But during a clean build this header isn't there when a file with this include compiles.

In the example I see there's #include "demo-rs/src/main.rs.h" and it's magically works with cargo build. So I guess I skipped something important, which does this generating of header. But what?

@dtolnay
Copy link
Owner

dtolnay commented Apr 10, 2020

I really appreciate your help debugging this -- the Cargo-based workflow is not bulletproof yet, since in my work codebase I am using this crate with Buck so I haven't had a chance to hit all the ways that stuff could be going wrong in a Cargo build.

The way it's supposed to work is that we write out the header to the $OUT_DIR specified by Cargo, which for an input file path/to/file.rs will be something like target/debug/build/cratename-2e37674c6d57ef6d/out/path/to/file.rs.h. Then, since that hash is not stable so it's not something you can #include, we symlink that output file into a predictable place namely target/cxxbridge/path/to/file.rs.h. When calling cxx::Build::new() in the build script it puts target/cxxbridge on the include path which is what enables #include "path/to/file.rs.h".

It's been working nicely in our CI builds so far but any of the above things could be going wrong for you, possibly for everyone, or possibly only in Windows-specific ways.

Some things that would help debug further:

  • Ideally, would you be able to put together a minimal repro that I can just clone and cargo build and see if it also fails on my system?
  • If not:
    • Is there any Cargo [workspace] involved? I thought we've handled it, but it's possible that might be messing up something that expects the target directory in the wrong place.
    • Is the cc build that's failing the one you get from cxx::Build::new(), or some other cc::Build?
    • When you build and it fails to find lib.rs.h under target/cxxbridge, can you find out if there is a lib.rs.h anywhere under target/debug/build/*/out/**? If so, maybe it's only the symlinking that fails and that might need a Windows-specific fix.

@ales-tsurko
Copy link
Author

ales-tsurko commented Apr 10, 2020

I can confirm this on macOS and two Windows machines (one of them is a virtual one).

Ideally, would you be able to put together a minimal repro that I can just clone and cargo build and see if it also fails on my system?

Sure, here is the original repo.


When you said about using the variable.

The way it's supposed to work is that we write out the header to the $OUT_DIR specified by Cargo,

I guessed it may be related to another issue, which is related to this one:

rust-lang/rust#54216

Firstly I had the issue above. When I'd done as described in this comment, everything compiled, but I started to get:

error: failed to run custom build command for `fpsdk v0.1.0 (Z:\Desktop\fpsdk)`
Caused by:
  process didn't exit successfully: `C:/tmp/tttt\debug\build\fpsdk-b31a351da4183363\build-script-build` (exit code: 1)
--- stderr


cxxbridge error: failed to locate target dir

Switching to fully virtual environment did the trick.

This is a minor one and related only to a virtual machine environment, so I didn't open a ticket for this. Also on a normal Windows machine there's no this issue.

@ales-tsurko
Copy link
Author

I just checked it again and I can't reproduce it on macOS. But I still get it on Windows.

Also rust/cxx.h is in target/cxxbridge/, but src/ is empty. The header is generated and it's in $OUT_DIR.

It looks like the problem is in generating symlinks.

@ales-tsurko
Copy link
Author

ales-tsurko commented Apr 14, 2020

I tried to patch it locally and because of unix symlinks in the code base it didn't compile.

Then I changed the code base so that it worked without symlinks and not only the crate compiled, but also that's solved this issue - header is generated in the target/cxxbridge/src/ and I'm able to include it.

But you say it works for CI... Also there're no any errors except of the one described here related to symlinks in the code base, when I use the version from crates.io. And I actually don't understand why it works, because it looks like it shouldn't...

I can make a PR and either specify path attribute for modules which use symlinks to avoid using symlinks at all or create windows native symlinks with win suffix and use cfg_attr to use these links on windows.


It probably related to rust-lang/cargo#5664

@ales-tsurko
Copy link
Author

Never mind. This is because on pre-Windows 10 you can't create a symlink without admin privileges. You can create it on Windows 10, but after you enable Developer Mode... Damn it! 😄

@dtolnay
Copy link
Owner

dtolnay commented Apr 14, 2020

So it sounds like writing the generated file directly to target/cxxbridge/path/to/file.rs.h instead of in OUT_DIR, rather than writing a symlink, would fix this right?

@ales-tsurko
Copy link
Author

I think so yes. That should work.

@veeg
Copy link

veeg commented Jul 17, 2020

Then, since that hash is not stable so it's not something you can #include, we symlink that output file into a predictable place namely target/cxxbridge/path/to/file.rs.h. When calling cxx::Build::new() in the build script it puts target/cxxbridge on the include path which is what enables #include "path/to/file.rs.h".

This is indeed an issue with workspaces.
I have to insert this workaround to cc::Build in build.rs to handle the additional subdirectory for the package:

        ...
        // When compiling in a workspace, the target folder seemingly misses an additional
        // package subdirectory
        .include(format!(
            "{}/../../../../cxxbridge/PACKAGE-rs",
            std::env::var("OUT_DIR").unwrap()
        ))

Target tree:

$ tree target/cxxbridge 
target/cxxbridge
├── PACKAGE-rs
│   └── src
│       ├── ffi.rs ->symlink
│       └── ffi.rs.h -> symlink
└── rust
    └── cxx.h

@dtolnay dtolnay added the integration How cxx fits into the big picture of an organization's codebase and builds label Aug 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integration How cxx fits into the big picture of an organization's codebase and builds
Projects
None yet
3 participants