This commit is contained in:
xushiwei
2024-04-25 01:41:44 +08:00
parent a2c6e5d7fc
commit 3f49fe9e98
5 changed files with 129 additions and 17 deletions

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
// Package build implements the llgo build command.
// Package build implements the "llgo build" command.
package build
import (
@@ -34,6 +34,7 @@ func init() {
func runCmd(cmd *base.Command, args []string) {
build.Do(args, &build.Config{
Mode: build.ModeBuild,
Mode: build.ModeBuild,
AppExt: build.DefaultAppExt(),
})
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
// Package install implements the llgo install command.
// Package install implements the "llgo install" command.
package install
import (

85
cmd/internal/run/run.go Normal file
View File

@@ -0,0 +1,85 @@
/*
* 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 run implements the "llgo run" command.
package run
import (
"errors"
"path/filepath"
"strings"
"github.com/goplus/llgo/cmd/internal/base"
"github.com/goplus/llgo/internal/build"
)
var (
errNoProj = errors.New("llgo: no go files listed")
)
// llgo run
var Cmd = &base.Command{
UsageLine: "llgo run [build flags] package [arguments...]",
Short: "Compile and run Go program",
}
func init() {
Cmd.Run = runCmd
}
func runCmd(cmd *base.Command, args []string) {
args, runArgs, err := parseRunArgs(args)
check(err)
conf := build.NewDefaultConf(build.ModeRun)
conf.RunArgs = runArgs
build.Do(args, conf)
}
func parseRunArgs(args []string) ([]string, []string, error) {
n := parseArgs(args)
if n < 0 {
return nil, nil, errNoProj
}
arg := args[n]
if isGoFile(arg) {
n++
for n < len(args) && isGoFile(args[n]) {
n++
}
return args[:n], args[n:], nil
}
return args[:n+1], args[n+1:], nil
}
func parseArgs(args []string) int {
for i, arg := range args {
if !strings.HasPrefix(arg, "-") {
return i
}
}
return -1
}
func isGoFile(fname string) bool {
return filepath.Ext(fname) == ".go"
}
func check(err error) {
if err != nil {
panic(err)
}
}

View File

@@ -28,6 +28,7 @@ import (
"github.com/goplus/llgo/cmd/internal/build"
"github.com/goplus/llgo/cmd/internal/help"
"github.com/goplus/llgo/cmd/internal/install"
"github.com/goplus/llgo/cmd/internal/run"
)
func mainUsage() {
@@ -40,6 +41,7 @@ func init() {
base.Llgo.Commands = []*base.Command{
build.Cmd,
install.Cmd,
run.Cmd,
}
}

View File

@@ -21,6 +21,7 @@ import (
"go/token"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
@@ -40,12 +41,18 @@ type Mode int
const (
ModeBuild Mode = iota
ModeInstall
ModeRun
)
func needLLFile(mode Mode) bool {
return mode != ModeBuild
}
type Config struct {
BinPath string
AppSuffix string // ".exe" on Windows, empty on Unix
Mode Mode
BinPath string
AppExt string // ".exe" on Windows, empty on Unix
RunArgs []string
Mode Mode
}
func NewDefaultConf(mode Mode) *Config {
@@ -56,13 +63,18 @@ func NewDefaultConf(mode Mode) *Config {
conf := &Config{
BinPath: bin,
Mode: mode,
}
if runtime.GOOS == "windows" {
conf.AppSuffix = ".exe"
AppExt: DefaultAppExt(),
}
return conf
}
func DefaultAppExt() string {
if runtime.GOOS == "windows" {
return ".exe"
}
return ""
}
// -----------------------------------------------------------------------------
const (
@@ -104,20 +116,22 @@ func Do(args []string, conf *Config) {
buildPkg(prog, pkg, mode)
}
if mode == ModeInstall {
if mode != ModeBuild || len(initial) == 1 {
for _, pkg := range initial {
if pkg.Name == "main" {
linkMainPkg(pkg, conf)
linkMainPkg(pkg, conf, mode)
}
}
}
}
func linkMainPkg(pkg *packages.Package, conf *Config) {
name := path.Base(pkg.PkgPath)
func linkMainPkg(pkg *packages.Package, conf *Config, mode Mode) {
pkgPath := pkg.PkgPath
name := path.Base(pkgPath)
app := filepath.Join(conf.BinPath, name+conf.AppExt)
args := make([]string, 2, len(pkg.Imports)+3)
args[0] = "-o"
args[1] = filepath.Join(conf.BinPath, name+conf.AppSuffix)
args[1] = app
packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) {
if p.PkgPath != "unsafe" { // TODO(xsw): remove this special case
args = append(args, p.ExportFile+".ll")
@@ -126,21 +140,31 @@ func linkMainPkg(pkg *packages.Package, conf *Config) {
// TODO(xsw): show work
// fmt.Fprintln(os.Stderr, "clang", args)
fmt.Fprintln(os.Stderr, args[1])
fmt.Fprintln(os.Stderr, "#", pkgPath)
err := clang.New("").Exec(args...)
check(err)
if mode == ModeRun {
cmd := exec.Command(app, conf.RunArgs...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
}
}
func buildPkg(prog llssa.Program, aPkg aPackage, mode Mode) {
pkg := aPkg.Package
pkgPath := pkg.PkgPath
fmt.Fprintln(os.Stderr, pkgPath)
if mode != ModeRun {
fmt.Fprintln(os.Stderr, pkgPath)
}
if pkgPath == "unsafe" { // TODO(xsw): remove this special case
return
}
ret, err := cl.NewPackage(prog, aPkg.SSA, pkg.Syntax)
check(err)
if mode == ModeInstall {
if needLLFile(mode) {
file := pkg.ExportFile + ".ll"
os.WriteFile(file, []byte(ret.String()), 0644)
}