traefik / yaegi

Yaegi is Another Elegant Go Interpreter
https://pkg.go.dev/github.com/traefik/yaegi
Apache License 2.0
6.78k stars 341 forks source link

External packages still not working #1612

Open rive-n opened 4 months ago

rive-n commented 4 months ago

The following program sample.go triggers an unexpected result

https://github.com/traefik/yaegi/issues/671 ->

It's also possible to re-build an interpreter containing a pre-compiled library and its wrapper (generated by goexports), so the package can be imported without the overhead of interpretation, as it is done for the standard library packages in yaegi.

I've added external library into runtime using "import", generated extract file for yaegi, but, TL;DR it won't find the package which is already imported inside the runtime:

  1. Extract the deps: ./yaegi extract "github.com/google/uuid"
  2. Add dep into the golang runtime (for example, inside yaegi/cmd/yaegi.go:
    import (
    ...
    _ "github.com/google/uuid"
    )

    or

    
    import "github.com/google/uuid"

func main() {} ... _ = uuid.New() ...


^ at this point package will be already stored inside golang runtime which every golang binary has inside of itself. 

3. Recompile yaegi:

go build ./cmd/yaegi

4. Run `./yaegi` and observer that import forks fine
5. Replace `$GOROOT` or move the binary to other namespace/mounted volume without GOROOT and observe that p.4 is not working anymore

### Expected result

After compiler was rebuilt using the extracted package, `yaegi` should not search packages inside `GOROOT`:
i := interp.New(interp.Options{
    GoPath:       build.Default.GOPATH,
    BuildTags:    strings.Split(tags, ","),
    Env:          os.Environ(),
    Unrestricted: useUnrestricted,
})

Inside mounted namespace without "uuid" package:

/ # ./ya

import "github.com/google/uuid"

```

Got

Inside mounted namespace without "uuid" package:

/ # ./ya
> import "github.com/google/uuid"
1:21: import "github.com/google/uuid" error: unable to find source related to: "github.com/google/uuid"

Yaegi Version

./ya version: devel

Additional Notes

Maybe I am just confused by the doc itself and there is no legit way to hook something from the runtime itself or maybe I am just wrong with the implementation, but still it's not clear how can you import something external.

Basically, what I am trying to achieve is: Build an interpreter with the package X in it's runtime and after, use the binary with the package X inside it without package X being installed on the system (some sort of from memory loading)

theclapp commented 1 month ago

I_am_not_a_Yaegi_developer

I'm not sure how to do exactly what you want -- build a stand-alone program that includes arbitrary Go modules -- but I do have some advice. It boils down to "figure out what they did with the standard library and then do that."

First, build a non-stand-alone Go program that creates a Yaegi interpreter and uses the package successfully.

This would probably look something like this:

// Code generated by 'yaegi extract github.com/google/uuid'. DO NOT EDIT.

package _test

import (
    "github.com/google/uuid"
    "reflect"
)

func init() {
    Symbols["github.com/google/uuid/uuid"] = map[string]reflect.Value{
        // function, constant and variable definitions
        "ClockSequence":        reflect.ValueOf(uuid.ClockSequence),
// ...

And that should get you an interpreter that can use uuid variable/functions/types.

Arranging for all that to happen in a stand-alone executable is up to you.