Is it possible to compile Motoko code directly to wasm file without conister ?
like if i would compile c/c++ code to wasm and call it from nodejs or other languages ?
Hi, you can explore using the standalone moc compiler:
https://sdk.dfinity.org/docs/language-guide/compiler-ref.html
To run it from the sdk install directory:
$(dfx cache show)/moc
You could also set an alias importing the base library:
alias moc="$(dfx cache show)/moc --package base $(dfx cache show)/base"
Then just pass it the .mo file, eg if you want to see your Debug.print() output you can use:
moc main.mo -r
Or to output a wasm file:
moc main.mo
i tried to call function add
i get this error :
(index):1 Uncaught (in promise) TypeError: WebAssembly.instantiate(): Import #0 module=āic0ā error: module is not an object or function
actor {
public func add(val1:Int,val2:Int):async Int{
return val1 + val2;
};
public func sub(val1:Int,val2:Int):async Int{
return val1 - val2;
};
};
here is javascript code:
function add(wasm){
const add = wasm.exports.add
console.log(add(2,2))
}
function wfadd(){
fetch("./src/main/main.wasm").then(response=>
response.arrayBuffer()
).then((bytes)=>
WebAssembly.instantiate(bytes,importObj)
).then(result=>
result.instance
).then(add)
}
wfadd()
Hmmm Iāve actually been using Rust or C++ for any in-browser Wasm myself, so Iām not sure of the workflow for Motoko, perhaps @claudio can help here? I know you can target other runtimes via WASI straight from moc.
Edit: The actor { } class isnāt needed for non-canister wasm output, so try removing that.
You can use the -wasi-system-api
flag on the compiler to make it emit WASI compatible code, but the only interface that is implemented is logging. Thatās good enough to write unit tests and run all kinds of pure synchronous Motoko in wasmtime, but I donāt think the browser engines implement WASI.
Check out the testing setup of the base
or the matchers
libraries for examples.
How does it work when I want to interpret the program only? The solution from @Ori seems to get me closer to what I want to achieve but does not quite work in the following simple case:
# test.mo
let x = 1;
x;
If I start motoko in the interpreter with ~/.cache/dfinity/versions/0.6.13/moc -i
, I can call x exactly in the way above:
Motoko compiler (revision czsashv5-30c3v29x-c1z1bswy-5zfr0s50)
> let x = 1;
let x : Nat = 1
> x;
1 : Nat
However, when it try to call the file with the -r option flag, no result is returned.
I tried both:
~/.cache/dfinity/versions/0.6.13/moc -r test.mo
and
~/.cache/dfinity/versions/0.6.13/moc test.mo -r
Moreover, I donāt quite catch how to import the Debug library. Does this work with the regular dfx setup or do I have to clone the motoko-base repo?
Ideally, I want to write small functions and test them as I write them with Coderunner.
Importing the Debug module is actually the answer:
test.mo
import Debug "mo:base/Debug";
let x = 1;
Debug.print(debug_show(x));
Then in the terminal:
alias moc="$(dfx cache show)/moc --package base $(dfx cache show)/base"
moc test.mo -r
This will output 1 as youāre expecting.
The --package flag in that alias assigns the base libraryās install directory to ābaseā, so you can then just import any base library module within your .mo files as above, eg import List "mo:base/List"
, the same way you do in the regular dfx/canister setup.
Thereās more reference on the base library modules here: https://sdk.dfinity.org/docs/base-libraries/stdlib-intro.html or you can just read through the base library files themselves, youāll find them in the install directory here: cd $(dfx cache show)/base
.
Thanks, Ori. That works.
One more edge case though is that I had to run dfx upgrade
and you guys are quite active . So the dfx cache show variable in the alias was pointing me to me installed version rather than to upgraded version. It also works with prepending the -r to the script. This is useful for the coderunner config. I find this quite interesting in my motoko journey and will make another icp.news blog article on this.
Thanks.
You can run dfx cache install
after upgrading to update that.
Older versions of the sdk will still remain in the $(dfx cache show)/..
directory when you upgrade, this lets you run canisters against older versions even after upgrading. In the canister environment youād be able to change your dfx.json file to do so.
Very neat! Thanks.