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:
parent
f9f196c2a0
commit
03b46849f2
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user