From 7b2e08e491cee8bc886e6481ceae012bbb216df3 Mon Sep 17 00:00:00 2001 From: Haolan Date: Tue, 1 Apr 2025 23:02:30 +0800 Subject: [PATCH 01/17] feat: support llpkg --- compiler/internal/build/build.go | 80 +++++- compiler/internal/installer/config.go | 27 ++ compiler/internal/installer/config/parse.go | 33 +++ .../githubreleases/githubreleases.go | 272 ++++++++++++++++++ .../githubreleases/githubreleases_test.go | 124 ++++++++ compiler/internal/installer/installer.go | 15 + compiler/internal/mod/mod.go | 70 ++++- compiler/internal/pc/env.go | 19 ++ 8 files changed, 634 insertions(+), 6 deletions(-) create mode 100644 compiler/internal/installer/config.go create mode 100644 compiler/internal/installer/config/parse.go create mode 100644 compiler/internal/installer/githubreleases/githubreleases.go create mode 100644 compiler/internal/installer/githubreleases/githubreleases_test.go create mode 100644 compiler/internal/installer/installer.go create mode 100644 compiler/internal/pc/env.go diff --git a/compiler/internal/build/build.go b/compiler/internal/build/build.go index 75f2617deb..41e46552b5 100644 --- a/compiler/internal/build/build.go +++ b/compiler/internal/build/build.go @@ -34,12 +34,17 @@ import ( "strings" "unsafe" + "golang.org/x/mod/module" "golang.org/x/tools/go/ssa" "github.com/goplus/llgo/compiler/cl" "github.com/goplus/llgo/compiler/internal/env" + "github.com/goplus/llgo/compiler/internal/installer" + "github.com/goplus/llgo/compiler/internal/installer/githubreleases" "github.com/goplus/llgo/compiler/internal/mockable" + "github.com/goplus/llgo/compiler/internal/mod" "github.com/goplus/llgo/compiler/internal/packages" + "github.com/goplus/llgo/compiler/internal/pc" "github.com/goplus/llgo/compiler/internal/typepatch" "github.com/goplus/llgo/compiler/ssa/abi" xenv "github.com/goplus/llgo/xtool/env" @@ -62,6 +67,9 @@ const ( ) const ( + defaultLLPkgOwner = "goplus" + defaultLLPkgRepo = "llpkg" + debugBuild = packages.DebugPackagesLoad ) @@ -112,6 +120,15 @@ func DefaultAppExt() string { return "" } +func defaultInstaller() installer.Installer { + return githubreleases.NewGHReleasesInstaller(map[string]string{ + "owner": defaultLLPkgOwner, + "repo": defaultLLPkgRepo, + "platform": runtime.GOOS, + "arch": runtime.GOARCH, + }) +} + // ----------------------------------------------------------------------------- const ( @@ -215,8 +232,10 @@ func Do(args []string, conf *Config) ([]Package, error) { env := llvm.New("") os.Setenv("PATH", env.BinDir()+":"+os.Getenv("PATH")) // TODO(xsw): check windows + installer := defaultInstaller() + output := conf.OutFile != "" - ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool)} + ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool), installer} pkgs, err := buildAllPkgs(ctx, initial, verbose) check(err) if mode == ModeGen { @@ -281,6 +300,61 @@ type context struct { needRt map[*packages.Package]bool needPyInit map[*packages.Package]bool + + installer installer.Installer +} + +func getModule(ctx *context, ver module.Version, llpkg installer.Package, verbose bool) error { + cmd := exec.Command("llgo", "get", ver.String()) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return err + } + + dir, err := mod.LLPkgCacheDirByModule(ver) + if err != nil { + return err + } + if err = os.MkdirAll(dir, 0777); err != nil { + return err + } + + if verbose { + fmt.Printf("installing %s to %s", ver.String(), dir) + + } + if _, err = ctx.installer.Install(llpkg, dir); err != nil { + return err + } + + pkgConfigPath := filepath.Join(dir, "lib", "pkgconfig") + + // too many command, hard to use temporary environment + os.Setenv("PKG_CONFIG_PATH", pc.AppendPCPath(pkgConfigPath)) + + return nil +} + +func buildLLPkg(ctx *context, pkg *packages.Package, verbose bool) (err error) { + // a standard lib, skip + if pkg.Module == nil { + return + } + ver := module.Version{ + Path: pkg.Module.Path, + Version: pkg.Module.Version, + } + llpkg, err := mod.ParseLLPkg(ver) + if err != nil { + // this is just not a llpkg, not an error + err = nil + return + } + + err = getModule(ctx, ver, llpkg, verbose) + + return } func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs []*aPackage, err error) { @@ -302,6 +376,10 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs continue } built[pkg.ID] = none{} + + err := buildLLPkg(ctx, pkg, verbose) + check(err) + switch kind, param := cl.PkgKindOf(pkg.Types); kind { case cl.PkgDeclOnly: // skip packages that only contain declarations diff --git a/compiler/internal/installer/config.go b/compiler/internal/installer/config.go new file mode 100644 index 0000000000..e7c1308a6a --- /dev/null +++ b/compiler/internal/installer/config.go @@ -0,0 +1,27 @@ +package installer + +// LLPkgConfig represents the configuration structure parsed from llpkg.cfg files. +type LLPkgConfig struct { + Upstream UpstreamConfig `json:"upstream"` +} + +// UpstreamConfig defines the upstream configuration containing installer settings and package metadata. +type UpstreamConfig struct { + Installer InstallerConfig `json:"installer"` + Package Package `json:"package"` +} + +// InstallerConfig specifies the installer type and its configuration options. +// "name" field must match supported installers (e.g., "conan"). +// "config" holds installer-specific parameters (optional). +type InstallerConfig struct { + Name string `json:"name"` + Config map[string]string `json:"config,omitempty"` +} + +// Package defines the metadata required to identify and install a software library. +// The Name and Version fields provide precise identification of the library. +type Package struct { + Name string + Version string +} diff --git a/compiler/internal/installer/config/parse.go b/compiler/internal/installer/config/parse.go new file mode 100644 index 0000000000..0a549ff439 --- /dev/null +++ b/compiler/internal/installer/config/parse.go @@ -0,0 +1,33 @@ +package config + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/goplus/llgo/compiler/internal/installer" +) + +// ParseLLPkgConfig reads and parses the llpkg.cfg configuration file +// Performs the following operations: +// +// 1. Opens and reads the configuration file. +// 2. Deserializes JSON content into LLPkgConfig struct. +// 3. Applies default values for missing parameters. +// 4. Returns parsed config or I/O/decoding errors. +func ParseLLPkgConfig(configPath string) (installer.LLPkgConfig, error) { + var config installer.LLPkgConfig + file, err := os.Open(configPath) + if err != nil { + return config, fmt.Errorf("failed to open config file: %w", err) + } + defer file.Close() + + decoder := json.NewDecoder(file) + err = decoder.Decode(&config) + if err != nil { + return config, fmt.Errorf("failed to decode config file: %w", err) + } + + return config, nil +} diff --git a/compiler/internal/installer/githubreleases/githubreleases.go b/compiler/internal/installer/githubreleases/githubreleases.go new file mode 100644 index 0000000000..735a860d60 --- /dev/null +++ b/compiler/internal/installer/githubreleases/githubreleases.go @@ -0,0 +1,272 @@ +package githubreleases + +import ( + "archive/tar" + "archive/zip" + "bytes" + "compress/gzip" + "errors" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "strings" + "text/template" + + "github.com/goplus/llgo/compiler/internal/installer" +) + +var ErrPackageNotFound = errors.New("package not found") + +// ghReleasesInstaller implements the installer.Installer interface by downloading +// the corresponding package from a GitHub release. +type ghReleasesInstaller struct { + config map[string]string +} + +// NewGHReleasesInstaller creates a new GitHub Release installer with the specified configuration. +// The config map is the info of release repo, for example: +// "owner": `goplus`, +// "repo": `llpkg`, +// "platform": runtime.GOOS, +// "arch": runtime.GOARCH, +func NewGHReleasesInstaller(config map[string]string) installer.Installer { + return &ghReleasesInstaller{ + config: config, + } +} + +func (c *ghReleasesInstaller) Name() string { + return "ghreleases" +} + +func (c *ghReleasesInstaller) Config() map[string]string { + return c.config +} + +// Install downloads the package from the GitHub Release and extracts it to the output directory. +// Unlike conaninstaller which is used for GitHub Action to obtain binary files +// this installer is used for `llgo get` to install binary files. +// The first return value is an empty string, as the pkgConfigName is not necessary for this GitHub Release installer. +func (c *ghReleasesInstaller) Install(pkg installer.Package, outputDir string) ([]string, error) { + compressPath, err := c.download(c.assertUrl(pkg), outputDir) + if err != nil { + return nil, err + } + if strings.HasSuffix(compressPath, ".tar.gz") { + err = c.untargz(outputDir, compressPath) + if err != nil { + return nil, err + } + } else if strings.HasSuffix(compressPath, ".zip") { + err = c.unzip(outputDir, compressPath) + if err != nil { + return nil, err + } + } else { + return nil, errors.New("unsupported compressed file format") + } + err = os.Remove(compressPath) + if err != nil { + return nil, fmt.Errorf("cannot delete compressed file: %w", err) + } + err = c.setPrefix(outputDir) + if err != nil { + return nil, fmt.Errorf("fail to reset .pc prefix: %w", err) + } + return nil, nil +} + +// Warning: not implemented +// Search is unnecessary for this installer +func (c *ghReleasesInstaller) Search(pkg installer.Package) ([]string, error) { + return nil, errors.New("unimplemented") +} + +// assertUrl returns the URL for the specified package. +// The URL is constructed based on the package name, version, and the installer configuration. +func (c *ghReleasesInstaller) assertUrl(pkg installer.Package) string { + releaseName := fmt.Sprintf("%s/%s", pkg.Name, pkg.Version) + fileName := fmt.Sprintf("%s_%s.zip", pkg.Name, c.config["platform"]+"_"+c.config["arch"]) + return fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/%s", c.config["owner"], c.config["repo"], releaseName, fileName) +} + +// download fetches the package from the specified URL and saves it to the output directory. +func (c *ghReleasesInstaller) download(url string, outputDir string) (string, error) { + client := &http.Client{} + resp, err := client.Get(url) + if err != nil { + return "", err + } + defer resp.Body.Close() + if resp.StatusCode == http.StatusNotFound { + return "", ErrPackageNotFound + } + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } + + parts := strings.Split(url, "/") + filename := parts[len(parts)-1] + + err = os.MkdirAll(outputDir, 0755) + if err != nil { + return "", err + } + + outputPath := filepath.Join(outputDir, filename) + outFile, err := os.Create(outputPath) + if err != nil { + return "", err + } + defer outFile.Close() + + _, err = io.Copy(outFile, resp.Body) + if err != nil { + return "", err + } + + return outputPath, nil +} + +// untargz extracts the gzip-compressed tarball to the output directory. +// The gzipPath must be a .tar.gz file. +func (c *ghReleasesInstaller) untargz(outputDir string, gzipPath string) error { + fr, err := os.Open(gzipPath) + if err != nil { + return err + } + defer fr.Close() + + gr, err := gzip.NewReader(fr) + if err != nil { + return err + } + defer gr.Close() + + tr := tar.NewReader(gr) + for { + header, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + return err + } + + path := filepath.Join(outputDir, header.Name) + info := header.FileInfo() + + if info.IsDir() { + if err = os.MkdirAll(path, info.Mode()); err != nil { + return err + } + continue + } + dir := filepath.Dir(path) + if err = os.MkdirAll(dir, 0755); err != nil { + return err + } + file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode()) + if err != nil { + return err + } + if _, err = io.Copy(file, tr); err != nil { + return err + } + file.Close() + } + return nil +} + +// unzip extracts the zip file to the output directory. +// The zipPath must be a .zip file. +func (c *ghReleasesInstaller) unzip(outputDir string, zipPath string) error { + r, err := zip.OpenReader(zipPath) + if err != nil { + return err + } + defer r.Close() + decompress := func(file *zip.File) error { + path := filepath.Join(outputDir, file.Name) + + if file.FileInfo().IsDir() { + if err := os.MkdirAll(path, 0755); err != nil { + return err + } + return nil + } + fs, err := file.Open() + if err != nil { + return err + } + w, err := os.Create(path) + if err != nil { + return err + } + defer fs.Close() + if _, err := io.Copy(w, fs); err != nil { + w.Close() + return err + } + return w.Close() + } + + for _, file := range r.File { + if err = decompress(file); err != nil { + break + } + } + return err +} + +// setPrefix can generate .pc files from .pc.tmpl files +func (c *ghReleasesInstaller) setPrefix(outputDir string) error { + absOutputDir, err := filepath.Abs(outputDir) + if err != nil { + return err + } + + // move to path where .pc files are stored + pkgConfigPath := filepath.Join(outputDir, "lib", "pkgconfig") + + pcTmpls, err := filepath.Glob(filepath.Join(pkgConfigPath, "*.pc.tmpl")) + if err != nil { + return err + } + if len(pcTmpls) == 0 { + return errors.New("no .pc.tmpl files found") + } + for _, pcTmpl := range pcTmpls { + tmplContent, err := os.ReadFile(pcTmpl) + if err != nil { + return err + } + tmplName := filepath.Base(pcTmpl) + tmpl, err := template.New(tmplName).Parse(string(tmplContent)) + if err != nil { + return err + } + + pcFilePath := filepath.Join(pkgConfigPath, strings.TrimSuffix(tmplName, ".tmpl")) + var buf bytes.Buffer + // The Prefix field specifies the absolute path to the output directory, + // which is used to replace placeholders in the .pc template files. + if err := tmpl.Execute(&buf, map[string]any{ + "Prefix": absOutputDir, + }); err != nil { + return err + } + if err := os.WriteFile(pcFilePath, buf.Bytes(), 0644); err != nil { + return err + } + // remove .pc.tmpl file + err = os.Remove(filepath.Join(pkgConfigPath, tmplName)) + if err != nil { + return fmt.Errorf("failed to remove template file: %w", err) + } + } + + return nil +} diff --git a/compiler/internal/installer/githubreleases/githubreleases_test.go b/compiler/internal/installer/githubreleases/githubreleases_test.go new file mode 100644 index 0000000000..69d5f04b86 --- /dev/null +++ b/compiler/internal/installer/githubreleases/githubreleases_test.go @@ -0,0 +1,124 @@ +package githubreleases + +import ( + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "strings" + "testing" + + "github.com/goplus/llgo/compiler/internal/installer" + "github.com/goplus/llgo/compiler/internal/pc" +) + +func TestGHInstaller(t *testing.T) { + ghr := &ghReleasesInstaller{ + config: map[string]string{ + "owner": `MeteorsLiu`, + "repo": `llpkg`, + "platform": runtime.GOOS, + "arch": runtime.GOARCH, + }, + } + + pkg := installer.Package{ + Version: `v1.0.0`, + Name: `libxml2`, + } + + tempDir, err := os.MkdirTemp("", "llpkg-tool") + if err != nil { + t.Errorf("Unexpected error when creating temp dir: %s", err) + return + } + defer os.RemoveAll(tempDir) + + if _, err = ghr.Install(pkg, tempDir); err != nil { + t.Errorf("Install failed: %s", err) + } + + if err := verify(tempDir); err != nil { + t.Errorf("Verify failed: %s", err) + } +} + +func TestNotExistsReleases(t *testing.T) { + ghr := &ghReleasesInstaller{ + config: map[string]string{ + "owner": `goplus`, + "repo": `llpkg`, + "platform": runtime.GOOS, + "arch": runtime.GOARCH, + }, + } + + pkg := installer.Package{ + Version: `v1.0.0`, + Name: `not-exists-pkg`, + } + + tempDir, err := os.MkdirTemp("", "llpkg-tool") + if err != nil { + t.Errorf("Unexpected error when creating temp dir: %s", err) + return + } + defer os.RemoveAll(tempDir) + + if _, err = ghr.Install(pkg, tempDir); err == nil { + t.Errorf("Expecting error but got nil") + } +} + +func verify(installDir string) error { + // 1. ensure .pc file exists + pcFiles, err := filepath.Glob(filepath.Join(installDir, "lib", "pkgconfig", "*.pc")) + if err != nil { + return err + } + if len(pcFiles) == 0 { + return errors.New("cannot find .pc file") + } + absPath, err := filepath.Abs(installDir) + if err != nil { + return err + } + + for _, pcFile := range pcFiles { + // 2. ensure .pc file's prefix is correctly set + pcContent, err := os.ReadFile(pcFile) + if err != nil { + return err + } + prefixMatch := regexp.MustCompile(`^prefix=(.*)`) + if prefixMatch.FindString(string(pcContent)) != fmt.Sprintf("prefix=%s", absPath) { + return errors.New("prefix is not correctly set") + } + // 3. ensure pkg-config can find .pc file + buildCmd := exec.Command("pkg-config", "--libs", strings.TrimSuffix(filepath.Base(pcFile), ".pc")) + pc.SetPath(buildCmd, absPath) + out, err := buildCmd.CombinedOutput() + if err != nil { + return errors.New("pkg-config failed: " + err.Error() + " with output: " + string(out)) + } + } + + // 4. ensure .so or .dylib file exists + switch runtime.GOOS { + case "linux": + matches, _ := filepath.Glob(filepath.Join(installDir, "lib", "*.so")) + if len(matches) == 0 { + return errors.New("cannot find so file") + } + case "darwin": + matches, _ := filepath.Glob(filepath.Join(installDir, "lib", "*.dylib")) + if len(matches) == 0 { + return errors.New("cannot find dylib file") + } + } + + return nil +} diff --git a/compiler/internal/installer/installer.go b/compiler/internal/installer/installer.go new file mode 100644 index 0000000000..37d159a12f --- /dev/null +++ b/compiler/internal/installer/installer.go @@ -0,0 +1,15 @@ +package installer + +// Installer represents a package installer that can download, install, and locate binaries from a remote repository. +// It provides methods to install packages to specific directories and search for installed package information. +type Installer interface { + Name() string + Config() map[string]string + // Install downloads and installs the specified package. + // The outputDir is where build artifacts (e.g., .pc files, headers) are stored. + // Returns an error if installation fails, all the pkgConfigFiles if success. + Install(pkg Package, outputDir string) (pkgConfigFiles []string, err error) + // Search checks remote repository for the specified package availability. + // Returns the search results text and any encountered errors. + Search(pkg Package) ([]string, error) +} diff --git a/compiler/internal/mod/mod.go b/compiler/internal/mod/mod.go index 5327a2adc3..307f97347f 100644 --- a/compiler/internal/mod/mod.go +++ b/compiler/internal/mod/mod.go @@ -2,12 +2,37 @@ package mod import ( "fmt" + "path/filepath" + "sync" "github.com/goplus/llgo/compiler/internal/env" + "github.com/goplus/llgo/compiler/internal/installer" + "github.com/goplus/llgo/compiler/internal/installer/config" + "github.com/goplus/mod/modcache" "golang.org/x/mod/module" "golang.org/x/mod/semver" ) +var ( + globalMetadataMgrMu sync.Mutex + globalMetadataMgr *metadataMgr +) + +func metadata() *metadataMgr { + globalMetadataMgrMu.Lock() + defer globalMetadataMgrMu.Unlock() + + if globalMetadataMgr != nil { + return globalMetadataMgr + } + var err error + globalMetadataMgr, err = NewMetadataMgr(env.LLGOCACHE()) // build a metadata manager for version query + if err != nil { + fmt.Println(err) + } + return globalMetadataMgr +} + const ( LLPkgConfigFileName = "llpkg.cfg" GoModFileName = "go.mod" @@ -27,11 +52,8 @@ func NewModuleVersionPair(name, version string) (module.Version, error) { if !IsModulePath(name) { // 1. Convert cversion to the latest semantic version by version mappings - metadataMgr, err := NewMetadataMgr(env.LLGOCACHE()) // build a metadata manager for version query - if err != nil { - return module.Version{}, err - } - version, err = metadataMgr.LatestGoVerFromCVer(name, version) + metadataMgr := metadata() + version, err := metadataMgr.LatestGoVerFromCVer(name, version) if err != nil { return module.Version{}, err } @@ -46,6 +68,44 @@ func NewModuleVersionPair(name, version string) (module.Version, error) { return module.Version{Path: name, Version: version}, nil } +func LLPkgCfgFilePath(mod module.Version) (string, error) { + cachePath, err := modcache.Path(mod) + if err != nil { + return "", err + } + + return filepath.Join(cachePath, LLPkgConfigFileName), nil +} + +func LLPkgCacheDirByModule(mod module.Version) (string, error) { + encPath, err := module.EscapePath(mod.Path) + if err != nil { + return "", err + } + + return filepath.Join(LLPkgCacheDir(), encPath+"@"+mod.Version), nil +} + +func LLPkgCacheDir() string { + return filepath.Join(env.LLGOCACHE(), "llpkg") +} + +func ParseLLPkg(mod module.Version) (installer.Package, error) { + cfgPath, err := LLPkgCfgFilePath(mod) + if err != nil { + return installer.Package{}, err + } + + cfg, err := config.ParseLLPkgConfig(cfgPath) + if err != nil { + return installer.Package{}, err + } + return installer.Package{ + Name: cfg.Upstream.Package.Name, + Version: mod.Version, + }, nil +} + // Returns true if the path is a valid module path, false otherwise func IsModulePath(path string) bool { err := module.CheckPath(path) diff --git a/compiler/internal/pc/env.go b/compiler/internal/pc/env.go new file mode 100644 index 0000000000..f2f4ec16fc --- /dev/null +++ b/compiler/internal/pc/env.go @@ -0,0 +1,19 @@ +package pc + +import ( + "fmt" + "os" + "os/exec" +) + +func AppendPCPath(path string) string { + if env, ok := os.LookupEnv("PKG_CONFIG_PATH"); ok { + return path + ":" + env + } + return path +} + +func SetPath(cmd *exec.Cmd, path string) { + pcPath := fmt.Sprintf("PKG_CONFIG_PATH=%s", AppendPCPath(path)) + cmd.Env = append(os.Environ(), pcPath) +} From a50b17ca438451ba127a95f2d7f758b2893c0f16 Mon Sep 17 00:00:00 2001 From: Haolan Date: Tue, 1 Apr 2025 23:13:07 +0800 Subject: [PATCH 02/17] fix: skip installing --- compiler/internal/build/build.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/compiler/internal/build/build.go b/compiler/internal/build/build.go index 41e46552b5..2e39a7e59d 100644 --- a/compiler/internal/build/build.go +++ b/compiler/internal/build/build.go @@ -316,16 +316,18 @@ func getModule(ctx *context, ver module.Version, llpkg installer.Package, verbos if err != nil { return err } - if err = os.MkdirAll(dir, 0777); err != nil { - return err - } - if verbose { - fmt.Printf("installing %s to %s", ver.String(), dir) - - } - if _, err = ctx.installer.Install(llpkg, dir); err != nil { - return err + _, err = os.Stat(dir) + if os.IsNotExist(err) { + if err = os.MkdirAll(dir, 0777); err != nil { + return err + } + if verbose { + fmt.Printf("installing %s to %s", ver.String(), dir) + } + if _, err = ctx.installer.Install(llpkg, dir); err != nil { + return err + } } pkgConfigPath := filepath.Join(dir, "lib", "pkgconfig") From f419f468ccf3e72136e6997ee4501d8ad40a786c Mon Sep 17 00:00:00 2001 From: Meteor Date: Wed, 2 Apr 2025 09:07:46 +0000 Subject: [PATCH 03/17] fix: use Visit to resolve llpkg deps --- compiler/internal/build/build.go | 79 ++++++++++++++++---------------- compiler/internal/mod/cache.go | 3 ++ 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/compiler/internal/build/build.go b/compiler/internal/build/build.go index 2e39a7e59d..6aeb714075 100644 --- a/compiler/internal/build/build.go +++ b/compiler/internal/build/build.go @@ -304,59 +304,60 @@ type context struct { installer installer.Installer } -func getModule(ctx *context, ver module.Version, llpkg installer.Package, verbose bool) error { - cmd := exec.Command("llgo", "get", ver.String()) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return err - } - +func getModule(ctx *context, ver module.Version, llpkg installer.Package, verbose bool) (string, error) { dir, err := mod.LLPkgCacheDirByModule(ver) if err != nil { - return err + return "", err } _, err = os.Stat(dir) if os.IsNotExist(err) { - if err = os.MkdirAll(dir, 0777); err != nil { - return err - } if verbose { - fmt.Printf("installing %s to %s", ver.String(), dir) + fmt.Printf("installing %s to %s\n", ver.String(), dir) + } + if err = os.MkdirAll(dir, 0777); err != nil { + return "", err } if _, err = ctx.installer.Install(llpkg, dir); err != nil { - return err + return "", err } } - pkgConfigPath := filepath.Join(dir, "lib", "pkgconfig") + return filepath.Join(dir, "lib", "pkgconfig"), nil +} - // too many command, hard to use temporary environment - os.Setenv("PKG_CONFIG_PATH", pc.AppendPCPath(pkgConfigPath)) +func buildAllLLPkg(ctx *context, pkg []*packages.Package, verbose bool) { + installed := map[string]none{} + var pcDir []string + packages.Visit(pkg, nil, func(p *packages.Package) { + // a standard lib, skip + if p.Module == nil { + return + } + ver := module.Version{ + Path: p.Module.Path, + Version: p.Module.Version, + } + if _, ok := installed[ver.String()]; ok { + return + } + installed[ver.String()] = none{} - return nil -} + llpkg, err := mod.ParseLLPkg(ver) + if err != nil { + // not an llpkg, skip. + return + } -func buildLLPkg(ctx *context, pkg *packages.Package, verbose bool) (err error) { - // a standard lib, skip - if pkg.Module == nil { - return - } - ver := module.Version{ - Path: pkg.Module.Path, - Version: pkg.Module.Version, - } - llpkg, err := mod.ParseLLPkg(ver) - if err != nil { - // this is just not a llpkg, not an error - err = nil - return - } + dir, err := getModule(ctx, ver, llpkg, verbose) + check(err) - err = getModule(ctx, ver, llpkg, verbose) + pcDir = append(pcDir, dir) + }) - return + if len(pcDir) > 0 { + os.Setenv("PKG_CONFIG_PATH", pc.AppendPCPath(strings.Join(pcDir, ":"))) + } } func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs []*aPackage, err error) { @@ -370,6 +371,9 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs if len(errPkgs) > 0 { return nil, fmt.Errorf("cannot build SSA for packages") } + + buildAllLLPkg(ctx, initial, verbose) + built := ctx.built for _, aPkg := range pkgs { pkg := aPkg.Package @@ -379,9 +383,6 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs } built[pkg.ID] = none{} - err := buildLLPkg(ctx, pkg, verbose) - check(err) - switch kind, param := cl.PkgKindOf(pkg.Types); kind { case cl.PkgDeclOnly: // skip packages that only contain declarations diff --git a/compiler/internal/mod/cache.go b/compiler/internal/mod/cache.go index b7a3020a7f..619ea64852 100644 --- a/compiler/internal/mod/cache.go +++ b/compiler/internal/mod/cache.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "io" + "log" "net/http" "os" "path/filepath" @@ -65,6 +66,7 @@ func (c *cache[T]) fetch() error { } if !c.modTime.IsZero() { req.Header.Set("If-Modified-Since", c.modTime.Format(http.TimeFormat)) + log.Println(req.Header.Get("If-Modified-Since")) } resp, err := http.DefaultClient.Do(req) if err != nil { @@ -74,6 +76,7 @@ func (c *cache[T]) fetch() error { switch resp.StatusCode { case http.StatusNotModified: + log.Println("not") return nil case http.StatusOK: // Read and parse the response body From d4adc946e03522675333b23856367e6096b46509 Mon Sep 17 00:00:00 2001 From: Meteor Date: Wed, 2 Apr 2025 09:09:06 +0000 Subject: [PATCH 04/17] fix: remove log --- compiler/internal/mod/cache.go | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/internal/mod/cache.go b/compiler/internal/mod/cache.go index 619ea64852..15a609ee02 100644 --- a/compiler/internal/mod/cache.go +++ b/compiler/internal/mod/cache.go @@ -76,7 +76,6 @@ func (c *cache[T]) fetch() error { switch resp.StatusCode { case http.StatusNotModified: - log.Println("not") return nil case http.StatusOK: // Read and parse the response body From 95900cfe110e74a31bdc10fa14484a8d23553c08 Mon Sep 17 00:00:00 2001 From: Meteor Date: Wed, 2 Apr 2025 09:10:11 +0000 Subject: [PATCH 05/17] fix: remove log --- compiler/internal/mod/cache.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/internal/mod/cache.go b/compiler/internal/mod/cache.go index 15a609ee02..b7a3020a7f 100644 --- a/compiler/internal/mod/cache.go +++ b/compiler/internal/mod/cache.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "io" - "log" "net/http" "os" "path/filepath" @@ -66,7 +65,6 @@ func (c *cache[T]) fetch() error { } if !c.modTime.IsZero() { req.Header.Set("If-Modified-Since", c.modTime.Format(http.TimeFormat)) - log.Println(req.Header.Get("If-Modified-Since")) } resp, err := http.DefaultClient.Do(req) if err != nil { From 6ecd02c1dc8b84f2469b6b54e4a2b3c3fcb28820 Mon Sep 17 00:00:00 2001 From: Haolan Date: Wed, 2 Apr 2025 17:47:30 +0800 Subject: [PATCH 06/17] revert --- compiler/internal/build/build.go | 9 +++++---- compiler/internal/mod/mod.go | 26 ++++---------------------- 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/compiler/internal/build/build.go b/compiler/internal/build/build.go index 6aeb714075..c445fedf66 100644 --- a/compiler/internal/build/build.go +++ b/compiler/internal/build/build.go @@ -334,14 +334,15 @@ func buildAllLLPkg(ctx *context, pkg []*packages.Package, verbose bool) { if p.Module == nil { return } + if _, ok := installed[p.PkgPath]; ok { + return + } + installed[p.PkgPath] = none{} + ver := module.Version{ Path: p.Module.Path, Version: p.Module.Version, } - if _, ok := installed[ver.String()]; ok { - return - } - installed[ver.String()] = none{} llpkg, err := mod.ParseLLPkg(ver) if err != nil { diff --git a/compiler/internal/mod/mod.go b/compiler/internal/mod/mod.go index 307f97347f..f619dee0ac 100644 --- a/compiler/internal/mod/mod.go +++ b/compiler/internal/mod/mod.go @@ -3,7 +3,6 @@ package mod import ( "fmt" "path/filepath" - "sync" "github.com/goplus/llgo/compiler/internal/env" "github.com/goplus/llgo/compiler/internal/installer" @@ -13,26 +12,6 @@ import ( "golang.org/x/mod/semver" ) -var ( - globalMetadataMgrMu sync.Mutex - globalMetadataMgr *metadataMgr -) - -func metadata() *metadataMgr { - globalMetadataMgrMu.Lock() - defer globalMetadataMgrMu.Unlock() - - if globalMetadataMgr != nil { - return globalMetadataMgr - } - var err error - globalMetadataMgr, err = NewMetadataMgr(env.LLGOCACHE()) // build a metadata manager for version query - if err != nil { - fmt.Println(err) - } - return globalMetadataMgr -} - const ( LLPkgConfigFileName = "llpkg.cfg" GoModFileName = "go.mod" @@ -52,7 +31,10 @@ func NewModuleVersionPair(name, version string) (module.Version, error) { if !IsModulePath(name) { // 1. Convert cversion to the latest semantic version by version mappings - metadataMgr := metadata() + metadataMgr, err := NewMetadataMgr(env.LLGOCACHE()) + if err != nil { + return module.Version{}, err + } version, err := metadataMgr.LatestGoVerFromCVer(name, version) if err != nil { return module.Version{}, err From eca8cdd390e7f94611e38efc0f1bea610014ba48 Mon Sep 17 00:00:00 2001 From: Haolan Date: Wed, 2 Apr 2025 17:50:48 +0800 Subject: [PATCH 07/17] revert --- compiler/internal/mod/mod.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/internal/mod/mod.go b/compiler/internal/mod/mod.go index f619dee0ac..c30a828ced 100644 --- a/compiler/internal/mod/mod.go +++ b/compiler/internal/mod/mod.go @@ -35,7 +35,7 @@ func NewModuleVersionPair(name, version string) (module.Version, error) { if err != nil { return module.Version{}, err } - version, err := metadataMgr.LatestGoVerFromCVer(name, version) + version, err = metadataMgr.LatestGoVerFromCVer(name, version) if err != nil { return module.Version{}, err } From 8d9033e976f873f5540490c91c1741c4621e8ef7 Mon Sep 17 00:00:00 2001 From: Haolan Date: Wed, 2 Apr 2025 18:48:14 +0800 Subject: [PATCH 08/17] refactor: use module set to reduce element size --- compiler/internal/build/build.go | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/internal/build/build.go b/compiler/internal/build/build.go index c445fedf66..13215fc763 100644 --- a/compiler/internal/build/build.go +++ b/compiler/internal/build/build.go @@ -326,10 +326,10 @@ func getModule(ctx *context, ver module.Version, llpkg installer.Package, verbos return filepath.Join(dir, "lib", "pkgconfig"), nil } -func buildAllLLPkg(ctx *context, pkg []*packages.Package, verbose bool) { - installed := map[string]none{} +func buildAllLLPkg(ctx *context, allPkgs []*aPackage, verbose bool) { + installed := map[string]*module.Version{} var pcDir []string - packages.Visit(pkg, nil, func(p *packages.Package) { + for _, p := range allPkgs { // a standard lib, skip if p.Module == nil { return @@ -337,24 +337,22 @@ func buildAllLLPkg(ctx *context, pkg []*packages.Package, verbose bool) { if _, ok := installed[p.PkgPath]; ok { return } - installed[p.PkgPath] = none{} - - ver := module.Version{ + installed[p.PkgPath] = &module.Version{ Path: p.Module.Path, Version: p.Module.Version, } + } - llpkg, err := mod.ParseLLPkg(ver) + for _, ver := range installed { + llpkg, err := mod.ParseLLPkg(*ver) if err != nil { - // not an llpkg, skip. - return + continue } - - dir, err := getModule(ctx, ver, llpkg, verbose) + dir, err := getModule(ctx, *ver, llpkg, verbose) check(err) pcDir = append(pcDir, dir) - }) + } if len(pcDir) > 0 { os.Setenv("PKG_CONFIG_PATH", pc.AppendPCPath(strings.Join(pcDir, ":"))) @@ -373,7 +371,7 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs return nil, fmt.Errorf("cannot build SSA for packages") } - buildAllLLPkg(ctx, initial, verbose) + buildAllLLPkg(ctx, pkgs, verbose) built := ctx.built for _, aPkg := range pkgs { From b35df5e5e1270b24f035b58a3a9af017037efcbe Mon Sep 17 00:00:00 2001 From: Haolan Date: Wed, 2 Apr 2025 20:19:31 +0800 Subject: [PATCH 09/17] refactor: generate module version map in allPkgs --- compiler/internal/build/build.go | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/compiler/internal/build/build.go b/compiler/internal/build/build.go index 13215fc763..e36c07c68d 100644 --- a/compiler/internal/build/build.go +++ b/compiler/internal/build/build.go @@ -235,7 +235,7 @@ func Do(args []string, conf *Config) ([]Package, error) { installer := defaultInstaller() output := conf.OutFile != "" - ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool), installer} + ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool), installer, map[string]*module.Version{}} pkgs, err := buildAllPkgs(ctx, initial, verbose) check(err) if mode == ModeGen { @@ -301,7 +301,8 @@ type context struct { needRt map[*packages.Package]bool needPyInit map[*packages.Package]bool - installer installer.Installer + installer installer.Installer + moduleVersion map[string]*module.Version } func getModule(ctx *context, ver module.Version, llpkg installer.Package, verbose bool) (string, error) { @@ -326,24 +327,9 @@ func getModule(ctx *context, ver module.Version, llpkg installer.Package, verbos return filepath.Join(dir, "lib", "pkgconfig"), nil } -func buildAllLLPkg(ctx *context, allPkgs []*aPackage, verbose bool) { - installed := map[string]*module.Version{} +func buildAllLLPkg(ctx *context, verbose bool) { var pcDir []string - for _, p := range allPkgs { - // a standard lib, skip - if p.Module == nil { - return - } - if _, ok := installed[p.PkgPath]; ok { - return - } - installed[p.PkgPath] = &module.Version{ - Path: p.Module.Path, - Version: p.Module.Version, - } - } - - for _, ver := range installed { + for _, ver := range ctx.moduleVersion { llpkg, err := mod.ParseLLPkg(*ver) if err != nil { continue @@ -371,7 +357,7 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs return nil, fmt.Errorf("cannot build SSA for packages") } - buildAllLLPkg(ctx, pkgs, verbose) + buildAllLLPkg(ctx, verbose) built := ctx.built for _, aPkg := range pkgs { @@ -785,6 +771,12 @@ func allPkgs(ctx *context, initial []*packages.Package, verbose bool) (all []*aP if _, ok := built[pkgPath]; ok || strings.HasPrefix(pkgPath, altPkgPathPrefix) { return } + if p.Module != nil { + ctx.moduleVersion[pkgPath] = &module.Version{ + Path: p.Module.Path, + Version: p.Module.Version, + } + } var altPkg *packages.Cached var ssaPkg = createSSAPkg(prog, p, verbose) if llruntime.HasAltPkg(pkgPath) { From 6d9dde07cfaffa2db75623acc65e0275e8900e65 Mon Sep 17 00:00:00 2001 From: Haolan Date: Wed, 2 Apr 2025 20:43:58 +0800 Subject: [PATCH 10/17] fix: check isLLPkg when building module --- compiler/internal/build/build.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/compiler/internal/build/build.go b/compiler/internal/build/build.go index e36c07c68d..ac5ab3a35a 100644 --- a/compiler/internal/build/build.go +++ b/compiler/internal/build/build.go @@ -235,7 +235,7 @@ func Do(args []string, conf *Config) ([]Package, error) { installer := defaultInstaller() output := conf.OutFile != "" - ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool), installer, map[string]*module.Version{}} + ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool), make(map[string]*module.Version), installer} pkgs, err := buildAllPkgs(ctx, initial, verbose) check(err) if mode == ModeGen { @@ -301,8 +301,8 @@ type context struct { needRt map[*packages.Package]bool needPyInit map[*packages.Package]bool - installer installer.Installer - moduleVersion map[string]*module.Version + mod map[string]*module.Version + installer installer.Installer } func getModule(ctx *context, ver module.Version, llpkg installer.Package, verbose bool) (string, error) { @@ -329,7 +329,7 @@ func getModule(ctx *context, ver module.Version, llpkg installer.Package, verbos func buildAllLLPkg(ctx *context, verbose bool) { var pcDir []string - for _, ver := range ctx.moduleVersion { + for _, ver := range ctx.mod { llpkg, err := mod.ParseLLPkg(*ver) if err != nil { continue @@ -762,6 +762,10 @@ type aPackage struct { type Package = *aPackage +func isLLPkg(pkg *packages.Package) bool { + return pkg.Module != nil && strings.HasPrefix(mod.LLPkgPathPrefix, pkg.Module.Path) +} + func allPkgs(ctx *context, initial []*packages.Package, verbose bool) (all []*aPackage, errs []*packages.Package) { prog := ctx.progSSA built := ctx.built @@ -771,11 +775,12 @@ func allPkgs(ctx *context, initial []*packages.Package, verbose bool) (all []*aP if _, ok := built[pkgPath]; ok || strings.HasPrefix(pkgPath, altPkgPathPrefix) { return } - if p.Module != nil { - ctx.moduleVersion[pkgPath] = &module.Version{ + if isLLPkg(p) { + ver := &module.Version{ Path: p.Module.Path, Version: p.Module.Version, } + ctx.mod[ver.String()] = ver } var altPkg *packages.Cached var ssaPkg = createSSAPkg(prog, p, verbose) From f932f6a2c2cdb5f527da2feba9e1297e13787af8 Mon Sep 17 00:00:00 2001 From: Haolan Date: Wed, 2 Apr 2025 20:45:38 +0800 Subject: [PATCH 11/17] fix: hasprefix --- compiler/internal/build/build.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/internal/build/build.go b/compiler/internal/build/build.go index ac5ab3a35a..fe2d1be4cc 100644 --- a/compiler/internal/build/build.go +++ b/compiler/internal/build/build.go @@ -763,7 +763,7 @@ type aPackage struct { type Package = *aPackage func isLLPkg(pkg *packages.Package) bool { - return pkg.Module != nil && strings.HasPrefix(mod.LLPkgPathPrefix, pkg.Module.Path) + return pkg.Module != nil && strings.HasPrefix(pkg.Module.Path, mod.LLPkgPathPrefix) } func allPkgs(ctx *context, initial []*packages.Package, verbose bool) (all []*aPackage, errs []*packages.Package) { From cb6606daba4b9475ef5bbbd84b211a29cc9d649a Mon Sep 17 00:00:00 2001 From: Haolan Date: Wed, 2 Apr 2025 21:22:01 +0800 Subject: [PATCH 12/17] fix: set pc by each package --- compiler/internal/build/build.go | 79 +++++++++++++++++--------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/compiler/internal/build/build.go b/compiler/internal/build/build.go index fe2d1be4cc..78c470aaf3 100644 --- a/compiler/internal/build/build.go +++ b/compiler/internal/build/build.go @@ -235,7 +235,7 @@ func Do(args []string, conf *Config) ([]Package, error) { installer := defaultInstaller() output := conf.OutFile != "" - ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool), make(map[string]*module.Version), installer} + ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0, output, make(map[*packages.Package]bool), make(map[*packages.Package]bool), make(map[module.Version]string), installer} pkgs, err := buildAllPkgs(ctx, initial, verbose) check(err) if mode == ModeGen { @@ -301,45 +301,27 @@ type context struct { needRt map[*packages.Package]bool needPyInit map[*packages.Package]bool - mod map[string]*module.Version + llpkgMod map[module.Version]string installer installer.Installer } -func getModule(ctx *context, ver module.Version, llpkg installer.Package, verbose bool) (string, error) { - dir, err := mod.LLPkgCacheDirByModule(ver) - if err != nil { - return "", err - } - - _, err = os.Stat(dir) - if os.IsNotExist(err) { - if verbose { - fmt.Printf("installing %s to %s\n", ver.String(), dir) - } - if err = os.MkdirAll(dir, 0777); err != nil { - return "", err - } - if _, err = ctx.installer.Install(llpkg, dir); err != nil { - return "", err - } - } - - return filepath.Join(dir, "lib", "pkgconfig"), nil -} - -func buildAllLLPkg(ctx *context, verbose bool) { +// the pc for the deps of each package should be unique +// consider duplicate clib but different version +// exmaple: A requires zlib/1.3.1, B requires zlib/1.3.0 +func setDepsPC(ctx *context, p *packages.Package) { var pcDir []string - for _, ver := range ctx.mod { - llpkg, err := mod.ParseLLPkg(*ver) - if err != nil { + for _, pkg := range p.Imports { + if !isLLPkg(pkg) { continue } - dir, err := getModule(ctx, *ver, llpkg, verbose) - check(err) - - pcDir = append(pcDir, dir) + ver := module.Version{ + Path: pkg.Module.Path, + Version: pkg.Module.Version, + } + if dir := ctx.llpkgMod[ver]; dir != "" { + pcDir = append(pcDir, dir) + } } - if len(pcDir) > 0 { os.Setenv("PKG_CONFIG_PATH", pc.AppendPCPath(strings.Join(pcDir, ":"))) } @@ -357,8 +339,6 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs return nil, fmt.Errorf("cannot build SSA for packages") } - buildAllLLPkg(ctx, verbose) - built := ctx.built for _, aPkg := range pkgs { pkg := aPkg.Package @@ -368,6 +348,8 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs } built[pkg.ID] = none{} + setDepsPC(ctx, pkg) + switch kind, param := cl.PkgKindOf(pkg.Types); kind { case cl.PkgDeclOnly: // skip packages that only contain declarations @@ -766,6 +748,29 @@ func isLLPkg(pkg *packages.Package) bool { return pkg.Module != nil && strings.HasPrefix(pkg.Module.Path, mod.LLPkgPathPrefix) } +func fetchLLPkg(ctx *context, ver module.Version, verbose bool) string { + llpkg, err := mod.ParseLLPkg(ver) + if err != nil { + return "" + } + + dir, err := mod.LLPkgCacheDirByModule(ver) + check(err) + + _, err = os.Stat(dir) + if os.IsNotExist(err) { + if verbose { + fmt.Printf("installing %s to %s\n", ver.String(), dir) + } + err = os.MkdirAll(dir, 0777) + check(err) + _, err = ctx.installer.Install(llpkg, dir) + check(err) + } + + return filepath.Join(dir, "lib", "pkgconfig") +} + func allPkgs(ctx *context, initial []*packages.Package, verbose bool) (all []*aPackage, errs []*packages.Package) { prog := ctx.progSSA built := ctx.built @@ -776,11 +781,11 @@ func allPkgs(ctx *context, initial []*packages.Package, verbose bool) (all []*aP return } if isLLPkg(p) { - ver := &module.Version{ + ver := module.Version{ Path: p.Module.Path, Version: p.Module.Version, } - ctx.mod[ver.String()] = ver + ctx.llpkgMod[ver] = fetchLLPkg(ctx, ver, verbose) } var altPkg *packages.Cached var ssaPkg = createSSAPkg(prog, p, verbose) From 35a1198c1aa26de44bd7d899475936d9db1c7deb Mon Sep 17 00:00:00 2001 From: Haolan Date: Wed, 2 Apr 2025 21:27:33 +0800 Subject: [PATCH 13/17] fix: some details --- compiler/internal/build/build.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/internal/build/build.go b/compiler/internal/build/build.go index 78c470aaf3..910b927bad 100644 --- a/compiler/internal/build/build.go +++ b/compiler/internal/build/build.go @@ -757,7 +757,9 @@ func fetchLLPkg(ctx *context, ver module.Version, verbose bool) string { dir, err := mod.LLPkgCacheDirByModule(ver) check(err) - _, err = os.Stat(dir) + pkgConfigDir := filepath.Join(dir, "lib", "pkgconfig") + + _, err = os.Stat(pkgConfigDir) if os.IsNotExist(err) { if verbose { fmt.Printf("installing %s to %s\n", ver.String(), dir) @@ -768,7 +770,7 @@ func fetchLLPkg(ctx *context, ver module.Version, verbose bool) string { check(err) } - return filepath.Join(dir, "lib", "pkgconfig") + return pkgConfigDir } func allPkgs(ctx *context, initial []*packages.Package, verbose bool) (all []*aPackage, errs []*packages.Package) { @@ -785,7 +787,9 @@ func allPkgs(ctx *context, initial []*packages.Package, verbose bool) (all []*aP Path: p.Module.Path, Version: p.Module.Version, } - ctx.llpkgMod[ver] = fetchLLPkg(ctx, ver, verbose) + if _, ok := ctx.llpkgMod[ver]; !ok { + ctx.llpkgMod[ver] = fetchLLPkg(ctx, ver, verbose) + } } var altPkg *packages.Cached var ssaPkg = createSSAPkg(prog, p, verbose) From da3088ace279cdc8e7dbb38944e63727df4dae75 Mon Sep 17 00:00:00 2001 From: Haolan Date: Wed, 2 Apr 2025 22:26:06 +0800 Subject: [PATCH 14/17] fix: remove AppendPCPath in build --- compiler/internal/build/build.go | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/compiler/internal/build/build.go b/compiler/internal/build/build.go index 910b927bad..66581a9c4f 100644 --- a/compiler/internal/build/build.go +++ b/compiler/internal/build/build.go @@ -44,7 +44,6 @@ import ( "github.com/goplus/llgo/compiler/internal/mockable" "github.com/goplus/llgo/compiler/internal/mod" "github.com/goplus/llgo/compiler/internal/packages" - "github.com/goplus/llgo/compiler/internal/pc" "github.com/goplus/llgo/compiler/internal/typepatch" "github.com/goplus/llgo/compiler/ssa/abi" xenv "github.com/goplus/llgo/xtool/env" @@ -308,22 +307,19 @@ type context struct { // the pc for the deps of each package should be unique // consider duplicate clib but different version // exmaple: A requires zlib/1.3.1, B requires zlib/1.3.0 -func setDepsPC(ctx *context, p *packages.Package) { +func setDepsPC(ctx *context, pkg *packages.Package) { var pcDir []string - for _, pkg := range p.Imports { - if !isLLPkg(pkg) { - continue - } - ver := module.Version{ - Path: pkg.Module.Path, - Version: pkg.Module.Version, - } - if dir := ctx.llpkgMod[ver]; dir != "" { - pcDir = append(pcDir, dir) - } + ver := module.Version{ + Path: pkg.Module.Path, + Version: pkg.Module.Version, } + if dir := ctx.llpkgMod[ver]; dir != "" { + pcDir = append(pcDir, dir) + } + if len(pcDir) > 0 { - os.Setenv("PKG_CONFIG_PATH", pc.AppendPCPath(strings.Join(pcDir, ":"))) + pcDir = append(pcDir, os.Getenv("PKG_CONFIG_PATH")) + os.Setenv("PKG_CONFIG_PATH", strings.Join(pcDir, ":")) } } @@ -348,7 +344,9 @@ func buildAllPkgs(ctx *context, initial []*packages.Package, verbose bool) (pkgs } built[pkg.ID] = none{} - setDepsPC(ctx, pkg) + if isLLPkg(pkg) { + setDepsPC(ctx, pkg) + } switch kind, param := cl.PkgKindOf(pkg.Types); kind { case cl.PkgDeclOnly: From f2f17950c0d28960e9e39f7761a65822a530a402 Mon Sep 17 00:00:00 2001 From: Haolan Date: Wed, 2 Apr 2025 22:28:39 +0800 Subject: [PATCH 15/17] fix: check PKG_CONFIG_PATH --- compiler/internal/build/build.go | 4 +++- compiler/internal/pc/env.go | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/internal/build/build.go b/compiler/internal/build/build.go index 66581a9c4f..b3641ebec6 100644 --- a/compiler/internal/build/build.go +++ b/compiler/internal/build/build.go @@ -318,7 +318,9 @@ func setDepsPC(ctx *context, pkg *packages.Package) { } if len(pcDir) > 0 { - pcDir = append(pcDir, os.Getenv("PKG_CONFIG_PATH")) + if pkgPath, ok := os.LookupEnv("PKG_CONFIG_PATH"); ok { + pcDir = append(pcDir, pkgPath) + } os.Setenv("PKG_CONFIG_PATH", strings.Join(pcDir, ":")) } } diff --git a/compiler/internal/pc/env.go b/compiler/internal/pc/env.go index f2f4ec16fc..27b769b374 100644 --- a/compiler/internal/pc/env.go +++ b/compiler/internal/pc/env.go @@ -6,7 +6,7 @@ import ( "os/exec" ) -func AppendPCPath(path string) string { +func appendPCPath(path string) string { if env, ok := os.LookupEnv("PKG_CONFIG_PATH"); ok { return path + ":" + env } @@ -14,6 +14,6 @@ func AppendPCPath(path string) string { } func SetPath(cmd *exec.Cmd, path string) { - pcPath := fmt.Sprintf("PKG_CONFIG_PATH=%s", AppendPCPath(path)) + pcPath := fmt.Sprintf("PKG_CONFIG_PATH=%s", appendPCPath(path)) cmd.Env = append(os.Environ(), pcPath) } From 8d43831a40a540054c22fa9cbbbf8884d0488278 Mon Sep 17 00:00:00 2001 From: Haolan Date: Thu, 3 Apr 2025 10:59:11 +0800 Subject: [PATCH 16/17] chore: upgrade ghreleases --- .../internal/installer/githubreleases/githubreleases_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/internal/installer/githubreleases/githubreleases_test.go b/compiler/internal/installer/githubreleases/githubreleases_test.go index 69d5f04b86..86a8f70887 100644 --- a/compiler/internal/installer/githubreleases/githubreleases_test.go +++ b/compiler/internal/installer/githubreleases/githubreleases_test.go @@ -18,7 +18,7 @@ import ( func TestGHInstaller(t *testing.T) { ghr := &ghReleasesInstaller{ config: map[string]string{ - "owner": `MeteorsLiu`, + "owner": `goplus`, "repo": `llpkg`, "platform": runtime.GOOS, "arch": runtime.GOARCH, From 04f00961fb8d26724fe017a9de30a5a5b4e97eed Mon Sep 17 00:00:00 2001 From: Haolan Date: Thu, 3 Apr 2025 11:45:27 +0800 Subject: [PATCH 17/17] fix: output errpr instead of panic --- compiler/internal/build/build.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/internal/build/build.go b/compiler/internal/build/build.go index b3641ebec6..a44e05baaf 100644 --- a/compiler/internal/build/build.go +++ b/compiler/internal/build/build.go @@ -761,13 +761,14 @@ func fetchLLPkg(ctx *context, ver module.Version, verbose bool) string { _, err = os.Stat(pkgConfigDir) if os.IsNotExist(err) { - if verbose { - fmt.Printf("installing %s to %s\n", ver.String(), dir) - } + fmt.Printf("installing %s to %s\n", ver.String(), dir) + err = os.MkdirAll(dir, 0777) check(err) _, err = ctx.installer.Install(llpkg, dir) - check(err) + if err != nil { + fmt.Fprintf(os.Stderr, "Warning: installing %s fail: %v\n", ver.String(), err) + } } return pkgConfigDir