Build LLVM from Rust for machine type wasm32 - rust

I'm trying to build a hobby project where I build a Rust file to WebAssembly. I want to pass more options to emscripten then Rustc and cargo seem to allow me (like MINIMAL_RUNTIME, ENVIRONMENT and INVOKE_RUN).
I had the 'brilliant' idea of compiling Rust to llvm, then feeding that llvm file to emscripten so that I can use the compiler options. However, when I try to build the WebAssembly, I get the error "machine type must be wasm32".
This is the file I'm trying to build:
fn main() {
println!("Hello World!");
}
And this is how I'm trying to build it:
rustc --emit=llvm-ir test.rs
emcc test.ll -O0 -s WASM=1
Any idea what I'm doing wrong? (Or another way I can achieve my goal?)

Duh, I needed to add a target option:
rustc --emit=llvm-ir --target wasm32-unknown-unknown test.rs
emcc test.ll -O0 -s WASM=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0
Of course, this leaves me with "Unknown symbol" errors now... -sigh-
EDIT: Actually, what I should be doing is using the -C flag on rustc to directly pass paramaters to emcc, which is what I wanted to do in the first place:
rustc --target wasm32-unknown-unknown -C link-arg="-s MINIMAL_RUNTIME=1" -C link-arg="-s INVOKE_RUN=0" test.rs

Related

How to add custom llvm pass into rustc

I am trying to add my llvm pass into Rustc. Rustc has one compiling option -C passes=val where we could add extra LLVM passes to run. However, as my try, this option can only accept the pass when the pass code is placed inside the LLVM code tree, but I want to add my pass out-of-tree into Rustc.
When I add my pass via this option:
RUSTFLAGS="-C passes=my-pass" cargo build
Compiler reports errors:
error: failed to run LLVM passes: unknown pass name 'my-pass'
Then I try to load my pass via -C llvm-args=-fpass-plugin=/opt/new-pass/mypass.so -C passes=my-pass in the clang way. It reports: rustc -Cllvm-args="..." with: Unknown command line argument '-fpass-plugin=/opt/new-pass/mypass.so'. Also tried to replace -fpass-plugin with other options like -load and -load-pass-plugin, but they still cannot be recognized by rustc.
How could I add my custom pass into Rustc?
I was trying to find a solution to this exact problem too. According to a rust developer on their Zulip Chat, it looks like you need to build a custom rustc with plugin support.

Is it possible to run a single rust file as a script while linking to other libraries without generating cargo projects

I'd like to run a one off rust "script" without going through creating a cargo project for a single run (since I am providing this script to colleagues).
Ideally I could build directly with the command line avoiding creating cargo projects etc.
for instance:
use serde_json::Value;
use some_private_packege_i_own_locally_in_another_directory;
fn main() {
// do some stuff with these packages and die
}
I would need to depend on the serde_json and my some_private_packege_i_own_locally_in_another_directory.
(A bit similar to rust playground I suppose for a single time use)
Something similar to this from the command line would be great:
rustc /path/to/main.rs --dependency serde_json, my_package ...
You can specify a dependency with with extern flag, and you can specify the location of transitive dependencies, with -L dependency. You will have to compile each dependency, and all of it's dependencies manually:
// compile all of serde's dependencies
// compile all of hyper's dependencies
// compile serde
// compile hyper
rustc script.rs --crate-type bin -L dependency=~/tmp/deps --extern serde_json=~/tmp/deps/serde_json.rlib --extern hyper=~/tmp/deps/hyper.rlib
As you can tell, this would get very difficult, even with two direct dependencies. Instead, you can use cargo-script, which handles all of this for you:
cargo install cargo-script
cargo script -D hyper -D serde_json script.rs

How can you compile a Rust library to target asm.js?

