1
0
mirror of https://github.com/golang/go synced 2024-11-22 09:04:42 -07:00

goinstall: preliminary support for cgo packages

Can handle cgo packages now but only if they
do not need to set CGO_LDFLAGS and CGO_CFLAGS.

R=adg, rsc
CC=golang-dev
https://golang.org/cl/3891042
This commit is contained in:
Gustavo Niemeyer 2011-01-11 13:14:48 -05:00 committed by Russ Cox
parent f9f196c2a0
commit 03b46849f2
3 changed files with 106 additions and 33 deletions

View File

@ -174,28 +174,25 @@ func install(pkg, parent string) {
} }
// Install prerequisites. // Install prerequisites.
files, m, pkgname, err := goFiles(dir, parent == "") dirInfo, err := scanDir(dir, parent == "")
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "%s: %s: %s\n", argv0, pkg, err) fmt.Fprintf(os.Stderr, "%s: %s: %s\n", argv0, pkg, err)
errors = true errors = true
visit[pkg] = done visit[pkg] = done
return return
} }
if len(files) == 0 { if len(dirInfo.goFiles) == 0 {
fmt.Fprintf(os.Stderr, "%s: %s: package has no files\n", argv0, pkg) fmt.Fprintf(os.Stderr, "%s: %s: package has no files\n", argv0, pkg)
errors = true errors = true
visit[pkg] = done visit[pkg] = done
return return
} }
for p := range m { for _, p := range dirInfo.imports {
if p == "C" { if p != "C" {
fmt.Fprintf(os.Stderr, "%s: %s: cgo packages are not supported yet. Try installing manually.\n", argv0, pkg) install(p, pkg)
errors = true
return
} }
install(p, pkg)
} }
if pkgname == "main" { if dirInfo.pkgName == "main" {
if !errors { if !errors {
fmt.Fprintf(os.Stderr, "%s: %s's dependencies are installed.\n", argv0, pkg) fmt.Fprintf(os.Stderr, "%s: %s's dependencies are installed.\n", argv0, pkg)
} }

View File

@ -44,12 +44,38 @@ func domake(dir, pkg string, local bool) (err os.Error) {
// installing as package pkg. It includes all *.go files in the directory // installing as package pkg. It includes all *.go files in the directory
// except those in package main and those ending in _test.go. // except those in package main and those ending in _test.go.
func makeMakefile(dir, pkg string) ([]byte, os.Error) { func makeMakefile(dir, pkg string) ([]byte, os.Error) {
files, _, _, err := goFiles(dir, false) dirInfo, err := scanDir(dir, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(dirInfo.cgoFiles) == 0 && len(dirInfo.cFiles) > 0 {
// When using cgo, .c files are compiled with gcc. Without cgo,
// they may be intended for 6c. Just error out for now.
return nil, os.ErrorString("C files found in non-cgo package")
}
cgoFiles := dirInfo.cgoFiles
isCgo := make(map[string]bool, len(cgoFiles))
for _, file := range cgoFiles {
isCgo[file] = true
}
oFiles := make([]string, 0, len(dirInfo.cFiles))
for _, file := range dirInfo.cFiles {
oFiles = append(oFiles, file[:len(file)-2]+".o")
}
goFiles := make([]string, 0, len(dirInfo.goFiles))
for _, file := range dirInfo.goFiles {
if !isCgo[file] {
goFiles = append(goFiles, file)
}
}
var buf bytes.Buffer var buf bytes.Buffer
if err := makefileTemplate.Execute(&makedata{pkg, files}, &buf); err != nil { md := makedata{pkg, goFiles, cgoFiles, oFiles}
if err := makefileTemplate.Execute(&md, &buf); err != nil {
return nil, err return nil, err
} }
return buf.Bytes(), nil return buf.Bytes(), nil
@ -57,19 +83,38 @@ func makeMakefile(dir, pkg string) ([]byte, os.Error) {
// makedata is the data type for the makefileTemplate. // makedata is the data type for the makefileTemplate.
type makedata struct { type makedata struct {
pkg string // package import path pkg string // package import path
files []string // list of .go files goFiles []string // list of non-cgo .go files
cgoFiles []string // list of cgo .go files
oFiles []string // list of ofiles for cgo
} }
var makefileTemplate = template.MustParse(` var makefileTemplate = template.MustParse(`
include $(GOROOT)/src/Make.inc include $(GOROOT)/src/Make.inc
TARG={pkg} TARG={pkg}
{.section goFiles}
GOFILES=\ GOFILES=\
{.repeated section files} {.repeated section goFiles}
{@}\ {@}\
{.end} {.end}
{.end}
{.section cgoFiles}
CGOFILES=\
{.repeated section cgoFiles}
{@}\
{.end}
{.end}
{.section oFiles}
CGO_OFILES=\
{.repeated section oFiles}
{@}\
{.end}
{.end}
include $(GOROOT)/src/Make.pkg include $(GOROOT)/src/Make.pkg
`, `,
nil) nil)

View File

@ -16,34 +16,58 @@ import (
"go/parser" "go/parser"
) )
// goFiles returns a list of the *.go source files in dir, excluding
// those in package main (unless allowMain is true) or ending in type dirInfo struct {
// _test.go. It also returns a map giving the packages imported by goFiles []string // .go files within dir (including cgoFiles)
// those files, and the package name. cgoFiles []string // .go files that import "C"
// The map keys are the imported paths. The key's value cFiles []string // .c files within dir
// is one file that imports that path. imports []string // All packages imported by goFiles
func goFiles(dir string, allowMain bool) (files []string, imports map[string]string, pkgName string, err os.Error) { pkgName string // Name of package within dir
}
// scanDir returns a structure with details about the Go content found
// in the given directory. The list of files will NOT contain the
// following entries:
//
// - Files in package main (unless allowMain is true)
// - Files ending in _test.go
// - Files starting with _ (temporary)
// - Files containing .cgo in their names
//
// The imports map keys are package paths imported by listed Go files,
// and the values are the Go files importing the respective package paths.
func scanDir(dir string, allowMain bool) (info *dirInfo, err os.Error) {
f, err := os.Open(dir, os.O_RDONLY, 0) f, err := os.Open(dir, os.O_RDONLY, 0)
if err != nil { if err != nil {
return nil, nil, "", err return nil, err
} }
dirs, err := f.Readdir(-1) dirs, err := f.Readdir(-1)
f.Close() f.Close()
if err != nil { if err != nil {
return nil, nil, "", err return nil, err
} }
files = make([]string, 0, len(dirs)) goFiles := make([]string, 0, len(dirs))
imports = make(map[string]string) cgoFiles := make([]string, 0, len(dirs))
cFiles := make([]string, 0, len(dirs))
importsm := make(map[string]bool)
pkgName := ""
for i := range dirs { for i := range dirs {
d := &dirs[i] d := &dirs[i]
if strings.HasPrefix(d.Name, "_") || strings.Index(d.Name, ".cgo") != -1 {
continue
}
if strings.HasSuffix(d.Name, ".c") {
cFiles = append(cFiles, d.Name)
continue
}
if !strings.HasSuffix(d.Name, ".go") || strings.HasSuffix(d.Name, "_test.go") { if !strings.HasSuffix(d.Name, ".go") || strings.HasSuffix(d.Name, "_test.go") {
continue continue
} }
filename := path.Join(dir, d.Name) filename := path.Join(dir, d.Name)
pf, err := parser.ParseFile(fset, filename, nil, parser.ImportsOnly) pf, err := parser.ParseFile(fset, filename, nil, parser.ImportsOnly)
if err != nil { if err != nil {
return nil, nil, "", err return nil, err
} }
s := string(pf.Name.Name) s := string(pf.Name.Name)
if s == "main" && !allowMain { if s == "main" && !allowMain {
@ -57,13 +81,11 @@ func goFiles(dir string, allowMain bool) (files []string, imports map[string]str
// A mix of main and another package reverts // A mix of main and another package reverts
// to the original (allowMain=false) behaviour. // to the original (allowMain=false) behaviour.
if s == "main" || pkgName == "main" { if s == "main" || pkgName == "main" {
return goFiles(dir, false) return scanDir(dir, false)
} }
return nil, nil, "", os.ErrorString("multiple package names in " + dir) return nil, os.ErrorString("multiple package names in " + dir)
} }
n := len(files) goFiles = append(goFiles, d.Name)
files = files[0 : n+1]
files[n] = filename
for _, decl := range pf.Decls { for _, decl := range pf.Decls {
for _, spec := range decl.(*ast.GenDecl).Specs { for _, spec := range decl.(*ast.GenDecl).Specs {
quoted := string(spec.(*ast.ImportSpec).Path.Value) quoted := string(spec.(*ast.ImportSpec).Path.Value)
@ -71,9 +93,18 @@ func goFiles(dir string, allowMain bool) (files []string, imports map[string]str
if err != nil { if err != nil {
log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted) log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
} }
imports[unquoted] = filename importsm[unquoted] = true
if unquoted == "C" {
cgoFiles = append(cgoFiles, d.Name)
}
} }
} }
} }
return files, imports, pkgName, nil imports := make([]string, len(importsm))
i := 0
for p := range importsm {
imports[i] = p
i++
}
return &dirInfo{goFiles, cgoFiles, cFiles, imports, pkgName}, nil
} }