TARG:=$(TARG).exe
endif
+ifeq ($(TARGDIR),)
+TARGDIR:=$(QUOTED_GOBIN)
+endif
+
all: $(TARG)
include $(QUOTED_GOROOT)/src/Make.common
PREREQ+=$(patsubst %,%.make,$(DEPS))
$(TARG): _go_.$O
- $(LD) -o $@ _go_.$O
+ $(LD) $(LDIMPORTS) -o $@ _go_.$O
_go_.$O: $(GOFILES) $(PREREQ)
- $(GC) -o $@ $(GOFILES)
+ $(GC) $(GCIMPORTS) -o $@ $(GOFILES)
-install: $(QUOTED_GOBIN)/$(TARG)
+install: $(TARGDIR)/$(TARG)
-$(QUOTED_GOBIN)/$(TARG): $(TARG)
- cp -f $(TARG) $(QUOTED_GOBIN)
+$(TARGDIR)/$(TARG): $(TARG)
+ cp -f $(TARG) $(TARGDIR)
CLEANFILES+=$(TARG) _test _testmain.go
nuke: clean
- rm -f $(QUOTED_GOBIN)/$(TARG)
+ rm -f $(TARGDIR)/$(TARG)
# for gotest
testpackage: _test/main.a
gopack grc $@ _gotest_.$O
_gotest_.$O: $(GOFILES) $(GOTESTFILES)
- $(GC) -o $@ $(GOFILES) $(GOTESTFILES)
+ $(GC) $(GCIMPORTS) -o $@ $(GOFILES) $(GOTESTFILES)
importpath:
echo main
pkgdir=$(QUOTED_GOROOT)/pkg/$(GOOS)_$(GOARCH)
-INSTALLFILES+=$(pkgdir)/$(TARG).a
+ifeq ($(TARGDIR),)
+TARGDIR:=$(pkgdir)
+endif
+
+INSTALLFILES+=$(TARGDIR)/$(TARG).a
# The rest of the cgo rules are below, but these variable updates
# must be done here so they apply to the main rules.
OFILES+=$(patsubst %.swig,_obj/%_gc.$O,$(patsubst %.swigcxx,%.swig,$(SWIGFILES)))
SWIG_PREFIX=$(subst /,-,$(TARG))
SWIG_SOS+=$(patsubst %.swig,_obj/$(SWIG_PREFIX)-%.so,$(patsubst %.swigcxx,%.swig,$(SWIGFILES)))
-INSTALLFILES+=$(patsubst %.swig,$(pkgdir)/swig/$(SWIG_PREFIX)-%.so,$(patsubst %.swigcxx,%.swig,$(SWIGFILES)))
+INSTALLFILES+=$(patsubst %.swig,$(TARGDIR)/swig/$(SWIG_PREFIX)-%.so,$(patsubst %.swigcxx,%.swig,$(SWIGFILES)))
endif
PREREQ+=$(patsubst %,%.make,$(DEPS))
gotest -test.bench=. -test.run="Do not run tests"
nuke: clean
- rm -f $(pkgdir)/$(TARG).a
+ rm -f $(TARGDIR)/$(TARG).a
testpackage-clean:
rm -f _test/$(TARG).a
install: $(INSTALLFILES)
-$(pkgdir)/$(TARG).a: _obj/$(TARG).a
- @test -d $(QUOTED_GOROOT)/pkg && mkdir -p $(pkgdir)/$(dir)
+$(TARGDIR)/$(TARG).a: _obj/$(TARG).a
+ @test -d $(QUOTED_GOROOT)/pkg && mkdir -p $(TARGDIR)/$(dir)
cp _obj/$(TARG).a "$@"
_go_.$O: $(GOFILES) $(PREREQ)
- $(GC) -o $@ $(GOFILES)
+ $(GC) $(GCIMPORTS) -o $@ $(GOFILES)
_gotest_.$O: $(GOFILES) $(GOTESTFILES) $(PREREQ)
- $(GC) -o $@ $(GOFILES) $(GOTESTFILES)
+ $(GC) $(GCIMPORTS) -o $@ $(GOFILES) $(GOTESTFILES)
_obj/$(TARG).a: _go_.$O $(OFILES)
@mkdir -p _obj/$(dir)
_obj/$(SWIG_PREFIX)-%.so: _obj/%_wrapcxx.o
$(HOST_CXX) $(_CGO_CFLAGS_$(GOARCH)) -o $@ $^ $(SWIG_LDFLAGS) $(_CGO_LDFLAGS_$(GOOS)) $(_SWIG_LDFLAGS_$(GOOS))
-$(pkgdir)/swig/$(SWIG_PREFIX)-%.so: _obj/$(SWIG_PREFIX)-%.so
- @test -d $(QUOTED_GOROOT)/pkg && mkdir -p $(pkgdir)/swig
+$(TARGDIR)/swig/$(SWIG_PREFIX)-%.so: _obj/$(SWIG_PREFIX)-%.so
+ @test -d $(QUOTED_GOROOT)/pkg && mkdir -p $(TARGDIR)/swig
cp $< "$@"
all: $(SWIG_SOS)
-SWIG_RPATH=-r $(pkgdir)/swig
+SWIG_RPATH=-r $(TARGDIR)/swig
endif
main.go\
make.go\
parse.go\
+ path.go\
syslist.go\
CLEANFILES+=syslist.go
var launchpad = regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`)
// download checks out or updates pkg from the remote server.
-func download(pkg string) (string, os.Error) {
+func download(pkg, srcDir string) os.Error {
if strings.Contains(pkg, "..") {
- return "", os.ErrorString("invalid path (contains ..)")
+ return os.ErrorString("invalid path (contains ..)")
}
if m := bitbucket.FindStringSubmatch(pkg); m != nil {
- if err := vcsCheckout(&hg, m[1], "http://"+m[1], m[1]); err != nil {
- return "", err
+ if err := vcsCheckout(&hg, srcDir, m[1], "http://"+m[1], m[1]); err != nil {
+ return err
}
- return root + pkg, nil
+ return nil
}
if m := googlecode.FindStringSubmatch(pkg); m != nil {
var v *vcs
// regexp only allows hg, svn to get through
panic("missing case in download: " + pkg)
}
- if err := vcsCheckout(v, m[1], "https://"+m[1], m[1]); err != nil {
- return "", err
+ if err := vcsCheckout(v, srcDir, m[1], "https://"+m[1], m[1]); err != nil {
+ return err
}
- return root + pkg, nil
+ return nil
}
if m := github.FindStringSubmatch(pkg); m != nil {
if strings.HasSuffix(m[1], ".git") {
- return "", os.ErrorString("repository " + pkg + " should not have .git suffix")
+ return os.ErrorString("repository " + pkg + " should not have .git suffix")
}
- if err := vcsCheckout(&git, m[1], "http://"+m[1]+".git", m[1]); err != nil {
- return "", err
+ if err := vcsCheckout(&git, srcDir, m[1], "http://"+m[1]+".git", m[1]); err != nil {
+ return err
}
- return root + pkg, nil
+ return nil
}
if m := launchpad.FindStringSubmatch(pkg); m != nil {
// Either lp.net/<project>[/<series>[/<path>]]
// or lp.net/~<user or team>/<project>/<branch>[/<path>]
- if err := vcsCheckout(&bzr, m[1], "https://"+m[1], m[1]); err != nil {
- return "", err
+ if err := vcsCheckout(&bzr, srcDir, m[1], "https://"+m[1], m[1]); err != nil {
+ return err
}
- return root + pkg, nil
+ return nil
}
- return "", os.ErrorString("unknown repository: " + pkg)
+ return os.ErrorString("unknown repository: " + pkg)
}
// a vcs represents a version control system
// exists and -u was specified on the command line)
// the repository at tag/branch "release". If there is no
// such tag or branch, it falls back to the repository tip.
-func vcsCheckout(vcs *vcs, pkgprefix, repo, dashpath string) os.Error {
- dst := filepath.Join(root, filepath.FromSlash(pkgprefix))
+func vcsCheckout(vcs *vcs, srcDir, pkgprefix, repo, dashpath string) os.Error {
+ dst := filepath.Join(srcDir, filepath.FromSlash(pkgprefix))
dir, err := os.Stat(filepath.Join(dst, vcs.metadir))
if err == nil && !dir.IsDirectory() {
return os.ErrorString("not a directory: " + dst)
// Check whether package is local or remote.
// If remote, download or update it.
var dir string
+ proot := gopath[0] // default to GOROOT
local := false
if strings.HasPrefix(pkg, "http://") {
fmt.Fprintf(os.Stderr, "%s: %s: 'http://' used in remote path, try '%s'\n", argv0, pkg, pkg[7:])
dir = filepath.Join(root, filepath.FromSlash(pkg))
local = true
} else {
- var err os.Error
- dir, err = download(pkg)
+ proot = findPkgroot(pkg)
+ err := download(pkg, proot.srcDir())
+ dir = filepath.Join(proot.srcDir(), pkg)
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %s: %s\n", argv0, pkg, err)
errors = true
// Install this package.
if !errors {
isCmd := dirInfo.pkgName == "main"
- if err := domake(dir, pkg, local, isCmd); err != nil {
+ if err := domake(dir, pkg, proot, local, isCmd); err != nil {
fmt.Fprintf(os.Stderr, "%s: installing %s: %s\n", argv0, pkg, err)
errors = true
} else if !local && *logPkgs {
// For non-local packages or packages without Makefiles,
// domake generates a standard Makefile and passes it
// to make on standard input.
-func domake(dir, pkg string, local, isCmd bool) (err os.Error) {
+func domake(dir, pkg string, root *pkgroot, local, isCmd bool) (err os.Error) {
needMakefile := true
if local {
_, err := os.Stat(dir + "/Makefile")
cmd := []string{"gomake"}
var makefile []byte
if needMakefile {
- if makefile, err = makeMakefile(dir, pkg, isCmd); err != nil {
+ if makefile, err = makeMakefile(dir, pkg, root, isCmd); err != nil {
return err
}
cmd = append(cmd, "-f-")
// makeMakefile computes the standard Makefile for the directory dir
// installing as package pkg. It includes all *.go files in the directory
// except those in package main and those ending in _test.go.
-func makeMakefile(dir, pkg string, isCmd bool) ([]byte, os.Error) {
+func makeMakefile(dir, pkg string, root *pkgroot, isCmd bool) ([]byte, os.Error) {
+ if !safeName(pkg) {
+ return nil, os.ErrorString("unsafe name: " + pkg)
+ }
targ := pkg
+ targDir := root.pkgDir()
if isCmd {
// use the last part of the package name only
_, targ = filepath.Split(pkg)
}
_, targ = filepath.Split(d)
}
- }
- if !safeName(targ) {
- return nil, os.ErrorString("unsafe name: " + pkg)
+ targDir = root.binDir()
}
dirInfo, err := scanDir(dir, isCmd)
if err != nil {
}
var buf bytes.Buffer
- md := makedata{targ, "pkg", goFiles, oFiles, cgoFiles, cgoOFiles}
+ md := makedata{targ, targDir, "pkg", goFiles, oFiles, cgoFiles, cgoOFiles, imports}
if isCmd {
md.Type = "cmd"
}
var safeBytes = []byte("+-./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")
func safeName(s string) bool {
- if len(s) == 0 {
+ if s == "" {
return false
}
for i := 0; i < len(s); i++ {
// makedata is the data type for the makefileTemplate.
type makedata struct {
Targ string // build target
+ TargDir string // build target directory
Type string // build type: "pkg" or "cmd"
GoFiles []string // list of non-cgo .go files
OFiles []string // list of .$O files
CgoFiles []string // list of cgo .go files
CgoOFiles []string // list of cgo .o files, without extension
+ Imports []string // gc/ld import paths
}
var makefileTemplate = template.MustParse(`
include $(GOROOT)/src/Make.inc
TARG={Targ}
+TARGDIR={TargDir}
{.section GoFiles}
GOFILES=\
{.end}
{.end}
+GCIMPORTS={.repeated section Imports}-I "{@}" {.end}
+LDIMPORTS={.repeated section Imports}-L "{@}" {.end}
+
include $(GOROOT)/src/Make.{Type}
`,
nil)
if s == "main" && !allowMain {
continue
}
+ if s == "documentation" {
+ continue
+ }
if pkgName == "" {
pkgName = s
} else if pkgName != s {
--- /dev/null
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "log"
+ "os"
+ "path/filepath"
+ "runtime"
+)
+
+var (
+ gopath []*pkgroot
+ imports []string
+ defaultRoot *pkgroot // default root for remote packages
+)
+
+// set up gopath: parse and validate GOROOT and GOPATH variables
+func init() {
+ p, err := newPkgroot(root)
+ if err != nil {
+ log.Fatalf("Invalid GOROOT %q: %v", root, err)
+ }
+ p.goroot = true
+ gopath = []*pkgroot{p}
+
+ for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
+ if p == "" {
+ continue
+ }
+ r, err := newPkgroot(p)
+ if err != nil {
+ log.Printf("Invalid GOPATH %q: %v", p, err)
+ continue
+ }
+ gopath = append(gopath, r)
+ imports = append(imports, r.pkgDir())
+
+ // select first GOPATH entry as default
+ if defaultRoot == nil {
+ defaultRoot = r
+ }
+ }
+
+ // use GOROOT if no valid GOPATH specified
+ if defaultRoot == nil {
+ defaultRoot = gopath[0]
+ }
+}
+
+type pkgroot struct {
+ path string
+ goroot bool // TODO(adg): remove this once Go tree re-organized
+}
+
+func newPkgroot(p string) (*pkgroot, os.Error) {
+ if !filepath.IsAbs(p) {
+ return nil, os.NewError("must be absolute")
+ }
+ ep, err := filepath.EvalSymlinks(p)
+ if err != nil {
+ return nil, err
+ }
+ return &pkgroot{path: ep}, nil
+}
+
+func (r *pkgroot) srcDir() string {
+ if r.goroot {
+ return filepath.Join(r.path, "src", "pkg")
+ }
+ return filepath.Join(r.path, "src")
+}
+
+func (r *pkgroot) pkgDir() string {
+ goos, goarch := runtime.GOOS, runtime.GOARCH
+ if e := os.Getenv("GOOS"); e != "" {
+ goos = e
+ }
+ if e := os.Getenv("GOARCH"); e != "" {
+ goarch = e
+ }
+ return filepath.Join(r.path, "pkg", goos+"_"+goarch)
+}
+
+func (r *pkgroot) binDir() string {
+ return filepath.Join(r.path, "bin")
+}
+
+func (r *pkgroot) hasSrcDir(name string) bool {
+ fi, err := os.Stat(filepath.Join(r.srcDir(), name))
+ if err != nil {
+ return false
+ }
+ return fi.IsDirectory()
+}
+
+func (r *pkgroot) hasPkg(name string) bool {
+ fi, err := os.Stat(filepath.Join(r.pkgDir(), name+".a"))
+ if err != nil {
+ return false
+ }
+ return fi.IsRegular()
+ // TODO(adg): check object version is consistent
+}
+
+// findPkgroot searches each of the gopath roots
+// for the source code for the given import path.
+func findPkgroot(importPath string) *pkgroot {
+ for _, r := range gopath {
+ if r.hasSrcDir(importPath) {
+ return r
+ }
+ }
+ return defaultRoot
+}