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

Platform generic transpilation #305

Open
chrysn opened this issue Sep 19, 2020 · 4 comments
Open

Platform generic transpilation #305

chrysn opened this issue Sep 19, 2020 · 4 comments
Labels
enhancement New feature or request

Comments

@chrysn
Copy link
Contributor

chrysn commented Sep 19, 2020

The FAQ are explicit about not supporting cross-transpilation, but I'd like to use that and work on fixing it (primarily to get rust-lang/rust-bindgen#1344 working); I'd appreciate a bit of high-level review before I get head-on into it.

According to the FAQ entry, the preprocessor is run first, and that's what's keeping transpilation from working. With the right flags supplied to the preprocessor, that should not be too much trouble. (After all, flags are already supplied for platform dependent stuff, like any defines the program may use to determine endianness and such).

Looks to me that the more difficult step will be getting the types right, ie. putting i32 or i64 where C has its int or long. The cty crate may be of some help there.

@chrysn
Copy link
Contributor Author

chrysn commented Sep 20, 2020

My initial experimentation on this indicates that working around the host preprocessor expansion might even be sufficient to transpile on generic platforms. Since I've started using a C compiler with the right target platform in -E mode to expand any defines and includes, all the non-matching sizes disappeared. That preprocessing goes down even into stdint.h, so C2Rust only sees native C types like "int" or "long", and defers to ::libc (or ::cty as I replace it, manually although I could merge in #297 and do it there).

The downside of this approach so far is that I'm using the actual platform C compiler and not clang with suitable flags -- which means that under some circumstances, GCC idiom winds up there and I get errors like "Type conversion not implemented for TagTypeUnknown expecting 3" (At least I think that's what's happening there).

Eventually, I think that if all arguments are passed around right (and I'm honestly not quite sure whether they aren't already), clang could work from the data already in compile_commands.json and produce output suitable for any platform, provided it's specified the right way in the compile commands.

@chrysn
Copy link
Contributor Author

chrysn commented Sep 21, 2020

Further experimentation has shown that expanding preprocessor is only really necessary when using a C compiler different from clang -- that then has its own path discovery, and eventually finds the platform-specific definitions for variously sized integers that clang does not find. Where clang is used, I see no real difference in the results between using preprocessed and original data. (Function sequence differs, and preprocessing loses the data C2Rust would need to --translate-const-macros).

Would it be correct to change the FAQ entry to

I translated code on platform X but it didn't work correctly on platform Y

We run the C preprocessor before translation to Rust. This specializes the code to the platform given in the compile_commands, defaulting to the host platform. For this reason, in order to cross-tanspile, the same platform must be selected during transpilation and compilation of the Rust code.

?

(That I'm using a non-clang C compiler is probably a niche problem for general C2Rust applications; most other projects probably just work with clang).

@ahomescu
Copy link
Contributor

To cross-compile with clang, you need at least the following:

  1. The correct compiler flags (and preprocessor flags, but those are not sufficient by themselves) for the target system, including -target <triple>.
  2. The path to the right sysroot for your cross-compilation target, which includes target-specific headers.
  3. A clang built with the cross-compilation target enabled.

For C2Rust, you get 1+2 above automatically from compile_commands.json. Since we use clang for our front-end, you just need to produce the compile_commands.json using a vanilla clang cross-compilation. Other compilers might work too, but we haven't tested any.

@chrysn
Copy link
Contributor Author

chrysn commented Sep 27, 2020

Those three I got, and they work for me. If there's really nothing more to it (and frankly it looks to me that way by now), I think the FAQ should be updated to say something different than "not supported at the moment".

Another suggestion for text (given I don't like the above that much any more):

I translated code on platform X but it didn't work correctly on platform Y

C2Rust can be in cross compilation, but the Rust code generated is already platform specific. (That is because it consumes platform specific definitions like typedef uint32_t unsigned int; in its processing). To cross compile, the eventually targeted platform must already be included in the compile_commands.json as -target <triple>, together with any sysroot or other paths and definitions that would be used for cross-compiling the C code using clang.

chrysn added a commit to RIOT-OS/rust-riot-sys that referenced this issue May 31, 2022
This ensures that the typedefs that lead to types like uint64_t are
aligned with the target code -- otherwise, odd expansions are pulled in
that lead to a uint64_t being defined as `unsigned long`. (Fortunately,
such errors show at compile time as RIOT bit-shifts such numbers by
hard-coded large sizes).

Workaround-For: immunant/c2rust#305
@kkysen kkysen added the enhancement New feature or request label Jun 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants