| /* |
| * Copyright 2015 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| package main |
| |
| // Example use: |
| // git clone https://skia.googlesource.com/skia.git |
| // cd skia |
| // SKIA=$PWD |
| // cd experimental/fiddle |
| // go get github.com/skia-dev/glog |
| // go get go.skia.org/infra/go/util |
| // go build fiddler.go |
| // # compile prerequisites |
| // ./fiddler "$SKIA" |
| // # compile and run a fiddle |
| // ./fiddler "$SKIA" draw.cpp | ./parse-fiddle-output |
| // # compile and run a different fiddle |
| // ./fiddler "$SKIA" ANOTHER_FIDDLE.cpp | ./parse-fiddle-output |
| |
| import ( |
| "bytes" |
| "fmt" |
| "io" |
| "io/ioutil" |
| "os" |
| "os/exec" |
| "path" |
| "syscall" |
| |
| "github.com/skia-dev/glog" |
| "go.skia.org/infra/go/util" |
| ) |
| |
| func setResourceLimits() error { |
| const maximumTimeInSeconds = 5 |
| limit := syscall.Rlimit{maximumTimeInSeconds, maximumTimeInSeconds} |
| if err := syscall.Setrlimit(syscall.RLIMIT_CPU, &limit); err != nil { |
| return err |
| } |
| const maximumMemoryInBytes = 1 << 28 |
| limit = syscall.Rlimit{maximumMemoryInBytes, maximumMemoryInBytes} |
| return syscall.Setrlimit(syscall.RLIMIT_AS, &limit) |
| } |
| |
| // execCommand runs command and returns an error if it fails. If there is no |
| // error, all output is discarded. |
| func execCommand(input io.Reader, dir string, name string, arg ...string) error { |
| var buffer bytes.Buffer |
| cmd := exec.Command(name, arg...) |
| cmd.Dir = dir |
| cmd.Stdout = &buffer |
| cmd.Stderr = &buffer |
| cmd.Stdin = input |
| if err := cmd.Run(); err != nil { |
| return fmt.Errorf("execution failed:\n\n%s\n[%v]", buffer.String(), err) |
| } |
| return nil |
| } |
| |
| func compileArgs(skiaSrc string) string { |
| return "@" + path.Join(skiaSrc, "cmake", "skia_compile_arguments.txt") |
| } |
| |
| func linkArgs(skiaSrc string) string { |
| return "@" + path.Join(skiaSrc, "cmake", "skia_link_arguments.txt") |
| } |
| |
| // fiddler compiles the input, links against skia, and runs the executable. |
| // @param skiaSrc: the base directory of the Skia repository |
| // @param inputReader: C++ fiddle source |
| // @param output: stdout of executable sent here |
| // @param tempDir: where to place the compiled executable |
| func fiddler(skiaSrc string, inputReader io.Reader, output io.Writer, tempDir string) error { |
| binarypath := path.Join(tempDir, "fiddle") |
| fiddle_dir := path.Join(skiaSrc, "experimental", "fiddle") |
| if err := execCommand(inputReader, fiddle_dir, |
| "c++", |
| compileArgs(skiaSrc), |
| "-I", fiddle_dir, |
| "-o", binarypath, |
| "-x", "c++", "-", "-x", "none", |
| "fiddle_main.o", |
| "-lOSMesa", |
| linkArgs(skiaSrc), |
| ); err != nil { |
| return err |
| } |
| var buffer bytes.Buffer |
| runCmd := exec.Cmd{Path: binarypath, Stdout: output, Stderr: &buffer} |
| if err := runCmd.Run(); err != nil { |
| return fmt.Errorf("execution failed:\n\n%s\n[%v]", buffer.String(), err) |
| } |
| return nil |
| } |
| |
| // Compile Skia library and fiddle_main.cpp |
| // @param skiaSrc: the base directory of the Skia repository. |
| func fiddlerPrerequisites(skiaSrc string) error { |
| cmakeDir := path.Join(skiaSrc, "cmake") |
| if err := execCommand(nil, cmakeDir, "cmake", "-G", "Ninja", "."); err != nil { |
| return err |
| } |
| if err := execCommand(nil, cmakeDir, "ninja", "skia"); err != nil { |
| return err |
| } |
| fiddle_dir := path.Join(skiaSrc, "experimental", "fiddle") |
| if err := execCommand(nil, fiddle_dir, "c++", compileArgs(skiaSrc), |
| "fiddle_main.h"); err != nil { |
| return err |
| } |
| return execCommand(nil, fiddle_dir, "c++", compileArgs(skiaSrc), |
| "-c", "-o", "fiddle_main.o", "fiddle_main.cpp") |
| } |
| |
| func main() { |
| if len(os.Args) < 2 { |
| glog.Fatalf("usage: %s SKIA_SRC_PATH [PATH_TO_DRAW.CPP]", os.Args[0]) |
| } |
| skiaSrc := os.Args[1] |
| if len(os.Args) < 3 { |
| // execCommand(nil, skiaSrc, "git", "fetch") |
| // execCommand(nil, skiaSrc, "git", "checkout", "origin/master") |
| if err := fiddlerPrerequisites(skiaSrc); err != nil { |
| glog.Fatal(err) |
| } |
| } else { |
| if err := setResourceLimits(); err != nil { |
| glog.Fatal(err) |
| } |
| tempDir, err := ioutil.TempDir("", "fiddle_") |
| if err != nil { |
| glog.Fatal(err) |
| } |
| defer func() { |
| err = os.RemoveAll(tempDir) |
| if err != nil { |
| glog.Fatalf("os.RemoveAll(tempDir) failed: %v", err) |
| } |
| }() |
| if os.Args[2] == "-" { |
| if err := fiddler(skiaSrc, os.Stdin, os.Stdout, tempDir); err != nil { |
| glog.Fatal(err) |
| } |
| } else { |
| inputFile, err := os.Open(os.Args[2]) |
| if err != nil { |
| glog.Fatalf("unable to open \"%s\": %v", os.Args[2], err) |
| } |
| util.Close(inputFile) |
| if err = fiddler(skiaSrc, inputFile, os.Stdout, tempDir); err != nil { |
| glog.Fatal(err) |
| } |
| } |
| } |
| } |