simple go runner written in go

102 views
Skip to first unread message

Dimiter "malkia" Stanev

unread,
Nov 25, 2009, 4:45:57 AM11/25/09
to golang-nuts
/*
# Makefile for go.go
# once build use the "go" command like this:
# go test
# would compile & link test.go and run it
# future versions would automatically parse test.go to detect other
used local modules
# current version is fixed to 6l/6g

all: install

include $(GOROOT)/src//Make.$(GOARCH)

TARG = go
GOFILES = $(TARG).go

include $(GOROOT)/src/Make.cmd
*/

package main

import ( "os"; "fmt"; "flag" )

func chk( e os.Error )
{
if( e != nil ) {
fmt.Fprintf( os.Stderr, "%s\n", e );
os.Exit(1);
}
}

func exec( args []string )
{
var p, e1 = os.ForkExec( args[0], args, os.Environ(), "", nil );
chk(e1);
var m, e2 = os.Wait( p, 0 );
chk(e2);
if( m.WaitStatus != 0 ) {
fmt.Fprintf( os.Stderr, "%s\n", m );
os.Exit(1);
}
}

func main() {
var args = flag.Args();
var gobin = os.Getenv( "GOBIN" ) + "/";
var wd, _ = os.Getwd();
if( len( args ) > 0 ) {
var target = args[0];
exec( []string{ gobin + "6g", target + ".go" } );
exec( []string{ gobin + "6l", "-o", target, target + ".6" } );
os.Exec( wd + "/" + target, args, os.Environ());
}
}

i3dmaster

unread,
Nov 27, 2009, 2:44:32 AM11/27/09
to golang-nuts
Hi I like this runner and it does simplify the compile, link, and run
process. I've made a bit change to have it support go supported
platforms and add more comments. It seems to be a useful cmd, if you
like, we can see if it can be added into the go tool set. Here is the
revised version, please take a look.

// all-in-one go cmd to compile, link and exec the target .go source
file.
// Original author: mal...@gmail.com (Dimiter malkia Stanev)
// Modified to support multiple platforms: i3dm...@gmail.com
(Yongjian Xu)

package main

import (
"flag";
"fmt";
"os";
"strings";
)

