diff --git a/README.md b/README.md index 8e2d9c59..0443e077 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,23 @@ llgo - A Go compiler based on LLVM [![GoDoc](https://pkg.go.dev/badge/github.com/goplus/llgo.svg)](https://pkg.go.dev/github.com/goplus/llgo) [![Language](https://img.shields.io/badge/language-Go+-blue.svg)](https://github.com/goplus/gop) -This is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem. It's a subproject of [the Go+ project](https://github.com/goplus/gop). +This is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a subproject of [the Go+ project](https://github.com/goplus/gop). ## C standard libary support -See [github.com/goplus/llgo/c](https://pkg.go.dev/github.com/goplus/llgo/c). +```go +package main + +import "github.com/goplus/llgo/c" + +func main() { + c.Printf(c.Str("Hello world\n")) +} +``` + +This is a simple example of calling the C `printf` function to print `Hello world`. Here, `c.Str` is not a function for converting a Go string to a C string, but a built-in instruction supported by llgo for generating a C string constant. + +See [github.com/goplus/llgo/c](https://pkg.go.dev/github.com/goplus/llgo/c) for more detials. ## Python support diff --git a/cl/compile.go b/cl/compile.go index 109126f4..62bdb0cb 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -486,7 +486,7 @@ func isPhi(i ssa.Instruction) bool { func (p *context) compilePhis(b llssa.Builder, block *ssa.BasicBlock) int { ret := p.fn.Block(block.Index) - b.SetBlock(ret) + b.SetBlockEx(ret, llssa.AtEnd) if ninstr := len(block.Instrs); ninstr > 0 { if isPhi(block.Instrs[0]) { n := 1 diff --git a/cl/compile_test.go b/cl/compile_test.go index 9430b561..6f417cbe 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -52,6 +52,10 @@ func TestFromTestpymath(t *testing.T) { cltest.Pkg(t, ssa.PkgPython+"/math", "../py/math/llgo_autogen.ll") } +func TestPython(t *testing.T) { + cltest.Pkg(t, ssa.PkgPython, "../py/llgo_autogen.ll") +} + func TestRuntime(t *testing.T) { cltest.Pkg(t, ssa.PkgRuntime, "../internal/runtime/llgo_autogen.ll") } diff --git a/internal/build/build.go b/internal/build/build.go index 38ccc5a8..898ea1c7 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -195,23 +195,26 @@ func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, ve // skip packages that only contain declarations // and set no export file pkg.ExportFile = "" - case cl.PkgLinkIR, cl.PkgPyModule: - // skip packages that don't need to be compiled but need to be linked + case cl.PkgLinkIR, cl.PkgLinkExtern, cl.PkgPyModule: pkgPath := pkg.PkgPath if isPkgInLLGo(pkgPath) { pkg.ExportFile = concatPkgLinkFiles(pkgPath) } else { panic("todo") } - case cl.PkgLinkExtern: - // skip packages that don't need to be compiled but need to be linked with external library - linkFile := os.ExpandEnv(strings.TrimSpace(param)) - dir, lib := filepath.Split(linkFile) - command := " -l " + lib - if dir != "" { - command += " -L " + dir + if kind == cl.PkgLinkExtern { // need to be linked with external library + linkFile := os.ExpandEnv(strings.TrimSpace(param)) + dir, lib := filepath.Split(linkFile) + command := " -l " + lib + if dir != "" { + command += " -L " + dir + } + if isMultiLinkFiles(pkg.ExportFile) { + pkg.ExportFile = command + pkg.ExportFile + } else { + pkg.ExportFile = command + " " + pkg.ExportFile + } } - pkg.ExportFile = command default: buildPkg(prog, aPkg, mode, verbose) setNeedRuntimeOrPyInit(pkg, prog.NeedRuntime(), prog.NeedPyInit()) diff --git a/internal/pyimport/pyimport.go b/internal/pyimport/pyimport.go deleted file mode 100644 index 72c23de7..00000000 --- a/internal/pyimport/pyimport.go +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package pyimport - -import ( - _ "unsafe" - - "github.com/goplus/llgo/c" - "github.com/goplus/llgo/py" -) - -const ( - LLGoPackage = "decl" -) - -/* -func init() { - py.Initialize() - py.SetProgramName(*c.Argv) -} -*/ - -//go:linkname Module C.PyImport_ImportModule -func Module(name *c.Char) *py.Module diff --git a/py/_demo/clpy/cleval.go b/py/_demo/clpy/cleval.go index 13f78b80..5b67bc1e 100644 --- a/py/_demo/clpy/cleval.go +++ b/py/_demo/clpy/cleval.go @@ -11,7 +11,7 @@ func main() { code := py.CompileString(c.Str(`print('Hello, World!')`), c.Str(`hello.py`), py.EvalInput) if code != nil { mod := py.ImportModule(c.Str("__main__")) - gbl := mod.GetDict() + gbl := mod.ModuleGetDict() result := py.EvalCode(code, gbl, nil) diff --git a/py/llgo_autogen.lla b/py/llgo_autogen.lla new file mode 100644 index 00000000..dd90aea6 Binary files /dev/null and b/py/llgo_autogen.lla differ diff --git a/py/module.go b/py/module.go index 8dddecbf..59e669c5 100644 --- a/py/module.go +++ b/py/module.go @@ -22,18 +22,13 @@ import ( "github.com/goplus/llgo/c" ) -// Module represents a Python module object. -type Module struct { - Object -} - // ----------------------------------------------------------------------------- // This is a wrapper around py.Import which takes a const char* as an argument // instead of an Object. // //go:linkname ImportModule C.PyImport_ImportModule -func ImportModule(name *c.Char) *Module +func ImportModule(name *c.Char) *Object // This is a higher-level interface that calls the current “import hook function” (with // an explicit level of 0, meaning absolute import). It invokes the __import__() function @@ -43,7 +38,7 @@ func ImportModule(name *c.Char) *Module // This function always uses absolute imports. // //go:linkname Import C.PyImport_Import -func Import(name *Object) *Module +func Import(name *Object) *Object // Return the dictionary object that implements module’s namespace; this object is the same // as the __dict__ attribute of the module object. If module is not a module object (or a @@ -52,7 +47,7 @@ func Import(name *Object) *Module // It is recommended extensions use other Module and Object functions rather than directly // manipulate a module’s __dict__. // -// llgo:link (*Module).GetDict C.PyModule_GetDict -func (m *Module) GetDict() *Object { return nil } +// llgo:link (*Object).ModuleGetDict C.PyModule_GetDict +func (m *Object) ModuleGetDict() *Object { return nil } // ----------------------------------------------------------------------------- diff --git a/py/object.go b/py/object.go index cb973653..6c3d3cc2 100644 --- a/py/object.go +++ b/py/object.go @@ -128,7 +128,7 @@ func (o *Object) CallFunctionObjArgs(__llgo_va_list ...any) *Object { return nil // llgo:link (*Object).CallMethod C.PyObject_CallMethod func (o *Object) CallMethod(name *c.Char, format *c.Char, __llgo_va_list ...any) *Object { - panic("unreachable") + return nil } // llgo:link (*Object).CallMethodObjArgs C.PyObject_CallMethodObjArgs