ebiten/cmd/ebitenmonogame/main.go
2020-04-24 20:48:01 +09:00

269 lines
6.2 KiB
Go

// Copyright 2020 The Ebiten Authors
//
// 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 main
import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/hajimehoshi/go2dotnet/gowasm2csharp"
)
const ebitenmonogameName = "ebitenmonogame"
var (
flagA bool // -a
flagGcflags string // -gcflags
flagI bool // -i
flagLdflags string // -ldflags
flagN bool // -n
flagTags string // -tags
flagTrimpath bool // -trimpath
flagV bool // -v
flagWork bool // -work
flagX bool // -x
flagNamespace string // -namespace
flagO string // -o
)
func main() {
if err := checkGOOS(); err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", ebitenmonogameName, err)
os.Exit(2)
}
var flagset flag.FlagSet
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "%s [-namespace namespace] [-o output] [build flags] [package]\n", ebitenmonogameName)
os.Exit(2)
}
flagset.BoolVar(&flagA, "a", false, "")
flagset.StringVar(&flagGcflags, "gcflags", "", "")
flagset.BoolVar(&flagI, "i", false, "")
flagset.StringVar(&flagLdflags, "ldflags", "", "")
flagset.BoolVar(&flagN, "n", false, "")
flagset.StringVar(&flagTags, "tags", "", "")
flagset.BoolVar(&flagTrimpath, "trimpath", false, "")
flagset.BoolVar(&flagV, "v", false, "")
flagset.BoolVar(&flagWork, "work", false, "")
flagset.BoolVar(&flagX, "x", false, "")
flagset.StringVar(&flagNamespace, "namespace", "", "")
flagset.StringVar(&flagO, "o", "", "")
flagset.Parse(os.Args[1:])
if flagNamespace == "" {
fmt.Fprintln(os.Stderr, "-namespace must be specified")
os.Exit(2)
}
if flagO == "" {
fmt.Fprintln(os.Stderr, "-o must be specified")
os.Exit(2)
}
if flagLdflags != "" {
flagLdflags += " "
}
flagLdflags = "-X github.com/hajimehoshi/ebiten/internal/monogame.namespace=" + flagNamespace
if flagTags != "" {
flagTags += ","
}
flagTags += "monogame"
var src string
switch srcs := flagset.Args(); len(srcs) {
case 0:
src = "."
case 1:
src = srcs[0]
default:
flag.Usage()
}
if err := run(src); err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", ebitenmonogameName, err)
os.Exit(2)
}
}
func checkGOOS() error {
out, err := exec.Command("go", "env", "GOOS").Output()
if err != nil {
return err
}
goos := strings.TrimSpace(string(out))
if goos != "windows" {
fmt.Fprintln(os.Stderr, "Warning: The output project is buildable on Windows.")
}
return nil
}
func run(src string) error {
// TODO: Check src is a main package?
// Generate a wasm binary.
env := []string{
"GOOS=js",
"GOARCH=wasm",
}
dir, err := ioutil.TempDir("", "ebitenmonogame")
if err != nil {
return err
}
defer func() {
if flagWork {
fmt.Fprintf(os.Stderr, "The temporary work directory: %s\n", dir)
return
}
os.RemoveAll(dir)
}()
wasmFile := filepath.Join(dir, "tmp.wasm")
if err := runGo("build", []string{src}, env, "-o", wasmFile); err != nil {
return err
}
if flagN {
return nil
}
autogenDir := filepath.Join(flagO, "autogen")
if flagV {
fmt.Fprintf(os.Stderr, "Writing %s%s*.cs\n", autogenDir, string(filepath.Separator))
}
if err := os.MkdirAll(autogenDir, 0755); err != nil {
return err
}
if err := gowasm2csharp.Generate(autogenDir, wasmFile, flagNamespace+".AutoGen"); err != nil {
return err
}
if err := writeFile(filepath.Join(flagO, "GoGame.cs"), replaceNamespace(gogame_cs)); err != nil {
return err
}
if err := writeFile(filepath.Join(flagO, "Program.cs"), replaceNamespace(program_cs)); err != nil {
return err
}
abs, err := filepath.Abs(flagO)
if err != nil {
return err
}
project := filepath.Base(abs)
if err := writeFile(filepath.Join(flagO, project+".csproj"), replaceNamespace(project_csproj)); err != nil {
return err
}
if err := writeFile(filepath.Join(flagO, "Content", "Content.mgcb"), replaceNamespace(content_mgcb)); err != nil {
return err
}
if err := writeFile(filepath.Join(flagO, "Content", "Shader.fx"), replaceNamespace(shader_fx)); err != nil {
return err
}
return nil
}
func runGo(subcmd string, srcs []string, env []string, args ...string) error {
cmd := exec.Command("go", subcmd)
if flagA {
cmd.Args = append(cmd.Args, "-a")
}
if flagGcflags != "" {
cmd.Args = append(cmd.Args, "-gcflags", flagGcflags)
}
if flagI {
cmd.Args = append(cmd.Args, "-i")
}
if flagLdflags != "" {
cmd.Args = append(cmd.Args, "-ldflags", flagLdflags)
}
if flagTags != "" {
cmd.Args = append(cmd.Args, "-tags", flagTags)
}
if flagTrimpath {
cmd.Args = append(cmd.Args, "-trimpath")
}
if flagV {
cmd.Args = append(cmd.Args, "-v")
}
if flagWork {
cmd.Args = append(cmd.Args, "-work")
}
if flagX {
cmd.Args = append(cmd.Args, "-x")
}
cmd.Args = append(cmd.Args, args...)
cmd.Args = append(cmd.Args, srcs...)
if len(env) > 0 {
cmd.Env = append([]string{}, env...)
}
if flagX || flagN {
env := strings.Join(cmd.Env, " ")
if env != "" {
env += " "
}
fmt.Fprintf(os.Stderr, "%s%s\n", env, strings.Join(cmd.Args, " "))
}
if flagN {
return nil
}
if len(cmd.Env) > 0 {
cmd.Env = append(os.Environ(), cmd.Env...)
}
buf := &bytes.Buffer{}
buf.WriteByte('\n')
if flagV {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
} else {
cmd.Stdout = buf
cmd.Stderr = buf
}
if err := cmd.Run(); err != nil {
return fmt.Errorf("%s failed: %v%s", strings.Join(cmd.Args, " "), err, buf)
}
return nil
}
func writeFile(dst string, src []byte) error {
if flagV {
fmt.Fprintf(os.Stderr, "Writing %s\n", dst)
}
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
return err
}
if err := ioutil.WriteFile(dst, src, 0644); err != nil {
return err
}
return nil
}
func replaceNamespace(src []byte) []byte {
return []byte(strings.ReplaceAll(string(src), "{{.Namespace}}", flagNamespace))
}