Open leighmcculloch opened 2 years ago
same issue
Related issue: https://github.com/tinygo-org/tinygo/issues/2735
One of the more curious causes of support is that when you compile with the wasi
target and don't have a main function, it defaults to assuming you want to import your own from the "env" module as "main.main".
I'm not sure the rationale of this assumption, or if it was an oversight. In any case, I think the right behavior is to remove it as an instantiation bomb and instead backfill a no-op main. A flag could be raised if anyone is actually importing "main.main" to allow it, or use the normal //export
thing to do that.
wdyt?
The title of this issue might be better if it described the use case. What calls the non-main module? How is it linked together?
currently, for lack of a standalone
target, people use wasi
to export functions in WebAssembly. The host uses those functions directly, passing parameters, as opposed to indirectly via a _start
.
For context, in zig, this is freestanding
and rust, cdylib
. The main request is to stop support cases where people have to remember to add main
and have confusing errors if not.
I should also mention that even when some export uses uses WASI (ex. indirectly via fmt.Println), I believe it is better to have a default to backfill main vs have everyone remember to add something like..
// main is required for TinyGo to compile to Wasm.
func main() {}
What calls the non-main module? How is it linked together?
A wasm runtime that doesn't call the start function, but calls other functions in the complied wasm.
My use case is to be able to build wasm programs to be deployed on @stellar, and so I'm more interested in the freestanding target, i.e. no WASI.
As @codefromthecrypt pointed out Rust and Zig both have good support for this use case.
Other use cases might be applications that use wasm as a plugin system that don't plan to call start.
However, given that this works in all these cases by providing an empty main function maybe this isn't important to address. It's mostly a first time bad experience and then once you know how it works you can move on.
the trouble with this is when the init code should be executed. If the initAll code is called in all the export functions. this may be a problem when linking modules in runtime(like wasmtime), and could lead to repeated calls to initAll code. go does not support dynamic linking usage.
i am not sure how wasmtime hand call to another module export function, if each module have diferent exec environment, could add a flag to check if have exected init code before. but if all module running in one environment, maybe have difficulty. need more dig for wasmtime.
per @jzabinski-dolios on https://github.com/tinygo-org/tinygo/issues/2495#issuecomment-1018576022, we should include this feedback in any eventual outcome here.
Should the lack of a func main() in the source file result in a compiler error?
Yes. It did in the past, but apparently this got removed at some point. This would be fixed by removing --allow-undefined.
Plus I think we should have an outcome shortly as this is one topic that causes quite a lot of support load.
One of the more curious causes of support is that when you compile with the
wasi
target and don't have a main function, it defaults to assuming you want to import your own from the "env" module as "main.main".I'm not sure the rationale of this assumption, or if it was an oversight.
It was an oversight. The change in #3133 will make this a linker error instead of a runtime error, which is already a lot better.
I suggest simply creating an empty main
function.
so this issue was requesting to build a non-main package (ex one not named main), and then there was a second topic which is that if you name it main, you had no feedback you missed adding a boilerplate main function.
Now, the latter is solved "good enough" imho:
$ ~/oss/tinygo/build/tinygo build -target=wasi -o main.wasm main.go
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2841776377/main.o: undefined symbol: main.main
failed to run tool: wasm-ld
error: failed to link /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2841776377/main: exit status 1
At least it doesn't silently pass anymore, and I think it is reasonable to expect someone to figure out main function was missing. from the symbol: main.main
part.
What I'm hearing is that for the first part, to allow building non-main packages (ex ones that don't want to have main in them, like library packages), that this is a won't fix for the wasi
target, even if another target such as freestanding
might. Am I understanding right @aykevl? If so, I'd recommend closing this and we can refer back to it and close any new issues as dupes when they arise.
Otherwise, this is a "not yet" and I expect that means help wanted, right?
Non-main packages are not something the Go language supports:
Program execution
A complete program is created by linking a single, unimported package called the main package with all the packages it imports, transitively. The main package must have package name main and declare a function main that takes no arguments and returns no value.
func main() { … }
Program execution begins by initializing the main package and then invoking the function main. When that function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.
So, while we could support it, note that it is non-standard. It would make a lot more sense to me to simply require users to use a main package.
Non-main packages are not something the Go language supports:
In that case keeping the requirement on it being a main package makes sense, and instead lifting the requirement on there being a main function to call.
This would be the same as for how Go plugins behave:
A plugin is a Go main package with exported functions and variables that has been built with:
go build -buildmode=plugin
When a plugin is first opened, the init functions of all packages not already part of the program are called. The main function is not run.
I've updated the issue title to reflect the above.
Maybe this is something for the docs?
Once implemented in tinygo, perhaps.
I will be interested to see if this is how the https://github.com/WebAssembly/component-model camel gets its nose into the tinygo tent, or vice versa.
Same issue here, it has been a lot time since the last comment, there are news about this?
I have this use case where I need to export go functions with the //export
directive in a non-main package
package non_main
//export add
func add(a, b int) {
return a + b
}
tinygo version
command output:
tinygo version 0.32.0 linux/amd64 (using go version go1.22.4 and LLVM version 18.1.6)
Output after building previous package:
$ tinygo build -target wasm -o a.wasm
panic: expected main package to have name 'main'
As @leighmcculloch cites, tinygo could support -buildmode
flag with a value like package
or other better descriptive name, allowing building a package and not running a main function, just exporting symbols
my solution is use a empty main function and export function in main package, after build process the wasm file. insert a call instruction to invoke __start
function before each export function, this operation is for invoke initAll function. this export function can work correctly.
I would like to contribute to solve this issue, it doesn't seem like there is an active branch related to this. So I will proceed to create a development fork.
my solution is use a empty main function and export function in main package, after build process the wasm file. insert a call instruction to invoke
__start
function before each export function, this operation is for invoke initAll function. this export function can work correctly.
For reactor programs that export functions, the runtime should be initialized in _initialize.
I tried building with tinygo a simple non-main package with no dependencies with the intention of using it with wasm standalone in wasm3 or wasmer and it errored with: