External packages still not working
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:
- Extract the deps:
./yaegi extract "github.com/google/uuid" - 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.
- Recompile yaegi:
go build ./cmd/yaegi
- Run
./yaegiand observer that import forks fine - Replace
$GOROOTor 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)
#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 extracton the external package to build a symbol table for all exported symbols in the package. This generated code updates aSymbolsvariable 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
Symbolsvariable of typeinterp.Exportsin that file's package. (Depending on where you ranyaegi extract, you may need to manually update thepackagedeclaration in the generated file. By default,extractspecifies a packaged based on your $PWD when you runyaegi extract.) - Import the package, e.g.
import "github.com/you/your_app/path/to/your_package" - Create an interpreter, e.g.
i := interp.New(...) UsetheSymbolsgenerated byextract, 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.