Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

External packages still not working #1612

Open
rive-n opened this issue Feb 29, 2024 · 1 comment
Open

External packages still not working #1612

rive-n opened this issue Feb 29, 2024 · 1 comment

Comments

@rive-n
Copy link

rive-n commented Feb 29, 2024

The following program sample.go triggers an unexpected result

#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.

  1. Recompile yaegi:
go build ./cmd/yaegi
  1. Run ./yaegi and observer that import forks fine
  2. 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"
<uuid_import_addr_val>

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
Copy link
Contributor

#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:

  • Use yaegi extract on the external package to build a symbol table for all exported symbols in the package. This generated code updates a Symbols variable assumed to already exist in whatever package the file is in. It looks 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),
// ...
  • Include the file generated above in your program source tree. Create a Symbols variable of type interp.Exports in that file's package. (Depending on where you ran yaegi extract, you may need to manually update the package declaration in the generated file. By default, extract specifies a packaged based on your $PWD when you run yaegi extract.)
  • Import the package, e.g. import "github.com/you/your_app/path/to/your_package"
  • Create an interpreter, e.g. i := interp.New(...)
  • Use the Symbols generated by extract, e.g. i.Use(your_package.Symbols)
  • call ImportUsed(), e.g. i.ImportUsed()
  • Import the package inside the interpreter, e.g. i.Eval("import \"github.com/google/uuid\"")

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants