github.com/goplus/llgo@v0.8.3/internal/llgen/llgenf.go (about) 1 /* 2 * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package llgen 18 19 import ( 20 "go/types" 21 "os" 22 "os/exec" 23 "path/filepath" 24 "strings" 25 26 "github.com/goplus/llgo/cl" 27 "golang.org/x/tools/go/packages" 28 "golang.org/x/tools/go/ssa" 29 "golang.org/x/tools/go/ssa/ssautil" 30 31 llssa "github.com/goplus/llgo/ssa" 32 ) 33 34 const ( 35 loadFiles = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles 36 loadImports = loadFiles | packages.NeedImports 37 loadTypes = loadImports | packages.NeedTypes | packages.NeedTypesSizes 38 loadSyntax = loadTypes | packages.NeedSyntax | packages.NeedTypesInfo 39 ) 40 41 func initRtAndPy(prog llssa.Program, cfg *packages.Config) { 42 var pkgRtAndPy []*packages.Package 43 load := func() []*packages.Package { 44 if pkgRtAndPy == nil { 45 var err error 46 pkgRtAndPy, err = packages.Load(cfg, llssa.PkgRuntime, llssa.PkgPython) 47 check(err) 48 } 49 return pkgRtAndPy 50 } 51 52 prog.SetRuntime(func() *types.Package { 53 rt := load() 54 return rt[0].Types 55 }) 56 prog.SetPython(func() *types.Package { 57 rt := load() 58 return rt[1].Types 59 }) 60 } 61 62 func GenFrom(fileOrPkg string) string { 63 cfg := &packages.Config{ 64 Mode: loadSyntax | packages.NeedDeps, 65 } 66 initial, err := packages.Load(cfg, fileOrPkg) 67 check(err) 68 69 _, pkgs := ssautil.AllPackages(initial, ssa.SanityCheckFunctions) 70 71 pkg := initial[0] 72 ssaPkg := pkgs[0] 73 ssaPkg.Build() 74 75 prog := llssa.NewProgram(nil) 76 initRtAndPy(prog, cfg) 77 78 if Verbose { 79 ssaPkg.WriteTo(os.Stderr) 80 } 81 82 ret, err := cl.NewPackage(prog, ssaPkg, pkg.Syntax) 83 check(err) 84 85 if prog.NeedPyInit { // call PyInit if needed 86 ret.PyInit() 87 } 88 89 return ret.String() 90 } 91 92 func DoFile(fileOrPkg, outFile string) { 93 ret := GenFrom(fileOrPkg) 94 err := os.WriteFile(outFile, []byte(ret), 0644) 95 check(err) 96 } 97 98 func SmartDoFile(inFile string, pkgPath ...string) { 99 const autgenFile = "llgo_autogen.ll" 100 dir, _ := filepath.Split(inFile) 101 absDir, _ := filepath.Abs(dir) 102 absDir = filepath.ToSlash(absDir) 103 fname := autgenFile 104 if inCompilerDir(absDir) { 105 fname = "out.ll" 106 } 107 outFile := dir + fname 108 109 if len(pkgPath) > 0 { 110 Do(pkgPath[0], inFile, outFile) 111 } else { 112 DoFile(inFile, outFile) 113 } 114 if false && fname == autgenFile { 115 genZip(absDir, "llgo_autogen.lla", autgenFile) 116 } 117 } 118 119 func genZip(dir string, outFile, inFile string) { 120 cmd := exec.Command("zip", outFile, inFile) 121 cmd.Dir = dir 122 cmd.Stdout = os.Stdout 123 cmd.Stderr = os.Stderr 124 cmd.Run() 125 } 126 127 func inCompilerDir(dir string) bool { 128 return strings.Contains(dir, "/llgo/cl/") 129 }