Skip to content

Commit

Permalink
feat(cli): add target-os and target-arch flags for neva build c…
Browse files Browse the repository at this point in the history
…md; add `neva osarch` command that prints output of the `go tool
  • Loading branch information
emil14 committed Jan 5, 2025
1 parent d6461f9 commit 579938e
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 22 deletions.
12 changes: 4 additions & 8 deletions cmd/neva/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
)

func main() {
wd, err := os.Getwd()
workdir, err := os.Getwd()
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -53,9 +53,7 @@ func main() {
&desugarer,
analyzer,
irgen,
native.NewBackend(
golangBackend,
),
native.NewBackend(golangBackend),
)

wasmCompiler := compiler.New(
Expand All @@ -64,9 +62,7 @@ func main() {
&desugarer,
analyzer,
irgen,
wasm.NewBackend(
golangBackend,
),
wasm.NewBackend(golangBackend),
)

jsonCompiler := compiler.New(
Expand All @@ -89,7 +85,7 @@ func main() {

// command-line app that can compile and interpret neva code
app := cli.NewApp(
wd,
workdir,
bldr,
goCompiler,
nativeCompiler,
Expand Down
2 changes: 2 additions & 0 deletions docs/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ This will produce an `output` file in the directory where neva-cli was executed,

Once again you should see `Hello, World!`.

> Execute `neva build --help` to learn more - how to compile to Go, WASM or how to do cross-compilation e.g. compile linux binaries in windows.
## Core Concepts

### Components
Expand Down
76 changes: 62 additions & 14 deletions internal/cli/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cli

import (
"fmt"
"os"

"github.com/nevalang/neva/internal/compiler"

Expand All @@ -18,7 +19,7 @@ func newBuildCmd(
) *cli.Command {
return &cli.Command{
Name: "build",
Usage: "Build neva program from source code",
Usage: "Generate target platform code from neva program",
Args: true,
Flags: []cli.Flag{
&cli.StringFlag{
Expand All @@ -31,7 +32,7 @@ func newBuildCmd(
},
&cli.StringFlag{
Name: "target",
Usage: "Target platform for build (options: go, wasm, native, json, dot)",
Usage: "Target platform for build (options: go, wasm, native, json, dot). For 'native' target, 'target-os' and 'target-arch' flags can be used, but if used, they must be used together.",
Action: func(ctx *cli.Context, s string) error {
switch s {
case "go", "wasm", "native", "json", "dot":
Expand All @@ -40,24 +41,52 @@ func newBuildCmd(
return fmt.Errorf("Unknown target %s", s)
},
},
&cli.StringFlag{
Name: "target-os",
Usage: "Target operating system for native build. See 'neva osarch' for supported combinations. Only supported for native target. Not needed if building for the current platform. Must be combined properly with 'target-arch'.",
},
&cli.StringFlag{
Name: "target-arch",
Usage: "Target architecture for native build. See 'neva osarch' for supported combinations. Only supported for native target. Not needed if building for the current platform. Must be combined properly with 'target-os'.",
},
},
ArgsUsage: "Provide path to main package",
Action: func(cliCtx *cli.Context) error {
var target string
if cliCtx.IsSet("target") {
target = cliCtx.String("target")
} else {
target = "native"
}

switch target {
case "go", "wasm", "json", "dot", "native":
default:
return fmt.Errorf("Unknown target %s", target)
}

var targetOS, targetArch string
if cliCtx.IsSet("target-os") {
targetOS = cliCtx.String("target-os")
}
if cliCtx.IsSet("target-arch") {
targetArch = cliCtx.String("target-arch")
}
if (targetOS != "" && targetArch == "") || (targetOS == "" && targetArch != "") {
return fmt.Errorf("target-os and target-arch must be set together")
}
if target != "native" && targetOS != "" {
return fmt.Errorf("target-os and target-arch are only supported when target is native")
}

mainPkg, err := mainPkgPathFromArgs(cliCtx)
if err != nil {
return err
}

output := workdir
outputDirPath := workdir
if cliCtx.IsSet("output") {
output = cliCtx.String("output")
}

var target string
if cliCtx.IsSet("target") {
target = cliCtx.String("target")
} else {
target = "native"
outputDirPath = cliCtx.String("output")
}

var isTraceEnabled bool
Expand All @@ -67,7 +96,7 @@ func newBuildCmd(

compilerInput := compiler.CompilerInput{
Main: mainPkg,
Output: output,
Output: outputDirPath,
Trace: isTraceEnabled,
}

Expand All @@ -83,8 +112,27 @@ func newBuildCmd(
compilerToUse = compilerToDOT
case "native":
compilerToUse = compilerToNative
default:
return fmt.Errorf("Unknown target %s", target)
}

if targetOS != "" {
prevGOOS := os.Getenv("GOOS")
prevGOARCH := os.Getenv("GOARCH")

if err := os.Setenv("GOOS", targetOS); err != nil {
return fmt.Errorf("set GOOS: %w", err)
}
if err := os.Setenv("GOARCH", targetArch); err != nil {
return fmt.Errorf("set GOARCH: %w", err)
}

defer func() {
if err := os.Setenv("GOOS", prevGOOS); err != nil {
panic(err)
}
if err := os.Setenv("GOARCH", prevGOARCH); err != nil {
panic(err)
}
}()
}

return compilerToUse.Compile(cliCtx.Context, compilerInput)
Expand Down
1 change: 1 addition & 0 deletions internal/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func NewApp(
newGetCmd(workdir, bldr),
newRunCmd(workdir, nativec),
newBuildCmd(workdir, goc, nativec, wasmc, jsonc, dotc),
newOSArchCmd(),
},
}
}
Expand Down
34 changes: 34 additions & 0 deletions internal/cli/osarch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package cli

import (
"fmt"
"os/exec"
"strings"

cli "github.com/urfave/cli/v2"
)

func newOSArchCmd() *cli.Command {
return &cli.Command{
Name: "osarch",
Usage: "List supported OS/architecture combinations for native target",
Action: func(cliCtx *cli.Context) error {
cmd := exec.Command("go", "tool", "dist", "list")
output, err := cmd.Output()
if err != nil {
return fmt.Errorf("failed to execute go tool dist list: %w", err)
}

fmt.Println("Supported OS/architecture combinations for native target:")
fmt.Println("(use these values for --target-os and --target-arch flags when cross-compiling)")
fmt.Println()

platforms := strings.Split(strings.TrimSpace(string(output)), "\n")
for _, platform := range platforms {
fmt.Println(platform)
}

return nil
},
}
}

0 comments on commit 579938e

Please sign in to comment.