r-wasm / rwasm

Build R packages for WebAssembly and create a CRAN-like repo for distribution.
https://r-wasm.github.io/rwasm/
Other
56 stars 4 forks source link

[Rust] set CC and CFLAGS envvars #18

Open yutannihilation opened 9 months ago

yutannihilation commented 9 months ago

(This issue is mainly for sharing the information, so feel free to close. But I hope this helps somehow.)

Probably you already know, the Rust compiler sometimes invokes the C compiler inside.

https://doc.rust-lang.org/cargo/reference/build-scripts.html

rwasm overrides the CC and CFLAGS Makevars, but I found these settings are not propagated to the C compiler unless the same name of envvars are set.

https://github.com/rust-lang/cc-rs#external-configuration-via-environment-variables

I'm not sure if this is what rwasm should take care of or the package author should, but I actually had to specify it in my package, which compiles a bit of C code in the crate.

https://github.com/yutannihilation/savvy-webr-test/commit/5ee66d793e9036a1e6bcdbe11c876cee63b00d04

georgestagg commented 9 months ago

A great find, thank you for sharing! I think we should take care of this in rwasm if we can.

We could tweak webr-vars.mk to export some of the make variables so that they're available in the environment with changes such as,

- CC = emcc
- CXX = em++
- FC = $(EMFC)
- CFLAGS = $(WASM_CFLAGS)
- CPPFLAGS = $(WASM_CPPFLAGS)
- CXXFLAGS = -std=gnu++11 $(WASM_CXXFLAGS)
+ export CC = emcc
+ export CXX = em++
+ export FC = $(EMFC)
+ export CFLAGS = $(WASM_CFLAGS)
+ export CPPFLAGS = $(WASM_CPPFLAGS)
+ export CXXFLAGS = -std=gnu++11 $(WASM_CXXFLAGS)

With this, Rust should pick up the emcc compiler without package authors having to add CC=$(CC) manually.

One thing I am not sure about is how this change could potentially affect other R packages. I can think of a situation where this might break things: if some package is building an executable as an intermediate step, then running it on the host machine to generate some further output to be included in the package. I don't actually know if any R packages work like that - @jeroen, can you think of any? Or think of any other issues with simply exporting these variables to the build environment?

Either way, I suppose any packages doing something like that could be made to use the compiler given in HOST_CC by a configure step instead:

$ emconfigure env | grep CC
CC=/Users/georgestagg/emsdk/upstream/emscripten/emcc
HOST_CC=/Users/georgestagg/emsdk/upstream/bin/clang
yutannihilation commented 9 months ago

Sounds great!

To be fair, the use of Rust is not majority and probably only few of them invokes C compiler. So, it might not be really worth the risk. At the moment, we anyway need to use Makevars.webr for overriding settings, so it might be reasonable to leave it for the author to specify it.

Also, to be precise, CC=$(CC) might not be strictly necessary. It seems choosing the wasm32-unknown-emscripten target determines the C compiler is emcc. (But, since I couldn't figured out the mechanism, I specify CC for safety).

georgestagg commented 9 months ago

At the moment, we anyway need to use Makevars.webr for overriding settings

We shim uname in rwasm to return "Emscripten" when cross-compiling, so you might be able to combine things into a single Makevars by testing for that:

UNAME := $(shell uname -s)
ifeq ($(UNAME),Emscripten)
    [...]
endif
yutannihilation commented 9 months ago

Oh, good to know, thanks.

yutannihilation commented 9 months ago

FYI, I chose to use configure instead of relying on ifeq GNU make extension. I'm not sure how it's meaningful, but it seems it's the preference of the CRAN maintainers to avoid extensions for the maximum portability. YMMV.

https://github.com/yutannihilation/savvy-webr-test/commit/257f8fbb20da472797cb6a05cf2e1bb42a12a742

jeroen commented 9 months ago

One thing I am not sure about is how this change could potentially affect other R packages. I can think of a situation where this might break things: if some package is building an executable as an intermediate step, then running it on the host machine to generate some further output to be included in the package. I don't actually know if any R packages work like that - @jeroen, can you think of any?

The maps package is one example.