I've got a Rust library with the following usual structure:
Cargo.toml
src
|--lib.rs
.cargo
|--config (specifies target=asmjs-unknown-emscripten)
target
|......
When I do cargo build, I get a new directory under target called asmjs-unknown-emscripten, but the .js files that I'd expect are not there.
As this user notes, you've got to do something special to export functions to asm.js besides marking them public:
Basically you have this boilerplate right now:
#[link_args = "-s EXPORTED_FUNCTIONS=['_hello_world']"]
extern {}
fn main() {}
#[no_mangle]
pub extern fn hello_world(n: c_int) -> c_int {
n + 1
}
Then you can use this in your javascript to access and call the function:
var hello_world = cwrap('hello_world', 'number', ['number']);
console.log(hello_world(41));
However, Rust complains about the #[link_args...] directive as deprecated. Is there any documentation out there that can explain how this works?
Very interesting question! I was running into similar dependency issues with fable.
I have checked Compiling Rust to your Browser - Call from JavaScript, Advanced Linking - Link args and How to pass cargo linker args however was not able to use cargo in the same way as rustc --target asmjs-unknown-emscripten call-into-lib.rs.
The closer I was able to get was to run both cargo and rustc like
cd lib1
cargo build --target asmjs-unknown-emscripten
rustc --target=asmjs-unknown-emscripten src\lib.rs
cd ..
cd lib2
cargo build --target asmjs-unknown-emscripten
rustc --target=asmjs-unknown-emscripten src\lib.rs --extern lib1=..\lib1\target\asmjs-unknown-emscripten\debug\liblib1.rlib
cd ..
cd lib3
cargo build --target asmjs-unknown-emscripten
rem rustc --target=asmjs-unknown-emscripten src\lib.rs --extern webplatform=..\lib3\target\asmjs-unknown-emscripten\debug\deps\libwebplatform-80d107ece17b262d.rlib
rem the line above fails with "error[E0460]: found possibly newer version of crate `libc` which `webplatform` depends on"
cd ..
cd app
cargo build --target asmjs-unknown-emscripten
cd ..
see the so-41492672-rust-js-structure. It allows to have several libraries that compile together to the JavaScript in the final application.
I still think some manual linking would help. Would be interested to know.
P.S. to see what rustc uses to link, you can pass -Z print-link-args to it.

How to emit LLVM-IR from Cargo

How can I get cargo to emit LLVM-IR instead of a binary for my project? I know that you can use the --emit=llvm-ir flag in rustc, but I've read some Github issues that show it's impossible to pass arbitrary compiler flags to cargo.
Is there any way I can get cargo to emit LLVM-IR directly?
There is cargo rustc to pass arbitrary compiler flags through Cargo to rustc. So I think:
cargo rustc -- --emit=llvm-ir
is what you want!
This will genarate a ll file in target\debug\deps\.
EDIT: You should use Jacob's answer instead; a lot easier and less hacky.
Build the project with cargo normally but add on the -v flag to show verbose output. The command will have a result like this:
casey#casey-ubuntu:~/Documents/project$ cargo build -v
Fresh aster v0.22.1
Fresh num-traits v0.1.34
Fresh itoa v0.1.1
...
Compiling project v0.1.0 (file:///home/casey/Documents/project)
Running `rustc src/main.rs --crate-name ...`
Finished debug [unoptimized + debuginfo] target(s) in 3.54 secs
If the command produces no output, make a change somewhere in your project code to trick the compiler into rebuilding it, since it will only rebuild if it detects a change in one of the files.
Copy the rustc command from inside the ` markers on the line starting with "Running `rustc..." and append --emit=llvm-ir to it.
This will produce a .ll file in your /target/debug folder.

failure to build rust-libc using cargo when rustc is musl-enabled

I successfully created a musl configured rustc by following this link
My attempt to build a project (which builds fine using non-musl configured rust) failed when I used cargo rustc -- --target=x86_64-unknown-linux-musl
'error: could not find crate `libc` with expected target triple x86_64-unknown-linux-musl'
Then, I tried to create rust-libc library using the code from crate. To be more accurate, I used the command provided by cargo to build rust-libc, I've only added --target=x86_64-unknown-linux-musl to the command. This time it failed reporting:
'error: could not find native static library `c`, perhaps an -L flag is missing?`'
I have two questions:
Is it mandatory to build musl configured cargo to be able to use cargo build --target=x86_64-unknown-linux-musl?
How can I address this:
'error: could not find native static library `c`, perhaps an -L flag is missing?'
This worked for me to build libc:
rustc --target=x86_64-unknown-linux-musl /address-of-libc/lib.rs --crate-name libc --crate-type lib -L /address-of-musldist/musldist/lib/ --out-dir=/your-chosen-address/target --cfg feature=\"default\" --cfg feature=\"cargo-build\" --emit=dep-info,link

Resources