// Error raised when target architecture is not supported by the go
language.
var UnSupportedArchError os.Error = os.ErrorString("Unsupported
Architecture")

// Struct to hold the go binaries for the current system.
// ext => the object file extension.
// gcompiler => gc compiler name.
// linker => linker name.
// compiler => C compiler name.
// assembler => Assembler name.
type toolChain struct {
ext string;
gcompiler string;
linker string;
compiler string;
assembler string;
}

// Return the toolchain binaries for the target system.
func getTooChain(arch string) (*toolChain, os.Error) {
toolchain := new(toolChain);
switch {
case arch == "amd64":
toolchain.ext = ".6";
toolchain.gcompiler = "6g";
toolchain.linker = "6l";
toolchain.compiler = "6c";
toolchain.assembler = "6a";
return toolchain, nil;
case arch == "386":
toolchain.ext = ".8";
toolchain.gcompiler = "8g";
toolchain.linker = "8l";
toolchain.compiler = "8c";
toolchain.assembler = "8a";
return toolchain, nil;
case arch == "arm":
toolchain.ext = ".5";
toolchain.gcompiler = "5g";
toolchain.linker = "5l";
toolchain.compiler = "5c";
toolchain.assembler = "5a";
return toolchain, nil;
}
return nil, UnSupportedArchError
}

// Check the command error status. Return false if command fails,
// otherwise, return true.
func chk(cmd string, e os.Error) bool
{
if(e != nil) {
fmt.Fprintf(os.Stderr, "%s: %s\n", e, cmd);
return false;
}
return true;
}

// Fork a subprocess and execute the command.
// If failed, exit immediately, otherwise, return true.
func exec(args []string) bool
{
cmd := strings.Join(args, " ");
fmt.Fprintf(os.Stderr, "Exec: %s\n", cmd);
p, e1 := os.ForkExec(args[0], args, os.Environ(), "", nil);
if !chk(cmd, e1) {
fmt.Fprintf(os.Stderr, "%s: exec err: %s\n", cmd, e1);
os.Exit(1);
}
m, e2 := os.Wait(p, 0);
if !chk(cmd, e2) {
fmt.Fprintf(os.Stderr, "%s: wait failed: %s\n", cmd, e2);
os.Exit(1);
}
if(m.WaitStatus != 0) {
fmt.Fprintf(os.Stderr, "%s\n", m);
os.Exit(1);
}
return true;
}

func main() {
if flag.NArg() <= 0 {
println("Compile, link and execute the target.");
fmt.Printf("Usage of %s:\n", os.Args[0]);
fmt.Printf("\t%s <target> [ args ]\n", os.Args[0]);
os.Exit(0);
}

args := flag.Args();
gobin := os.Getenv("GOBIN") + "/";
fmt.Fprintf(os.Stderr, "GOBIN: %s\n", gobin);
wd, _ := os.Getwd();
fmt.Fprintf(os.Stderr, "Current dir: %s\n", wd);
toolchain, err := getTooChain(os.Getenv("GOARCH"));
if err == nil {
if len(args) > 0 {
target := args[0];
exec([]string{gobin + toolchain.gcompiler, target + ".go"});
exec([]string{gobin + toolchain.linker, "-o", target, target +
toolchain.ext});
os.Exec(wd + "/" + target, args, os.Environ());
}
} else {
fmt.Fprintf(os.Stderr, "%s\n", err);
os.Exit(1);
}
}


On Nov 25, 1:45 am, "Dimiter \"malkia\" Stanev" <mal...@gmail.com>
wrote:
> /*
> # Makefile forgo.go
> # once build use the "go" command like this:
> #  gotest
> # would compile & link test.goand run it
> # future versions would automatically parse test.goto detect other

i3dmaster

unread,
Nov 27, 2009, 4:03:04 AM11/27/09
to golang-nuts
Added flags to support nolink and noexec, support either target.go |
target, and add usage printout.

e.g:
go target //compile, link, run.
go -nolinking target //only compile, no link, no run)
go -noexec target //only compile, link, and no run)
go // Print Usage.

The above target can also be provided as "target.go"


// all-in-one go cmd to compile, link and exec the target .go source
file.
// Original author: mal...@gmail.com (Dimiter malkia Stanev)
// Modified to support multiple platforms: i3dm...@gmail.com
(Yongjian Xu)

package main

import (
"flag";
"fmt";
"os";
"strings";
)

var flag_nolink = flag.Bool("nolinking", false,
"Do not run linker after compile.")
var flag_noexec = flag.Bool("noexec", false, "Do not run the binary.")
flag.Parse();
if flag.NArg() <= 0 {
fmt.Printf("%s <target> [ args ]\n", os.Args[0]);
flag.Usage();
os.Exit(0);
}

args := flag.Args();
gobin := os.Getenv("GOBIN") + "/";
fmt.Fprintf(os.Stderr, "GOBIN: %s\n", gobin);
wd, _ := os.Getwd();
fmt.Fprintf(os.Stderr, "Current dir: %s\n", wd);
toolchain, err := getTooChain(os.Getenv("GOARCH"));
if err == nil {
target := strings.Split(args[0], ".", 2)[0];
file := target + ".go";
exec([]string{gobin + toolchain.gcompiler, file});
if !*flag_nolink {
exec([]string{gobin + toolchain.linker, "-o", target, target +
toolchain.ext});
if !*flag_noexec {
os.Exec(wd + "/" + target, args, os.Environ());
}
}
} else {
fmt.Fprintf(os.Stderr, "%s\n", err);
os.Exit(1);
}
}


On Nov 25, 1:45 am, "Dimiter \"malkia\" Stanev" <mal...@gmail.com>
wrote:

manatlan

unread,
Nov 27, 2009, 4:12:00 AM11/27/09
to golang-nuts
There is GG too : http://www.manatlan.com/blog/gg_in_go_language
with incremental builds ... yaml makefile possibilities ...

Which is able to do this kind of things :
http://www.manatlan.com/blog/google_go_language_and_the_gg_builder

(and I ve got one version (not released yet), which is able to
generate a makefile (ast/token parsing), by providing go files ...)


On Nov 25, 10:45 am, "Dimiter \"malkia\" Stanev" <mal...@gmail.com>
wrote:

Yongjian Xu

unread,
Nov 27, 2009, 5:44:09 AM11/27/09
to manatlan, golang-nuts
Cool. Wish I've had known that earlier. :) Should try to get included into the go source tree. 

Dimiter "malkia" Stanev

unread,
Dec 2, 2009, 3:36:37 AM12/2/09
to golang-nuts
I've updated the runner. Now it can compile files included with
'import "./somefile"'

It assumes that the package "./somefile" refers to somefile.go, and
that somefile.go starts with "package somefile".

It always compiles/links, never checks for timestamps, and assumes
model 6 (amd64).

Here is the latest version:

http://gist.github.com/247048

On Nov 25, 1:45 am, "Dimiter \"malkia\" Stanev" <mal...@gmail.com>
wrote:
> /*
> # Makefile forgo.go
> # once build use the "go" command like this:
> #  gotest
> # would compile & link test.goand run it
> # future versions would automatically parse test.goto detect other

simonced

unread,
Dec 2, 2009, 9:09:34 AM12/2/09
to golang-nuts
Hi,

I'm new to go and I'm trying to give it a try.

I wanted to write this same thing (in bash or python lol but I don't
need as you did it).
But I can't compile it :(
My Go installation is working as I played with a single go source I
made, but here I encounter this error :

$ 8c sample_go_runner.go
simple_go_runner.go:1 not a function
simple_go_runner.go:1 syntax error, last name: main

This line only contains the "package main" line.
Any idea? I may have forgotten something as Go is totally new to me
but...

Thank you.

emghazal

unread,
Dec 2, 2009, 11:29:09 AM12/2/09
to golang-nuts

On Dec 2, 5:09 pm, simonced <simon...@gmail.com> wrote:
>
> $ 8c sample_go_runner.go
> simple_go_runner.go:1 not a function
> simple_go_runner.go:1 syntax error, last name: main
>

8c is the Plan9 C compiler. use 8g and 8l to compile and run go:
$ 8g filename.go
$ 8l filename.8
$ ./8.out

Well, the runner is currently hardcoded to use 6g/6l. You can try
editing it yourself to use 8g/8l instead if your computer is not 64-
bit.

Dimiter "malkia" Stanev

unread,
Dec 2, 2009, 11:39:01 AM12/2/09
to golang-nuts
You can compile it with this Makefile:

# Makefile for go.go

all: install

include $(GOROOT)/src/Make.$(GOARCH)

TARG = go
GOFILES = $(TARG).go

include $(GOROOT)/src/Make.cmd

simonced

unread,
Dec 3, 2009, 9:29:14 AM12/3/09
to golang-nuts
Thank you very much.
It's working well, but I could not use the Makefile.
I don't use make anyway....

I'm testing a bit the language now and I'd like to know, if it's
possible to add a a trace-back at compilation in case of error.
I mean when I launch
$ sample_go_runner test
, if my code test.go has an error, I Don't see the line like with the
command :
$ 8g test.go

Thank you for your feedback.

Dimiter "malkia" Stanev

unread,
Dec 3, 2009, 12:29:43 PM12/3/09
to golang-nuts
Yup, it's buggy yet :)

I'm gonna work on fixing that one. Honestly I now realize the runner
is going to work only for projects written in specific ways - for
example it won't work if you have more than one file in an user
package - e.g. it would only work if you have 1 to 1 mapping of file
and package.

Dimiter "malkia" Stanev

unread,
Dec 10, 2009, 5:21:33 PM12/10/09
to golang-nuts
I've update go runner to the latest version.

http://github.com/malkia/go-runner

Compile it using the Makefile (or you can compile it with "go"
itself). Just type for example "go powser1" or "go powser2.go" from
the go tests.

Go runner does not handle cases where you import local .go file that
does not have the same package name as it's filename.

For example it won't work for:

//this is in file sqlerrors.go
package sql
const {
SqlError1 = iota
}

That won't work for go runner because it expects sqlerrors.go to be
from the same package "sqlerrors", not "sql"

That to be said, for small experiments it works fine. Once I have more
time, I'll explore where I can get it working for the case above (with
some heuristics, and checking all source files from the directories
that might be involved).

On Nov 25, 1:45 am, "Dimiter \"malkia\" Stanev" <mal...@gmail.com>
wrote:
Reply all
Reply to author
Forward
0 new messages