forked from OSchip/llvm-project
Roll gofrontend to a6e10414311a
This takes us to Go 1.4. Also includes a couple of changes to the test suite, both in the runtime package: - Disable TestSetPanicOnFault. We cannot support this scenario at all, due to LLVM's lack of non-call exceptions. - Tweak TestFinalizerType. This test only passes with two GC runs. Differential Revision: http://reviews.llvm.org/D8828 llvm-svn: 234134
This commit is contained in:
parent
7d39641c80
commit
93c73ebcbd
llgo
CMakeLists.txt
irgen
libgo-check-failures.difflibgo-noext.diffthird_party/gofrontend/libgo
MERGEMakefile.amMakefile.inconfig.h.inconfigureconfigure.ac
go
archive
bufio
bytes
cmd
cgo
go
build.godoc.gogenerate.gogenerate_test.goget.gogo_windows_test.gohelp.golist.gomain.gopkg.gotest.gotestflag.gotestgo.gotool.govcs.govcs_test.govet.go
testdata
generate
importcom
norunexample
src
testinternal
testinternal2
gofmt
doc.gogofmt.gogofmt_test.golong_test.gorewrite.gosimplify.go
testdata
composites.goldencomposites.inputcrlf.goldencrlf.inputrewrite1.goldenrewrite1.inputrewrite2.goldenrewrite2.inputrewrite3.goldenrewrite3.inputrewrite4.goldenrewrite4.inputrewrite5.goldenrewrite5.inputrewrite6.goldenrewrite6.inputrewrite7.goldenrewrite7.inputrewrite8.goldenrewrite8.inputslices1.goldenslices1.inputslices2.golden
|
@ -56,6 +56,7 @@ set(LLGO_GO_SOURCES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/env.go
|
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/env.go
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/fix.go
|
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/fix.go
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/fmt.go
|
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/fmt.go
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/generate.go
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/get.go
|
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/get.go
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/go11.go
|
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/go11.go
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/help.go
|
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/help.go
|
||||||
|
|
|
@ -1600,6 +1600,7 @@ const (
|
||||||
gccgoRuntimeTypeKindSTRING = 24
|
gccgoRuntimeTypeKindSTRING = 24
|
||||||
gccgoRuntimeTypeKindSTRUCT = 25
|
gccgoRuntimeTypeKindSTRUCT = 25
|
||||||
gccgoRuntimeTypeKindUNSAFE_POINTER = 26
|
gccgoRuntimeTypeKindUNSAFE_POINTER = 26
|
||||||
|
gccgoRuntimeTypeKindDIRECT_IFACE = (1 << 5)
|
||||||
gccgoRuntimeTypeKindNO_POINTERS = (1 << 7)
|
gccgoRuntimeTypeKindNO_POINTERS = (1 << 7)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1669,7 +1670,7 @@ func runtimeTypeKind(t types.Type) (k uint8) {
|
||||||
case types.String:
|
case types.String:
|
||||||
k = gccgoRuntimeTypeKindSTRING
|
k = gccgoRuntimeTypeKindSTRING
|
||||||
case types.UnsafePointer:
|
case types.UnsafePointer:
|
||||||
k = gccgoRuntimeTypeKindUNSAFE_POINTER
|
k = gccgoRuntimeTypeKindUNSAFE_POINTER | gccgoRuntimeTypeKindDIRECT_IFACE
|
||||||
default:
|
default:
|
||||||
panic("unrecognized builtin type")
|
panic("unrecognized builtin type")
|
||||||
}
|
}
|
||||||
|
@ -1680,7 +1681,7 @@ func runtimeTypeKind(t types.Type) (k uint8) {
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
k = gccgoRuntimeTypeKindSTRUCT
|
k = gccgoRuntimeTypeKindSTRUCT
|
||||||
case *types.Pointer:
|
case *types.Pointer:
|
||||||
k = gccgoRuntimeTypeKindPTR
|
k = gccgoRuntimeTypeKindPTR | gccgoRuntimeTypeKindDIRECT_IFACE
|
||||||
case *types.Signature:
|
case *types.Signature:
|
||||||
k = gccgoRuntimeTypeKindFUNC
|
k = gccgoRuntimeTypeKindFUNC
|
||||||
case *types.Interface:
|
case *types.Interface:
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
package irgen
|
package irgen
|
||||||
|
|
||||||
const (
|
const (
|
||||||
goVersion = "go1.3"
|
goVersion = "go1.4"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GoVersion returns the version of Go that we are targeting.
|
// GoVersion returns the version of Go that we are targeting.
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
|
diff -r a6e10414311a libgo/Makefile.am
|
||||||
index 526b656..31c206e 100644
|
--- a/libgo/Makefile.am Fri Jan 16 07:57:02 2015 -0800
|
||||||
--- a/libgo/Makefile.am
|
+++ b/libgo/Makefile.am Fri Apr 03 15:07:47 2015 -0700
|
||||||
+++ b/libgo/Makefile.am
|
@@ -3738,7 +3738,6 @@
|
||||||
@@ -3688,7 +3688,6 @@ TEST_PACKAGES = \
|
|
||||||
os/check \
|
os/check \
|
||||||
path/check \
|
path/check \
|
||||||
reflect/check \
|
reflect/check \
|
||||||
|
@ -10,7 +9,7 @@ index 526b656..31c206e 100644
|
||||||
runtime/check \
|
runtime/check \
|
||||||
sort/check \
|
sort/check \
|
||||||
strconv/check \
|
strconv/check \
|
||||||
@@ -3787,7 +3786,6 @@ TEST_PACKAGES = \
|
@@ -3838,7 +3837,6 @@
|
||||||
os/user/check \
|
os/user/check \
|
||||||
path/filepath/check \
|
path/filepath/check \
|
||||||
regexp/syntax/check \
|
regexp/syntax/check \
|
||||||
|
@ -18,11 +17,10 @@ index 526b656..31c206e 100644
|
||||||
sync/atomic/check \
|
sync/atomic/check \
|
||||||
text/scanner/check \
|
text/scanner/check \
|
||||||
text/tabwriter/check \
|
text/tabwriter/check \
|
||||||
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
|
diff -r a6e10414311a libgo/Makefile.in
|
||||||
index 2254478..d2482d1 100644
|
--- a/libgo/Makefile.in Fri Jan 16 07:57:02 2015 -0800
|
||||||
--- a/libgo/Makefile.in
|
+++ b/libgo/Makefile.in Fri Apr 03 15:07:47 2015 -0700
|
||||||
+++ b/libgo/Makefile.in
|
@@ -2212,7 +2212,6 @@
|
||||||
@@ -2193,7 +2193,6 @@ TEST_PACKAGES = \
|
|
||||||
os/check \
|
os/check \
|
||||||
path/check \
|
path/check \
|
||||||
reflect/check \
|
reflect/check \
|
||||||
|
@ -30,7 +28,7 @@ index 2254478..d2482d1 100644
|
||||||
runtime/check \
|
runtime/check \
|
||||||
sort/check \
|
sort/check \
|
||||||
strconv/check \
|
strconv/check \
|
||||||
@@ -2292,7 +2291,6 @@ TEST_PACKAGES = \
|
@@ -2312,7 +2311,6 @@
|
||||||
os/user/check \
|
os/user/check \
|
||||||
path/filepath/check \
|
path/filepath/check \
|
||||||
regexp/syntax/check \
|
regexp/syntax/check \
|
||||||
|
@ -38,3 +36,26 @@ index 2254478..d2482d1 100644
|
||||||
sync/atomic/check \
|
sync/atomic/check \
|
||||||
text/scanner/check \
|
text/scanner/check \
|
||||||
text/tabwriter/check \
|
text/tabwriter/check \
|
||||||
|
diff -r a6e10414311a libgo/go/runtime/mfinal_test.go
|
||||||
|
--- a/libgo/go/runtime/mfinal_test.go Fri Jan 16 07:57:02 2015 -0800
|
||||||
|
+++ b/libgo/go/runtime/mfinal_test.go Fri Apr 03 15:07:47 2015 -0700
|
||||||
|
@@ -62,6 +62,7 @@
|
||||||
|
}()
|
||||||
|
<-done
|
||||||
|
runtime.GC()
|
||||||
|
+ runtime.GC()
|
||||||
|
select {
|
||||||
|
case <-ch:
|
||||||
|
case <-time.After(time.Second * 4):
|
||||||
|
diff -r a6e10414311a libgo/go/runtime/runtime_test.go
|
||||||
|
--- a/libgo/go/runtime/runtime_test.go Fri Jan 16 07:57:02 2015 -0800
|
||||||
|
+++ b/libgo/go/runtime/runtime_test.go Fri Apr 03 15:07:47 2015 -0700
|
||||||
|
@@ -176,6 +176,8 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetPanicOnFault(t *testing.T) {
|
||||||
|
+ t.Skip("skipping for llgo due to lack of non-call exception support")
|
||||||
|
+
|
||||||
|
// This currently results in a fault in the signal trampoline on
|
||||||
|
// dragonfly/386 - see issue 7421.
|
||||||
|
if GOOS == "dragonfly" && GOARCH == "386" {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/chan.goc
|
diff -r a6e10414311a libgo/runtime/chan.goc
|
||||||
--- a/libgo/runtime/chan.goc Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/chan.goc Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/chan.goc Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/chan.goc Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -111,7 +111,7 @@
|
@@ -111,7 +111,7 @@
|
||||||
mysg.releasetime = -1;
|
mysg.releasetime = -1;
|
||||||
}
|
}
|
||||||
|
@ -207,9 +207,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/chan.goc
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/chan.h
|
diff -r a6e10414311a libgo/runtime/chan.h
|
||||||
--- a/libgo/runtime/chan.h Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/chan.h Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/chan.h Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/chan.h Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -39,7 +39,7 @@
|
@@ -39,7 +39,7 @@
|
||||||
uintgo recvx; // receive index
|
uintgo recvx; // receive index
|
||||||
WaitQ recvq; // list of recv waiters
|
WaitQ recvq; // list of recv waiters
|
||||||
|
@ -219,9 +219,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/chan.h
|
||||||
};
|
};
|
||||||
|
|
||||||
// Buffer follows Hchan immediately in memory.
|
// Buffer follows Hchan immediately in memory.
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/heapdump.c
|
diff -r a6e10414311a libgo/runtime/heapdump.c
|
||||||
--- a/libgo/runtime/heapdump.c Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/heapdump.c Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/heapdump.c Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/heapdump.c Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -387,7 +387,7 @@
|
@@ -387,7 +387,7 @@
|
||||||
if(sp->kind != KindSpecialFinalizer)
|
if(sp->kind != KindSpecialFinalizer)
|
||||||
continue;
|
continue;
|
||||||
|
@ -240,10 +240,10 @@ diff -r 0fde0b6a7eb2 libgo/runtime/heapdump.c
|
||||||
dumpint(TagAllocSample);
|
dumpint(TagAllocSample);
|
||||||
dumpint((uintptr)p);
|
dumpint((uintptr)p);
|
||||||
dumpint((uintptr)spp->b);
|
dumpint((uintptr)spp->b);
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/malloc.goc
|
diff -r a6e10414311a libgo/runtime/malloc.goc
|
||||||
--- a/libgo/runtime/malloc.goc Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/malloc.goc Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/malloc.goc Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/malloc.goc Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -436,9 +436,9 @@
|
@@ -437,9 +437,9 @@
|
||||||
m->mcache->local_nlookup++;
|
m->mcache->local_nlookup++;
|
||||||
if (sizeof(void*) == 4 && m->mcache->local_nlookup >= (1<<30)) {
|
if (sizeof(void*) == 4 && m->mcache->local_nlookup >= (1<<30)) {
|
||||||
// purge cache stats to prevent overflow
|
// purge cache stats to prevent overflow
|
||||||
|
@ -255,7 +255,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/malloc.goc
|
||||||
}
|
}
|
||||||
|
|
||||||
s = runtime_MHeap_LookupMaybe(&runtime_mheap, v);
|
s = runtime_MHeap_LookupMaybe(&runtime_mheap, v);
|
||||||
@@ -735,7 +735,7 @@
|
@@ -736,7 +736,7 @@
|
||||||
|
|
||||||
static struct
|
static struct
|
||||||
{
|
{
|
||||||
|
@ -264,7 +264,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/malloc.goc
|
||||||
byte* pos;
|
byte* pos;
|
||||||
byte* end;
|
byte* end;
|
||||||
} persistent;
|
} persistent;
|
||||||
@@ -764,19 +764,19 @@
|
@@ -765,19 +765,19 @@
|
||||||
align = 8;
|
align = 8;
|
||||||
if(size >= PersistentAllocMaxBlock)
|
if(size >= PersistentAllocMaxBlock)
|
||||||
return runtime_SysAlloc(size, stat);
|
return runtime_SysAlloc(size, stat);
|
||||||
|
@ -287,9 +287,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/malloc.goc
|
||||||
if(stat != &mstats.other_sys) {
|
if(stat != &mstats.other_sys) {
|
||||||
// reaccount the allocation against provided stat
|
// reaccount the allocation against provided stat
|
||||||
runtime_xadd64(stat, size);
|
runtime_xadd64(stat, size);
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/malloc.h
|
diff -r a6e10414311a libgo/runtime/malloc.h
|
||||||
--- a/libgo/runtime/malloc.h Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/malloc.h Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/malloc.h Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/malloc.h Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -390,7 +390,7 @@
|
@@ -390,7 +390,7 @@
|
||||||
typedef struct SpecialFinalizer SpecialFinalizer;
|
typedef struct SpecialFinalizer SpecialFinalizer;
|
||||||
struct SpecialFinalizer
|
struct SpecialFinalizer
|
||||||
|
@ -335,9 +335,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/malloc.h
|
||||||
byte pad[64];
|
byte pad[64];
|
||||||
} central[NumSizeClasses];
|
} central[NumSizeClasses];
|
||||||
|
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/mcache.c
|
diff -r a6e10414311a libgo/runtime/mcache.c
|
||||||
--- a/libgo/runtime/mcache.c Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/mcache.c Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/mcache.c Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/mcache.c Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -23,9 +23,9 @@
|
@@ -23,9 +23,9 @@
|
||||||
MCache *c;
|
MCache *c;
|
||||||
int32 i;
|
int32 i;
|
||||||
|
@ -410,9 +410,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mcache.c
|
||||||
l->list = nil;
|
l->list = nil;
|
||||||
l->nlist = 0;
|
l->nlist = 0;
|
||||||
}
|
}
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/mcentral.c
|
diff -r a6e10414311a libgo/runtime/mcentral.c
|
||||||
--- a/libgo/runtime/mcentral.c Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/mcentral.c Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/mcentral.c Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/mcentral.c Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -39,14 +39,14 @@
|
@@ -39,14 +39,14 @@
|
||||||
int32 cap, n;
|
int32 cap, n;
|
||||||
uint32 sg;
|
uint32 sg;
|
||||||
|
@ -554,10 +554,10 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mcentral.c
|
||||||
runtime_unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
|
runtime_unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
|
||||||
runtime_MHeap_Free(&runtime_mheap, s, 0);
|
runtime_MHeap_Free(&runtime_mheap, s, 0);
|
||||||
}
|
}
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
diff -r a6e10414311a libgo/runtime/mgc0.c
|
||||||
--- a/libgo/runtime/mgc0.c Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/mgc0.c Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/mgc0.c Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/mgc0.c Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -224,7 +224,7 @@
|
@@ -225,7 +225,7 @@
|
||||||
Note alldone;
|
Note alldone;
|
||||||
ParFor *markfor;
|
ParFor *markfor;
|
||||||
|
|
||||||
|
@ -566,7 +566,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
||||||
byte *chunk;
|
byte *chunk;
|
||||||
uintptr nchunk;
|
uintptr nchunk;
|
||||||
} work __attribute__((aligned(8)));
|
} work __attribute__((aligned(8)));
|
||||||
@@ -1336,7 +1336,7 @@
|
@@ -1337,7 +1337,7 @@
|
||||||
// retain everything it points to.
|
// retain everything it points to.
|
||||||
spf = (SpecialFinalizer*)sp;
|
spf = (SpecialFinalizer*)sp;
|
||||||
// A finalizer can be set for an inner byte of an object, find object beginning.
|
// A finalizer can be set for an inner byte of an object, find object beginning.
|
||||||
|
@ -575,7 +575,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
||||||
enqueue1(&wbuf, (Obj){p, s->elemsize, 0});
|
enqueue1(&wbuf, (Obj){p, s->elemsize, 0});
|
||||||
enqueue1(&wbuf, (Obj){(void*)&spf->fn, PtrSize, 0});
|
enqueue1(&wbuf, (Obj){(void*)&spf->fn, PtrSize, 0});
|
||||||
enqueue1(&wbuf, (Obj){(void*)&spf->ft, PtrSize, 0});
|
enqueue1(&wbuf, (Obj){(void*)&spf->ft, PtrSize, 0});
|
||||||
@@ -1377,7 +1377,7 @@
|
@@ -1378,7 +1378,7 @@
|
||||||
b = (Workbuf*)runtime_lfstackpop(&work.empty);
|
b = (Workbuf*)runtime_lfstackpop(&work.empty);
|
||||||
if(b == nil) {
|
if(b == nil) {
|
||||||
// Need to allocate.
|
// Need to allocate.
|
||||||
|
@ -584,7 +584,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
||||||
if(work.nchunk < sizeof *b) {
|
if(work.nchunk < sizeof *b) {
|
||||||
work.nchunk = 1<<20;
|
work.nchunk = 1<<20;
|
||||||
work.chunk = runtime_SysAlloc(work.nchunk, &mstats.gc_sys);
|
work.chunk = runtime_SysAlloc(work.nchunk, &mstats.gc_sys);
|
||||||
@@ -1387,7 +1387,7 @@
|
@@ -1388,7 +1388,7 @@
|
||||||
b = (Workbuf*)work.chunk;
|
b = (Workbuf*)work.chunk;
|
||||||
work.chunk += sizeof *b;
|
work.chunk += sizeof *b;
|
||||||
work.nchunk -= sizeof *b;
|
work.nchunk -= sizeof *b;
|
||||||
|
@ -593,7 +593,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
||||||
}
|
}
|
||||||
b->nobj = 0;
|
b->nobj = 0;
|
||||||
return b;
|
return b;
|
||||||
@@ -1801,7 +1801,7 @@
|
@@ -1802,7 +1802,7 @@
|
||||||
c->local_nsmallfree[cl] += nfree;
|
c->local_nsmallfree[cl] += nfree;
|
||||||
c->local_cachealloc -= nfree * size;
|
c->local_cachealloc -= nfree * size;
|
||||||
runtime_xadd64(&mstats.next_gc, -(uint64)(nfree * size * (gcpercent + 100)/100));
|
runtime_xadd64(&mstats.next_gc, -(uint64)(nfree * size * (gcpercent + 100)/100));
|
||||||
|
@ -602,7 +602,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
||||||
//MCentral_FreeSpan updates sweepgen
|
//MCentral_FreeSpan updates sweepgen
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
@@ -2146,10 +2146,10 @@
|
@@ -2147,10 +2147,10 @@
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(gcpercent == GcpercentUnknown) { // first time through
|
if(gcpercent == GcpercentUnknown) { // first time through
|
||||||
|
@ -615,7 +615,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
||||||
}
|
}
|
||||||
if(gcpercent < 0)
|
if(gcpercent < 0)
|
||||||
return;
|
return;
|
||||||
@@ -2420,7 +2420,7 @@
|
@@ -2423,7 +2423,7 @@
|
||||||
|
|
||||||
// Pass back: pauses, last gc (absolute time), number of gc, total pause ns.
|
// Pass back: pauses, last gc (absolute time), number of gc, total pause ns.
|
||||||
p = (uint64*)pauses->array;
|
p = (uint64*)pauses->array;
|
||||||
|
@ -624,7 +624,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
||||||
n = mstats.numgc;
|
n = mstats.numgc;
|
||||||
if(n > nelem(mstats.pause_ns))
|
if(n > nelem(mstats.pause_ns))
|
||||||
n = nelem(mstats.pause_ns);
|
n = nelem(mstats.pause_ns);
|
||||||
@@ -2435,7 +2435,7 @@
|
@@ -2438,7 +2438,7 @@
|
||||||
p[n] = mstats.last_gc;
|
p[n] = mstats.last_gc;
|
||||||
p[n+1] = mstats.numgc;
|
p[n+1] = mstats.numgc;
|
||||||
p[n+2] = mstats.pause_total_ns;
|
p[n+2] = mstats.pause_total_ns;
|
||||||
|
@ -633,7 +633,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
||||||
pauses->__count = n+3;
|
pauses->__count = n+3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2443,14 +2443,14 @@
|
@@ -2446,14 +2446,14 @@
|
||||||
runtime_setgcpercent(int32 in) {
|
runtime_setgcpercent(int32 in) {
|
||||||
int32 out;
|
int32 out;
|
||||||
|
|
||||||
|
@ -650,9 +650,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/mheap.c
|
diff -r a6e10414311a libgo/runtime/mheap.c
|
||||||
--- a/libgo/runtime/mheap.c Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/mheap.c Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/mheap.c Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/mheap.c Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -70,7 +70,7 @@
|
@@ -70,7 +70,7 @@
|
||||||
runtime_MSpanList_Init(&h->freelarge);
|
runtime_MSpanList_Init(&h->freelarge);
|
||||||
runtime_MSpanList_Init(&h->busylarge);
|
runtime_MSpanList_Init(&h->busylarge);
|
||||||
|
@ -837,9 +837,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mheap.c
|
||||||
+ runtime_unlock(&h->lock);
|
+ runtime_unlock(&h->lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/netpoll.goc
|
diff -r a6e10414311a libgo/runtime/netpoll.goc
|
||||||
--- a/libgo/runtime/netpoll.goc Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/netpoll.goc Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/netpoll.goc Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/netpoll.goc Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -53,7 +53,7 @@
|
@@ -53,7 +53,7 @@
|
||||||
// pollReset, pollWait, pollWaitCanceled and runtime_netpollready (IO rediness notification)
|
// pollReset, pollWait, pollWaitCanceled and runtime_netpollready (IO rediness notification)
|
||||||
// proceed w/o taking the lock. So closing, rg, rd, wg and wd are manipulated
|
// proceed w/o taking the lock. So closing, rg, rd, wg and wd are manipulated
|
||||||
|
@ -901,7 +901,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/netpoll.goc
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pd->seq++; // invalidate current timers
|
pd->seq++; // invalidate current timers
|
||||||
@@ -223,7 +223,7 @@
|
@@ -226,7 +226,7 @@
|
||||||
rg = netpollunblock(pd, 'r', false);
|
rg = netpollunblock(pd, 'r', false);
|
||||||
if(pd->wd < 0)
|
if(pd->wd < 0)
|
||||||
wg = netpollunblock(pd, 'w', false);
|
wg = netpollunblock(pd, 'w', false);
|
||||||
|
@ -910,7 +910,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/netpoll.goc
|
||||||
if(rg)
|
if(rg)
|
||||||
runtime_ready(rg);
|
runtime_ready(rg);
|
||||||
if(wg)
|
if(wg)
|
||||||
@@ -233,7 +233,7 @@
|
@@ -236,7 +236,7 @@
|
||||||
func runtime_pollUnblock(pd *PollDesc) {
|
func runtime_pollUnblock(pd *PollDesc) {
|
||||||
G *rg, *wg;
|
G *rg, *wg;
|
||||||
|
|
||||||
|
@ -919,7 +919,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/netpoll.goc
|
||||||
if(pd->closing)
|
if(pd->closing)
|
||||||
runtime_throw("runtime_pollUnblock: already closing");
|
runtime_throw("runtime_pollUnblock: already closing");
|
||||||
pd->closing = true;
|
pd->closing = true;
|
||||||
@@ -249,7 +249,7 @@
|
@@ -252,7 +252,7 @@
|
||||||
runtime_deltimer(&pd->wt);
|
runtime_deltimer(&pd->wt);
|
||||||
pd->wt.fv = nil;
|
pd->wt.fv = nil;
|
||||||
}
|
}
|
||||||
|
@ -928,7 +928,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/netpoll.goc
|
||||||
if(rg)
|
if(rg)
|
||||||
runtime_ready(rg);
|
runtime_ready(rg);
|
||||||
if(wg)
|
if(wg)
|
||||||
@@ -277,13 +277,13 @@
|
@@ -280,13 +280,13 @@
|
||||||
void
|
void
|
||||||
runtime_netpolllock(PollDesc *pd)
|
runtime_netpolllock(PollDesc *pd)
|
||||||
{
|
{
|
||||||
|
@ -944,12 +944,14 @@ diff -r 0fde0b6a7eb2 libgo/runtime/netpoll.goc
|
||||||
}
|
}
|
||||||
|
|
||||||
// make pd ready, newly runnable goroutines (if any) are enqueued info gpp list
|
// make pd ready, newly runnable goroutines (if any) are enqueued info gpp list
|
||||||
@@ -401,10 +401,10 @@
|
@@ -399,12 +399,12 @@
|
||||||
// If it's stale, ignore the timer event.
|
|
||||||
seq = (uintptr)arg.type;
|
pd = (PollDesc*)arg.data;
|
||||||
rg = wg = nil;
|
rg = wg = nil;
|
||||||
- runtime_lock(pd);
|
- runtime_lock(pd);
|
||||||
+ runtime_lock(&pd->lock);
|
+ runtime_lock(&pd->lock);
|
||||||
|
// Seq arg is seq when the timer was set.
|
||||||
|
// If it's stale, ignore the timer event.
|
||||||
if(seq != pd->seq) {
|
if(seq != pd->seq) {
|
||||||
// The descriptor was reused or timers were reset.
|
// The descriptor was reused or timers were reset.
|
||||||
- runtime_unlock(pd);
|
- runtime_unlock(pd);
|
||||||
|
@ -983,9 +985,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/netpoll.goc
|
||||||
+ runtime_unlock(&pollcache.lock);
|
+ runtime_unlock(&pollcache.lock);
|
||||||
return pd;
|
return pd;
|
||||||
}
|
}
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/proc.c
|
diff -r a6e10414311a libgo/runtime/proc.c
|
||||||
--- a/libgo/runtime/proc.c Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/proc.c Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/proc.c Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/proc.c Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -302,7 +302,7 @@
|
@@ -302,7 +302,7 @@
|
||||||
|
|
||||||
typedef struct Sched Sched;
|
typedef struct Sched Sched;
|
||||||
|
@ -1500,9 +1502,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/proc.c
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/runtime.h
|
diff -r a6e10414311a libgo/runtime/runtime.h
|
||||||
--- a/libgo/runtime/runtime.h Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/runtime.h Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/runtime.h Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/runtime.h Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -286,7 +286,7 @@
|
@@ -286,7 +286,7 @@
|
||||||
|
|
||||||
struct P
|
struct P
|
||||||
|
@ -1521,9 +1523,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/runtime.h
|
||||||
G *timerproc;
|
G *timerproc;
|
||||||
bool sleeping;
|
bool sleeping;
|
||||||
bool rescheduling;
|
bool rescheduling;
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/sema.goc
|
diff -r a6e10414311a libgo/runtime/sema.goc
|
||||||
--- a/libgo/runtime/sema.goc Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/sema.goc Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/sema.goc Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/sema.goc Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -35,7 +35,7 @@
|
@@ -35,7 +35,7 @@
|
||||||
typedef struct SemaRoot SemaRoot;
|
typedef struct SemaRoot SemaRoot;
|
||||||
struct SemaRoot
|
struct SemaRoot
|
||||||
|
@ -1652,9 +1654,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/sema.goc
|
||||||
- runtime_unlock(s);
|
- runtime_unlock(s);
|
||||||
+ runtime_unlock(&s->lock);
|
+ runtime_unlock(&s->lock);
|
||||||
}
|
}
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/sigqueue.goc
|
diff -r a6e10414311a libgo/runtime/sigqueue.goc
|
||||||
--- a/libgo/runtime/sigqueue.goc Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/sigqueue.goc Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/sigqueue.goc Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/sigqueue.goc Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -32,7 +32,7 @@
|
@@ -32,7 +32,7 @@
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
|
||||||
|
@ -1693,13 +1695,13 @@ diff -r 0fde0b6a7eb2 libgo/runtime/sigqueue.goc
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
diff -r 0fde0b6a7eb2 libgo/runtime/time.goc
|
diff -r a6e10414311a libgo/runtime/time.goc
|
||||||
--- a/libgo/runtime/time.goc Fri Jan 09 17:00:26 2015 -0800
|
--- a/libgo/runtime/time.goc Fri Jan 16 07:57:02 2015 -0800
|
||||||
+++ b/libgo/runtime/time.goc Fri Feb 13 12:12:23 2015 -0800
|
+++ b/libgo/runtime/time.goc Fri Feb 13 16:36:07 2015 -0800
|
||||||
@@ -91,17 +91,17 @@
|
@@ -92,17 +92,17 @@
|
||||||
t.period = 0;
|
|
||||||
t.fv = &readyv;
|
t.fv = &readyv;
|
||||||
t.arg.__object = g;
|
t.arg.__object = g;
|
||||||
|
t.seq = 0;
|
||||||
- runtime_lock(&timers);
|
- runtime_lock(&timers);
|
||||||
+ runtime_lock(&timers.lock);
|
+ runtime_lock(&timers.lock);
|
||||||
addtimer(&t);
|
addtimer(&t);
|
||||||
|
@ -1718,7 +1720,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/time.goc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a timer to the heap and start or kick the timer proc
|
// Add a timer to the heap and start or kick the timer proc
|
||||||
@@ -166,14 +166,14 @@
|
@@ -167,14 +167,14 @@
|
||||||
i = t->i;
|
i = t->i;
|
||||||
gi = i;
|
gi = i;
|
||||||
|
|
||||||
|
@ -1735,7 +1737,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/time.goc
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@
|
@@ -190,7 +190,7 @@
|
||||||
}
|
}
|
||||||
if(debug)
|
if(debug)
|
||||||
dumptimers("deltimer");
|
dumptimers("deltimer");
|
||||||
|
@ -1744,8 +1746,8 @@ diff -r 0fde0b6a7eb2 libgo/runtime/time.goc
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +207,7 @@
|
@@ -209,7 +209,7 @@
|
||||||
Eface arg;
|
uintptr seq;
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
- runtime_lock(&timers);
|
- runtime_lock(&timers);
|
||||||
|
@ -1753,16 +1755,16 @@ diff -r 0fde0b6a7eb2 libgo/runtime/time.goc
|
||||||
timers.sleeping = false;
|
timers.sleeping = false;
|
||||||
now = runtime_nanotime();
|
now = runtime_nanotime();
|
||||||
for(;;) {
|
for(;;) {
|
||||||
@@ -233,7 +233,7 @@
|
@@ -236,7 +236,7 @@
|
||||||
fv = t->fv;
|
|
||||||
f = (void*)t->fv->fn;
|
f = (void*)t->fv->fn;
|
||||||
arg = t->arg;
|
arg = t->arg;
|
||||||
|
seq = t->seq;
|
||||||
- runtime_unlock(&timers);
|
- runtime_unlock(&timers);
|
||||||
+ runtime_unlock(&timers.lock);
|
+ runtime_unlock(&timers.lock);
|
||||||
__go_set_closure(fv);
|
__go_set_closure(fv);
|
||||||
f(now, arg);
|
f(arg, seq);
|
||||||
|
|
||||||
@@ -244,20 +244,20 @@
|
@@ -247,20 +247,20 @@
|
||||||
arg.__object = nil;
|
arg.__object = nil;
|
||||||
USED(&arg);
|
USED(&arg);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
f44017549ff9
|
14854533dcc7
|
||||||
|
|
||||||
The first line of this file holds the Mercurial revision number of the
|
The first line of this file holds the Mercurial revision number of the
|
||||||
last merge done from the master library sources.
|
last merge done from the master library sources.
|
||||||
|
|
|
@ -495,6 +495,7 @@ runtime_files = \
|
||||||
runtime/go-unsafe-new.c \
|
runtime/go-unsafe-new.c \
|
||||||
runtime/go-unsafe-newarray.c \
|
runtime/go-unsafe-newarray.c \
|
||||||
runtime/go-unsafe-pointer.c \
|
runtime/go-unsafe-pointer.c \
|
||||||
|
runtime/go-unsetenv.c \
|
||||||
runtime/go-unwind.c \
|
runtime/go-unwind.c \
|
||||||
runtime/go-varargs.c \
|
runtime/go-varargs.c \
|
||||||
runtime/env_posix.c \
|
runtime/env_posix.c \
|
||||||
|
@ -695,7 +696,7 @@ go_net_sockoptip_file = go/net/sockoptip_linux.go go/net/sockoptip_posix.go
|
||||||
else
|
else
|
||||||
if LIBGO_IS_SOLARIS
|
if LIBGO_IS_SOLARIS
|
||||||
go_net_cgo_file = go/net/cgo_linux.go
|
go_net_cgo_file = go/net/cgo_linux.go
|
||||||
go_net_sock_file = go/net/sock_solaris.go
|
go_net_sock_file = go/net/sock_stub.go
|
||||||
go_net_sockopt_file = go/net/sockopt_solaris.go
|
go_net_sockopt_file = go/net/sockopt_solaris.go
|
||||||
go_net_sockoptip_file = go/net/sockoptip_stub.go
|
go_net_sockoptip_file = go/net/sockoptip_stub.go
|
||||||
else
|
else
|
||||||
|
@ -997,7 +998,6 @@ go_runtime_files = \
|
||||||
go/runtime/extern.go \
|
go/runtime/extern.go \
|
||||||
go/runtime/mem.go \
|
go/runtime/mem.go \
|
||||||
go/runtime/softfloat64.go \
|
go/runtime/softfloat64.go \
|
||||||
go/runtime/type.go \
|
|
||||||
version.go
|
version.go
|
||||||
|
|
||||||
version.go: s-version; @true
|
version.go: s-version; @true
|
||||||
|
@ -1187,10 +1187,19 @@ go_crypto_md5_files = \
|
||||||
go/crypto/md5/md5.go \
|
go/crypto/md5/md5.go \
|
||||||
go/crypto/md5/md5block.go \
|
go/crypto/md5/md5block.go \
|
||||||
go/crypto/md5/md5block_generic.go
|
go/crypto/md5/md5block_generic.go
|
||||||
|
|
||||||
|
if LIBGO_IS_LINUX
|
||||||
|
crypto_rand_file = go/crypto/rand/rand_linux.go
|
||||||
|
else
|
||||||
|
crypto_rand_file =
|
||||||
|
endif
|
||||||
|
|
||||||
go_crypto_rand_files = \
|
go_crypto_rand_files = \
|
||||||
go/crypto/rand/rand.go \
|
go/crypto/rand/rand.go \
|
||||||
go/crypto/rand/rand_unix.go \
|
go/crypto/rand/rand_unix.go \
|
||||||
|
$(crypto_rand_file) \
|
||||||
go/crypto/rand/util.go
|
go/crypto/rand/util.go
|
||||||
|
|
||||||
go_crypto_rc4_files = \
|
go_crypto_rc4_files = \
|
||||||
go/crypto/rc4/rc4.go \
|
go/crypto/rc4/rc4.go \
|
||||||
go/crypto/rc4/rc4_ref.go
|
go/crypto/rc4/rc4_ref.go
|
||||||
|
@ -1289,9 +1298,11 @@ go_encoding_csv_files = \
|
||||||
go_encoding_gob_files = \
|
go_encoding_gob_files = \
|
||||||
go/encoding/gob/decode.go \
|
go/encoding/gob/decode.go \
|
||||||
go/encoding/gob/decoder.go \
|
go/encoding/gob/decoder.go \
|
||||||
|
go/encoding/gob/dec_helpers.go \
|
||||||
go/encoding/gob/doc.go \
|
go/encoding/gob/doc.go \
|
||||||
go/encoding/gob/encode.go \
|
go/encoding/gob/encode.go \
|
||||||
go/encoding/gob/encoder.go \
|
go/encoding/gob/encoder.go \
|
||||||
|
go/encoding/gob/enc_helpers.go \
|
||||||
go/encoding/gob/error.go \
|
go/encoding/gob/error.go \
|
||||||
go/encoding/gob/type.go
|
go/encoding/gob/type.go
|
||||||
go_encoding_hex_files = \
|
go_encoding_hex_files = \
|
||||||
|
@ -1452,7 +1463,6 @@ go_mime_multipart_files = \
|
||||||
go/mime/multipart/writer.go
|
go/mime/multipart/writer.go
|
||||||
|
|
||||||
go_net_http_files = \
|
go_net_http_files = \
|
||||||
go/net/http/chunked.go \
|
|
||||||
go/net/http/client.go \
|
go/net/http/client.go \
|
||||||
go/net/http/cookie.go \
|
go/net/http/cookie.go \
|
||||||
go/net/http/filetransport.go \
|
go/net/http/filetransport.go \
|
||||||
|
@ -1496,12 +1506,12 @@ go_net_http_httptest_files = \
|
||||||
go_net_http_pprof_files = \
|
go_net_http_pprof_files = \
|
||||||
go/net/http/pprof/pprof.go
|
go/net/http/pprof/pprof.go
|
||||||
go_net_http_httputil_files = \
|
go_net_http_httputil_files = \
|
||||||
go/net/http/httputil/chunked.go \
|
|
||||||
go/net/http/httputil/dump.go \
|
go/net/http/httputil/dump.go \
|
||||||
go/net/http/httputil/httputil.go \
|
go/net/http/httputil/httputil.go \
|
||||||
go/net/http/httputil/persist.go \
|
go/net/http/httputil/persist.go \
|
||||||
go/net/http/httputil/reverseproxy.go
|
go/net/http/httputil/reverseproxy.go
|
||||||
|
go_net_http_internal_files = \
|
||||||
|
go/net/http/internal/chunked.go
|
||||||
|
|
||||||
go_old_regexp_files = \
|
go_old_regexp_files = \
|
||||||
go/old/regexp/regexp.go
|
go/old/regexp/regexp.go
|
||||||
|
@ -1535,7 +1545,8 @@ go_path_filepath_files = \
|
||||||
go/path/filepath/match.go \
|
go/path/filepath/match.go \
|
||||||
go/path/filepath/path.go \
|
go/path/filepath/path.go \
|
||||||
go/path/filepath/path_unix.go \
|
go/path/filepath/path_unix.go \
|
||||||
go/path/filepath/symlink.go
|
go/path/filepath/symlink.go \
|
||||||
|
go/path/filepath/symlink_unix.go
|
||||||
|
|
||||||
go_regexp_syntax_files = \
|
go_regexp_syntax_files = \
|
||||||
go/regexp/syntax/compile.go \
|
go/regexp/syntax/compile.go \
|
||||||
|
@ -1570,7 +1581,8 @@ go_text_template_parse_files = \
|
||||||
go/text/template/parse/parse.go
|
go/text/template/parse/parse.go
|
||||||
|
|
||||||
go_sync_atomic_files = \
|
go_sync_atomic_files = \
|
||||||
go/sync/atomic/doc.go
|
go/sync/atomic/doc.go \
|
||||||
|
go/sync/atomic/value.go
|
||||||
go_sync_atomic_c_files = \
|
go_sync_atomic_c_files = \
|
||||||
go/sync/atomic/atomic.c
|
go/sync/atomic/atomic.c
|
||||||
|
|
||||||
|
@ -1784,10 +1796,21 @@ go_syscall_c_files = \
|
||||||
|
|
||||||
go_syscall_test_files = \
|
go_syscall_test_files = \
|
||||||
$(syscall_creds_test_file) \
|
$(syscall_creds_test_file) \
|
||||||
|
go/syscall/export_test.go \
|
||||||
go/syscall/mmap_unix_test.go \
|
go/syscall/mmap_unix_test.go \
|
||||||
go/syscall/syscall_test.go \
|
go/syscall/syscall_test.go \
|
||||||
go/syscall/syscall_unix_test.go
|
go/syscall/syscall_unix_test.go
|
||||||
|
|
||||||
|
if LIBGO_IS_LINUX
|
||||||
|
internal_syscall_getrandom_file = go/internal/syscall/getrandom_linux.go
|
||||||
|
else
|
||||||
|
internal_syscall_getrandom_file =
|
||||||
|
endif
|
||||||
|
|
||||||
|
go_internal_syscall_files = \
|
||||||
|
go/internal/syscall/dummy.go \
|
||||||
|
$(internal_syscall_getrandom_file)
|
||||||
|
|
||||||
libcalls.go: s-libcalls; @true
|
libcalls.go: s-libcalls; @true
|
||||||
s-libcalls: libcalls-list go/syscall/mksyscall.awk $(go_base_syscall_files)
|
s-libcalls: libcalls-list go/syscall/mksyscall.awk $(go_base_syscall_files)
|
||||||
rm -f libcalls.go.tmp
|
rm -f libcalls.go.tmp
|
||||||
|
@ -1957,6 +1980,7 @@ libgo_go_objs = \
|
||||||
net/http/fcgi.lo \
|
net/http/fcgi.lo \
|
||||||
net/http/httptest.lo \
|
net/http/httptest.lo \
|
||||||
net/http/httputil.lo \
|
net/http/httputil.lo \
|
||||||
|
net/http/internal.lo \
|
||||||
net/http/pprof.lo \
|
net/http/pprof.lo \
|
||||||
image/color.lo \
|
image/color.lo \
|
||||||
image/color/palette.lo \
|
image/color/palette.lo \
|
||||||
|
@ -1965,6 +1989,7 @@ libgo_go_objs = \
|
||||||
image/jpeg.lo \
|
image/jpeg.lo \
|
||||||
image/png.lo \
|
image/png.lo \
|
||||||
index/suffixarray.lo \
|
index/suffixarray.lo \
|
||||||
|
internal/syscall.lo \
|
||||||
io/ioutil.lo \
|
io/ioutil.lo \
|
||||||
log/syslog.lo \
|
log/syslog.lo \
|
||||||
log/syslog/syslog_c.lo \
|
log/syslog/syslog_c.lo \
|
||||||
|
@ -3160,6 +3185,15 @@ net/http/httputil/check: $(check_deps)
|
||||||
@$(CHECK)
|
@$(CHECK)
|
||||||
.PHONY: net/http/httputil/check
|
.PHONY: net/http/httputil/check
|
||||||
|
|
||||||
|
@go_include@ net/http/internal.lo.dep
|
||||||
|
net/http/internal.lo.dep: $(go_net_http_internal_files)
|
||||||
|
$(BUILDDEPS)
|
||||||
|
net/http/internal.lo: $(go_net_http_internal_files)
|
||||||
|
$(BUILDPACKAGE)
|
||||||
|
net/http/internal/check: $(CHECK_DEPS)
|
||||||
|
@$(CHECK)
|
||||||
|
.PHONY: net/http/internal/check
|
||||||
|
|
||||||
@go_include@ net/http/pprof.lo.dep
|
@go_include@ net/http/pprof.lo.dep
|
||||||
net/http/pprof.lo.dep: $(go_net_http_pprof_files)
|
net/http/pprof.lo.dep: $(go_net_http_pprof_files)
|
||||||
$(BUILDDEPS)
|
$(BUILDDEPS)
|
||||||
|
@ -3260,7 +3294,8 @@ runtime/pprof/check: $(CHECK_DEPS)
|
||||||
.PHONY: runtime/pprof/check
|
.PHONY: runtime/pprof/check
|
||||||
# At least for now, we need -static-libgo for this test, because
|
# At least for now, we need -static-libgo for this test, because
|
||||||
# otherwise we can't get the line numbers.
|
# otherwise we can't get the line numbers.
|
||||||
runtime_pprof_check_GOCFLAGS = -static-libgo
|
# Also use -fno-inline to get better results from the memory profiler.
|
||||||
|
runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
|
||||||
|
|
||||||
@go_include@ sync/atomic.lo.dep
|
@go_include@ sync/atomic.lo.dep
|
||||||
sync/atomic.lo.dep: $(go_sync_atomic_files)
|
sync/atomic.lo.dep: $(go_sync_atomic_files)
|
||||||
|
@ -3363,6 +3398,15 @@ syscall/check: $(CHECK_DEPS)
|
||||||
@$(CHECK)
|
@$(CHECK)
|
||||||
.PHONY: syscall/check
|
.PHONY: syscall/check
|
||||||
|
|
||||||
|
@go_include@ internal/syscall.lo.dep
|
||||||
|
internal/syscall.lo.dep: $(go_internal_syscall_files)
|
||||||
|
$(BUILDDEPS)
|
||||||
|
internal/syscall.lo: $(go_internal_syscall_files)
|
||||||
|
$(BUILDPACKAGE)
|
||||||
|
internal/syscall/check: $(CHECK_DEPS)
|
||||||
|
@$(CHECK)
|
||||||
|
.PHONY: internal/syscall/check
|
||||||
|
|
||||||
# How to build a .gox file from a .lo file.
|
# How to build a .gox file from a .lo file.
|
||||||
BUILDGOX = \
|
BUILDGOX = \
|
||||||
f=`echo $< | sed -e 's/.lo$$/.o/'`; \
|
f=`echo $< | sed -e 's/.lo$$/.o/'`; \
|
||||||
|
@ -3623,6 +3667,9 @@ net/http/httputil.gox: net/http/httputil.lo
|
||||||
net/http/pprof.gox: net/http/pprof.lo
|
net/http/pprof.gox: net/http/pprof.lo
|
||||||
$(BUILDGOX)
|
$(BUILDGOX)
|
||||||
|
|
||||||
|
net/http/internal.gox: net/http/internal.lo
|
||||||
|
$(BUILDGOX)
|
||||||
|
|
||||||
net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
|
net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
|
||||||
$(BUILDGOX)
|
$(BUILDGOX)
|
||||||
|
|
||||||
|
@ -3652,6 +3699,9 @@ runtime/pprof.gox: runtime/pprof.lo
|
||||||
sync/atomic.gox: sync/atomic.lo
|
sync/atomic.gox: sync/atomic.lo
|
||||||
$(BUILDGOX)
|
$(BUILDGOX)
|
||||||
|
|
||||||
|
internal/syscall.gox: internal/syscall.lo
|
||||||
|
$(BUILDGOX)
|
||||||
|
|
||||||
text/scanner.gox: text/scanner.lo
|
text/scanner.gox: text/scanner.lo
|
||||||
$(BUILDGOX)
|
$(BUILDGOX)
|
||||||
text/tabwriter.gox: text/tabwriter.lo
|
text/tabwriter.gox: text/tabwriter.lo
|
||||||
|
@ -3773,6 +3823,7 @@ TEST_PACKAGES = \
|
||||||
net/http/fcgi/check \
|
net/http/fcgi/check \
|
||||||
net/http/httptest/check \
|
net/http/httptest/check \
|
||||||
net/http/httputil/check \
|
net/http/httputil/check \
|
||||||
|
net/http/internal/check \
|
||||||
net/mail/check \
|
net/mail/check \
|
||||||
net/rpc/check \
|
net/rpc/check \
|
||||||
net/smtp/check \
|
net/smtp/check \
|
||||||
|
|
|
@ -164,14 +164,15 @@ am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \
|
||||||
go/printer.lo go/scanner.lo go/token.lo hash/adler32.lo \
|
go/printer.lo go/scanner.lo go/token.lo hash/adler32.lo \
|
||||||
hash/crc32.lo hash/crc64.lo hash/fnv.lo net/http/cgi.lo \
|
hash/crc32.lo hash/crc64.lo hash/fnv.lo net/http/cgi.lo \
|
||||||
net/http/cookiejar.lo net/http/fcgi.lo net/http/httptest.lo \
|
net/http/cookiejar.lo net/http/fcgi.lo net/http/httptest.lo \
|
||||||
net/http/httputil.lo net/http/pprof.lo image/color.lo \
|
net/http/httputil.lo net/http/internal.lo net/http/pprof.lo \
|
||||||
image/color/palette.lo image/draw.lo image/gif.lo \
|
image/color.lo image/color/palette.lo image/draw.lo \
|
||||||
image/jpeg.lo image/png.lo index/suffixarray.lo io/ioutil.lo \
|
image/gif.lo image/jpeg.lo image/png.lo index/suffixarray.lo \
|
||||||
log/syslog.lo log/syslog/syslog_c.lo math/big.lo math/cmplx.lo \
|
internal/syscall.lo io/ioutil.lo log/syslog.lo \
|
||||||
math/rand.lo mime/multipart.lo net/http.lo net/mail.lo \
|
log/syslog/syslog_c.lo math/big.lo math/cmplx.lo math/rand.lo \
|
||||||
net/rpc.lo net/smtp.lo net/textproto.lo net/url.lo \
|
mime/multipart.lo net/http.lo net/mail.lo net/rpc.lo \
|
||||||
old/regexp.lo old/template.lo os/exec.lo $(am__DEPENDENCIES_1) \
|
net/smtp.lo net/textproto.lo net/url.lo old/regexp.lo \
|
||||||
os/signal.lo os/user.lo path/filepath.lo regexp/syntax.lo \
|
old/template.lo os/exec.lo $(am__DEPENDENCIES_1) os/signal.lo \
|
||||||
|
os/user.lo path/filepath.lo regexp/syntax.lo \
|
||||||
net/rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \
|
net/rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \
|
||||||
sync/atomic.lo sync/atomic_c.lo text/scanner.lo \
|
sync/atomic.lo sync/atomic_c.lo text/scanner.lo \
|
||||||
text/tabwriter.lo text/template.lo text/template/parse.lo \
|
text/tabwriter.lo text/template.lo text/template/parse.lo \
|
||||||
|
@ -218,15 +219,15 @@ am__objects_6 = go-append.lo go-assert.lo go-assert-interface.lo \
|
||||||
go-type-complex.lo go-type-eface.lo go-type-error.lo \
|
go-type-complex.lo go-type-eface.lo go-type-error.lo \
|
||||||
go-type-float.lo go-type-identity.lo go-type-interface.lo \
|
go-type-float.lo go-type-identity.lo go-type-interface.lo \
|
||||||
go-type-string.lo go-typedesc-equal.lo go-unsafe-new.lo \
|
go-type-string.lo go-typedesc-equal.lo go-unsafe-new.lo \
|
||||||
go-unsafe-newarray.lo go-unsafe-pointer.lo go-unwind.lo \
|
go-unsafe-newarray.lo go-unsafe-pointer.lo go-unsetenv.lo \
|
||||||
go-varargs.lo env_posix.lo heapdump.lo $(am__objects_1) \
|
go-unwind.lo go-varargs.lo env_posix.lo heapdump.lo \
|
||||||
mcache.lo mcentral.lo $(am__objects_2) mfixalloc.lo mgc0.lo \
|
$(am__objects_1) mcache.lo mcentral.lo $(am__objects_2) \
|
||||||
mheap.lo msize.lo $(am__objects_3) panic.lo parfor.lo print.lo \
|
mfixalloc.lo mgc0.lo mheap.lo msize.lo $(am__objects_3) \
|
||||||
proc.lo runtime.lo signal_unix.lo thread.lo yield.lo \
|
panic.lo parfor.lo print.lo proc.lo runtime.lo signal_unix.lo \
|
||||||
$(am__objects_4) chan.lo cpuprof.lo go-iface.lo lfstack.lo \
|
thread.lo yield.lo $(am__objects_4) chan.lo cpuprof.lo \
|
||||||
malloc.lo map.lo mprof.lo netpoll.lo rdebug.lo reflect.lo \
|
go-iface.lo lfstack.lo malloc.lo map.lo mprof.lo netpoll.lo \
|
||||||
runtime1.lo sema.lo sigqueue.lo string.lo time.lo \
|
rdebug.lo reflect.lo runtime1.lo sema.lo sigqueue.lo string.lo \
|
||||||
$(am__objects_5)
|
time.lo $(am__objects_5)
|
||||||
am_libgo_llgo_la_OBJECTS = $(am__objects_6)
|
am_libgo_llgo_la_OBJECTS = $(am__objects_6)
|
||||||
libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS)
|
libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS)
|
||||||
libgo_llgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
libgo_llgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||||
|
@ -838,6 +839,7 @@ runtime_files = \
|
||||||
runtime/go-unsafe-new.c \
|
runtime/go-unsafe-new.c \
|
||||||
runtime/go-unsafe-newarray.c \
|
runtime/go-unsafe-newarray.c \
|
||||||
runtime/go-unsafe-pointer.c \
|
runtime/go-unsafe-pointer.c \
|
||||||
|
runtime/go-unsetenv.c \
|
||||||
runtime/go-unwind.c \
|
runtime/go-unwind.c \
|
||||||
runtime/go-varargs.c \
|
runtime/go-varargs.c \
|
||||||
runtime/env_posix.c \
|
runtime/env_posix.c \
|
||||||
|
@ -992,7 +994,7 @@ go_mime_files = \
|
||||||
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
|
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
|
||||||
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
|
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
|
||||||
@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
|
@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go
|
||||||
@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sock_file = go/net/sock_solaris.go
|
@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sock_file = go/net/sock_stub.go
|
||||||
@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sock_file = go/net/sock_linux.go
|
@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sock_file = go/net/sock_linux.go
|
||||||
@LIBGO_IS_LINUX_TRUE@go_net_sock_file = go/net/sock_linux.go
|
@LIBGO_IS_LINUX_TRUE@go_net_sock_file = go/net/sock_linux.go
|
||||||
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockopt_file = go/net/sockopt_bsd.go
|
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sockopt_file = go/net/sockopt_bsd.go
|
||||||
|
@ -1180,7 +1182,6 @@ go_runtime_files = \
|
||||||
go/runtime/extern.go \
|
go/runtime/extern.go \
|
||||||
go/runtime/mem.go \
|
go/runtime/mem.go \
|
||||||
go/runtime/softfloat64.go \
|
go/runtime/softfloat64.go \
|
||||||
go/runtime/type.go \
|
|
||||||
version.go
|
version.go
|
||||||
|
|
||||||
go_sort_files = \
|
go_sort_files = \
|
||||||
|
@ -1348,9 +1349,12 @@ go_crypto_md5_files = \
|
||||||
go/crypto/md5/md5block.go \
|
go/crypto/md5/md5block.go \
|
||||||
go/crypto/md5/md5block_generic.go
|
go/crypto/md5/md5block_generic.go
|
||||||
|
|
||||||
|
@LIBGO_IS_LINUX_FALSE@crypto_rand_file =
|
||||||
|
@LIBGO_IS_LINUX_TRUE@crypto_rand_file = go/crypto/rand/rand_linux.go
|
||||||
go_crypto_rand_files = \
|
go_crypto_rand_files = \
|
||||||
go/crypto/rand/rand.go \
|
go/crypto/rand/rand.go \
|
||||||
go/crypto/rand/rand_unix.go \
|
go/crypto/rand/rand_unix.go \
|
||||||
|
$(crypto_rand_file) \
|
||||||
go/crypto/rand/util.go
|
go/crypto/rand/util.go
|
||||||
|
|
||||||
go_crypto_rc4_files = \
|
go_crypto_rc4_files = \
|
||||||
|
@ -1469,9 +1473,11 @@ go_encoding_csv_files = \
|
||||||
go_encoding_gob_files = \
|
go_encoding_gob_files = \
|
||||||
go/encoding/gob/decode.go \
|
go/encoding/gob/decode.go \
|
||||||
go/encoding/gob/decoder.go \
|
go/encoding/gob/decoder.go \
|
||||||
|
go/encoding/gob/dec_helpers.go \
|
||||||
go/encoding/gob/doc.go \
|
go/encoding/gob/doc.go \
|
||||||
go/encoding/gob/encode.go \
|
go/encoding/gob/encode.go \
|
||||||
go/encoding/gob/encoder.go \
|
go/encoding/gob/encoder.go \
|
||||||
|
go/encoding/gob/enc_helpers.go \
|
||||||
go/encoding/gob/error.go \
|
go/encoding/gob/error.go \
|
||||||
go/encoding/gob/type.go
|
go/encoding/gob/type.go
|
||||||
|
|
||||||
|
@ -1649,7 +1655,6 @@ go_mime_multipart_files = \
|
||||||
go/mime/multipart/writer.go
|
go/mime/multipart/writer.go
|
||||||
|
|
||||||
go_net_http_files = \
|
go_net_http_files = \
|
||||||
go/net/http/chunked.go \
|
|
||||||
go/net/http/client.go \
|
go/net/http/client.go \
|
||||||
go/net/http/cookie.go \
|
go/net/http/cookie.go \
|
||||||
go/net/http/filetransport.go \
|
go/net/http/filetransport.go \
|
||||||
|
@ -1702,12 +1707,14 @@ go_net_http_pprof_files = \
|
||||||
go/net/http/pprof/pprof.go
|
go/net/http/pprof/pprof.go
|
||||||
|
|
||||||
go_net_http_httputil_files = \
|
go_net_http_httputil_files = \
|
||||||
go/net/http/httputil/chunked.go \
|
|
||||||
go/net/http/httputil/dump.go \
|
go/net/http/httputil/dump.go \
|
||||||
go/net/http/httputil/httputil.go \
|
go/net/http/httputil/httputil.go \
|
||||||
go/net/http/httputil/persist.go \
|
go/net/http/httputil/persist.go \
|
||||||
go/net/http/httputil/reverseproxy.go
|
go/net/http/httputil/reverseproxy.go
|
||||||
|
|
||||||
|
go_net_http_internal_files = \
|
||||||
|
go/net/http/internal/chunked.go
|
||||||
|
|
||||||
go_old_regexp_files = \
|
go_old_regexp_files = \
|
||||||
go/old/regexp/regexp.go
|
go/old/regexp/regexp.go
|
||||||
|
|
||||||
|
@ -1737,7 +1744,8 @@ go_path_filepath_files = \
|
||||||
go/path/filepath/match.go \
|
go/path/filepath/match.go \
|
||||||
go/path/filepath/path.go \
|
go/path/filepath/path.go \
|
||||||
go/path/filepath/path_unix.go \
|
go/path/filepath/path_unix.go \
|
||||||
go/path/filepath/symlink.go
|
go/path/filepath/symlink.go \
|
||||||
|
go/path/filepath/symlink_unix.go
|
||||||
|
|
||||||
go_regexp_syntax_files = \
|
go_regexp_syntax_files = \
|
||||||
go/regexp/syntax/compile.go \
|
go/regexp/syntax/compile.go \
|
||||||
|
@ -1775,7 +1783,8 @@ go_text_template_parse_files = \
|
||||||
go/text/template/parse/parse.go
|
go/text/template/parse/parse.go
|
||||||
|
|
||||||
go_sync_atomic_files = \
|
go_sync_atomic_files = \
|
||||||
go/sync/atomic/doc.go
|
go/sync/atomic/doc.go \
|
||||||
|
go/sync/atomic/value.go
|
||||||
|
|
||||||
go_sync_atomic_c_files = \
|
go_sync_atomic_c_files = \
|
||||||
go/sync/atomic/atomic.c
|
go/sync/atomic/atomic.c
|
||||||
|
@ -1918,10 +1927,17 @@ go_syscall_c_files = \
|
||||||
|
|
||||||
go_syscall_test_files = \
|
go_syscall_test_files = \
|
||||||
$(syscall_creds_test_file) \
|
$(syscall_creds_test_file) \
|
||||||
|
go/syscall/export_test.go \
|
||||||
go/syscall/mmap_unix_test.go \
|
go/syscall/mmap_unix_test.go \
|
||||||
go/syscall/syscall_test.go \
|
go/syscall/syscall_test.go \
|
||||||
go/syscall/syscall_unix_test.go
|
go/syscall/syscall_unix_test.go
|
||||||
|
|
||||||
|
@LIBGO_IS_LINUX_FALSE@internal_syscall_getrandom_file =
|
||||||
|
@LIBGO_IS_LINUX_TRUE@internal_syscall_getrandom_file = go/internal/syscall/getrandom_linux.go
|
||||||
|
go_internal_syscall_files = \
|
||||||
|
go/internal/syscall/dummy.go \
|
||||||
|
$(internal_syscall_getrandom_file)
|
||||||
|
|
||||||
@LIBGO_IS_LINUX_FALSE@os_lib_inotify_lo =
|
@LIBGO_IS_LINUX_FALSE@os_lib_inotify_lo =
|
||||||
|
|
||||||
# os_lib_inotify_lo = os/inotify.lo
|
# os_lib_inotify_lo = os/inotify.lo
|
||||||
|
@ -2030,6 +2046,7 @@ libgo_go_objs = \
|
||||||
net/http/fcgi.lo \
|
net/http/fcgi.lo \
|
||||||
net/http/httptest.lo \
|
net/http/httptest.lo \
|
||||||
net/http/httputil.lo \
|
net/http/httputil.lo \
|
||||||
|
net/http/internal.lo \
|
||||||
net/http/pprof.lo \
|
net/http/pprof.lo \
|
||||||
image/color.lo \
|
image/color.lo \
|
||||||
image/color/palette.lo \
|
image/color/palette.lo \
|
||||||
|
@ -2038,6 +2055,7 @@ libgo_go_objs = \
|
||||||
image/jpeg.lo \
|
image/jpeg.lo \
|
||||||
image/png.lo \
|
image/png.lo \
|
||||||
index/suffixarray.lo \
|
index/suffixarray.lo \
|
||||||
|
internal/syscall.lo \
|
||||||
io/ioutil.lo \
|
io/ioutil.lo \
|
||||||
log/syslog.lo \
|
log/syslog.lo \
|
||||||
log/syslog/syslog_c.lo \
|
log/syslog/syslog_c.lo \
|
||||||
|
@ -2169,7 +2187,8 @@ CHECK_DEPS = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
|
||||||
$(toolexeclibgounicode_DATA) $(am__append_1) $(am__append_2)
|
$(toolexeclibgounicode_DATA) $(am__append_1) $(am__append_2)
|
||||||
# At least for now, we need -static-libgo for this test, because
|
# At least for now, we need -static-libgo for this test, because
|
||||||
# otherwise we can't get the line numbers.
|
# otherwise we can't get the line numbers.
|
||||||
runtime_pprof_check_GOCFLAGS = -static-libgo
|
# Also use -fno-inline to get better results from the memory profiler.
|
||||||
|
runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
|
||||||
|
|
||||||
# How to build a .gox file from a .lo file.
|
# How to build a .gox file from a .lo file.
|
||||||
BUILDGOX = \
|
BUILDGOX = \
|
||||||
|
@ -2278,6 +2297,7 @@ TEST_PACKAGES = \
|
||||||
net/http/fcgi/check \
|
net/http/fcgi/check \
|
||||||
net/http/httptest/check \
|
net/http/httptest/check \
|
||||||
net/http/httputil/check \
|
net/http/httputil/check \
|
||||||
|
net/http/internal/check \
|
||||||
net/mail/check \
|
net/mail/check \
|
||||||
net/rpc/check \
|
net/rpc/check \
|
||||||
net/smtp/check \
|
net/smtp/check \
|
||||||
|
@ -2513,6 +2533,7 @@ distclean-compile:
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-new.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-new.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-newarray.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-newarray.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-pointer.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsafe-pointer.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unsetenv.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unwind.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-unwind.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-varargs.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-varargs.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heapdump.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heapdump.Plo@am__quote@
|
||||||
|
@ -3029,6 +3050,13 @@ go-unsafe-pointer.lo: runtime/go-unsafe-pointer.c
|
||||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||||
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unsafe-pointer.lo `test -f 'runtime/go-unsafe-pointer.c' || echo '$(srcdir)/'`runtime/go-unsafe-pointer.c
|
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unsafe-pointer.lo `test -f 'runtime/go-unsafe-pointer.c' || echo '$(srcdir)/'`runtime/go-unsafe-pointer.c
|
||||||
|
|
||||||
|
go-unsetenv.lo: runtime/go-unsetenv.c
|
||||||
|
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unsetenv.lo -MD -MP -MF $(DEPDIR)/go-unsetenv.Tpo -c -o go-unsetenv.lo `test -f 'runtime/go-unsetenv.c' || echo '$(srcdir)/'`runtime/go-unsetenv.c
|
||||||
|
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-unsetenv.Tpo $(DEPDIR)/go-unsetenv.Plo
|
||||||
|
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-unsetenv.c' object='go-unsetenv.lo' libtool=yes @AMDEPBACKSLASH@
|
||||||
|
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||||
|
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-unsetenv.lo `test -f 'runtime/go-unsetenv.c' || echo '$(srcdir)/'`runtime/go-unsetenv.c
|
||||||
|
|
||||||
go-unwind.lo: runtime/go-unwind.c
|
go-unwind.lo: runtime/go-unwind.c
|
||||||
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unwind.lo -MD -MP -MF $(DEPDIR)/go-unwind.Tpo -c -o go-unwind.lo `test -f 'runtime/go-unwind.c' || echo '$(srcdir)/'`runtime/go-unwind.c
|
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-unwind.lo -MD -MP -MF $(DEPDIR)/go-unwind.Tpo -c -o go-unwind.lo `test -f 'runtime/go-unwind.c' || echo '$(srcdir)/'`runtime/go-unwind.c
|
||||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-unwind.Tpo $(DEPDIR)/go-unwind.Plo
|
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-unwind.Tpo $(DEPDIR)/go-unwind.Plo
|
||||||
|
@ -5496,6 +5524,15 @@ net/http/httputil/check: $(check_deps)
|
||||||
@$(CHECK)
|
@$(CHECK)
|
||||||
.PHONY: net/http/httputil/check
|
.PHONY: net/http/httputil/check
|
||||||
|
|
||||||
|
@go_include@ net/http/internal.lo.dep
|
||||||
|
net/http/internal.lo.dep: $(go_net_http_internal_files)
|
||||||
|
$(BUILDDEPS)
|
||||||
|
net/http/internal.lo: $(go_net_http_internal_files)
|
||||||
|
$(BUILDPACKAGE)
|
||||||
|
net/http/internal/check: $(CHECK_DEPS)
|
||||||
|
@$(CHECK)
|
||||||
|
.PHONY: net/http/internal/check
|
||||||
|
|
||||||
@go_include@ net/http/pprof.lo.dep
|
@go_include@ net/http/pprof.lo.dep
|
||||||
net/http/pprof.lo.dep: $(go_net_http_pprof_files)
|
net/http/pprof.lo.dep: $(go_net_http_pprof_files)
|
||||||
$(BUILDDEPS)
|
$(BUILDDEPS)
|
||||||
|
@ -5696,6 +5733,15 @@ syscall/check: $(CHECK_DEPS)
|
||||||
@$(CHECK)
|
@$(CHECK)
|
||||||
.PHONY: syscall/check
|
.PHONY: syscall/check
|
||||||
|
|
||||||
|
@go_include@ internal/syscall.lo.dep
|
||||||
|
internal/syscall.lo.dep: $(go_internal_syscall_files)
|
||||||
|
$(BUILDDEPS)
|
||||||
|
internal/syscall.lo: $(go_internal_syscall_files)
|
||||||
|
$(BUILDPACKAGE)
|
||||||
|
internal/syscall/check: $(CHECK_DEPS)
|
||||||
|
@$(CHECK)
|
||||||
|
.PHONY: internal/syscall/check
|
||||||
|
|
||||||
bufio.gox: bufio.lo
|
bufio.gox: bufio.lo
|
||||||
$(BUILDGOX)
|
$(BUILDGOX)
|
||||||
bytes.gox: bytes.lo
|
bytes.gox: bytes.lo
|
||||||
|
@ -5951,6 +5997,9 @@ net/http/httputil.gox: net/http/httputil.lo
|
||||||
net/http/pprof.gox: net/http/pprof.lo
|
net/http/pprof.gox: net/http/pprof.lo
|
||||||
$(BUILDGOX)
|
$(BUILDGOX)
|
||||||
|
|
||||||
|
net/http/internal.gox: net/http/internal.lo
|
||||||
|
$(BUILDGOX)
|
||||||
|
|
||||||
net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
|
net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
|
||||||
$(BUILDGOX)
|
$(BUILDGOX)
|
||||||
|
|
||||||
|
@ -5980,6 +6029,9 @@ runtime/pprof.gox: runtime/pprof.lo
|
||||||
sync/atomic.gox: sync/atomic.lo
|
sync/atomic.gox: sync/atomic.lo
|
||||||
$(BUILDGOX)
|
$(BUILDGOX)
|
||||||
|
|
||||||
|
internal/syscall.gox: internal/syscall.lo
|
||||||
|
$(BUILDGOX)
|
||||||
|
|
||||||
text/scanner.gox: text/scanner.lo
|
text/scanner.gox: text/scanner.lo
|
||||||
$(BUILDGOX)
|
$(BUILDGOX)
|
||||||
text/tabwriter.gox: text/tabwriter.lo
|
text/tabwriter.gox: text/tabwriter.lo
|
||||||
|
|
|
@ -319,6 +319,9 @@
|
||||||
/* Define to 1 if you have the `unlinkat' function. */
|
/* Define to 1 if you have the `unlinkat' function. */
|
||||||
#undef HAVE_UNLINKAT
|
#undef HAVE_UNLINKAT
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `unsetenv' function. */
|
||||||
|
#undef HAVE_UNSETENV
|
||||||
|
|
||||||
/* Define to 1 if you have the `unshare' function. */
|
/* Define to 1 if you have the `unshare' function. */
|
||||||
#undef HAVE_UNSHARE
|
#undef HAVE_UNSHARE
|
||||||
|
|
||||||
|
|
|
@ -2511,7 +2511,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||||
ac_config_headers="$ac_config_headers config.h"
|
ac_config_headers="$ac_config_headers config.h"
|
||||||
|
|
||||||
|
|
||||||
libtool_VERSION=6:0:0
|
libtool_VERSION=7:0:0
|
||||||
|
|
||||||
|
|
||||||
# Default to --enable-multilib
|
# Default to --enable-multilib
|
||||||
|
@ -14805,7 +14805,7 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
for ac_func in strerror_r strsignal wait4 mincore setenv dl_iterate_phdr
|
for ac_func in strerror_r strsignal wait4 mincore setenv unsetenv dl_iterate_phdr
|
||||||
do :
|
do :
|
||||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||||
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
||||||
|
|
|
@ -11,7 +11,7 @@ AC_INIT(package-unused, version-unused,, libgo)
|
||||||
AC_CONFIG_SRCDIR(Makefile.am)
|
AC_CONFIG_SRCDIR(Makefile.am)
|
||||||
AC_CONFIG_HEADER(config.h)
|
AC_CONFIG_HEADER(config.h)
|
||||||
|
|
||||||
libtool_VERSION=6:0:0
|
libtool_VERSION=7:0:0
|
||||||
AC_SUBST(libtool_VERSION)
|
AC_SUBST(libtool_VERSION)
|
||||||
|
|
||||||
AM_ENABLE_MULTILIB(, ..)
|
AM_ENABLE_MULTILIB(, ..)
|
||||||
|
@ -551,7 +551,7 @@ fi
|
||||||
|
|
||||||
AM_CONDITIONAL(HAVE_SYS_MMAN_H, test "$ac_cv_header_sys_mman_h" = yes)
|
AM_CONDITIONAL(HAVE_SYS_MMAN_H, test "$ac_cv_header_sys_mman_h" = yes)
|
||||||
|
|
||||||
AC_CHECK_FUNCS(strerror_r strsignal wait4 mincore setenv dl_iterate_phdr)
|
AC_CHECK_FUNCS(strerror_r strsignal wait4 mincore setenv unsetenv dl_iterate_phdr)
|
||||||
AM_CONDITIONAL(HAVE_STRERROR_R, test "$ac_cv_func_strerror_r" = yes)
|
AM_CONDITIONAL(HAVE_STRERROR_R, test "$ac_cv_func_strerror_r" = yes)
|
||||||
AM_CONDITIONAL(HAVE_WAIT4, test "$ac_cv_func_wait4" = yes)
|
AM_CONDITIONAL(HAVE_WAIT4, test "$ac_cv_func_wait4" = yes)
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,11 @@ const maxNanoSecondIntSize = 9
|
||||||
// The Next method advances to the next file in the archive (including the first),
|
// The Next method advances to the next file in the archive (including the first),
|
||||||
// and then it can be treated as an io.Reader to access the file's data.
|
// and then it can be treated as an io.Reader to access the file's data.
|
||||||
type Reader struct {
|
type Reader struct {
|
||||||
r io.Reader
|
r io.Reader
|
||||||
err error
|
err error
|
||||||
pad int64 // amount of padding (ignored) after current file entry
|
pad int64 // amount of padding (ignored) after current file entry
|
||||||
curr numBytesReader // reader for current file entry
|
curr numBytesReader // reader for current file entry
|
||||||
|
hdrBuff [blockSize]byte // buffer to use in readHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// A numBytesReader is an io.Reader with a numBytes method, returning the number
|
// A numBytesReader is an io.Reader with a numBytes method, returning the number
|
||||||
|
@ -426,7 +427,9 @@ func (tr *Reader) verifyChecksum(header []byte) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *Reader) readHeader() *Header {
|
func (tr *Reader) readHeader() *Header {
|
||||||
header := make([]byte, blockSize)
|
header := tr.hdrBuff[:]
|
||||||
|
copy(header, zeroBlock)
|
||||||
|
|
||||||
if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
|
if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,8 +37,10 @@ type Writer struct {
|
||||||
nb int64 // number of unwritten bytes for current file entry
|
nb int64 // number of unwritten bytes for current file entry
|
||||||
pad int64 // amount of padding to write after current file entry
|
pad int64 // amount of padding to write after current file entry
|
||||||
closed bool
|
closed bool
|
||||||
usedBinary bool // whether the binary numeric field extension was used
|
usedBinary bool // whether the binary numeric field extension was used
|
||||||
preferPax bool // use pax header instead of binary numeric header
|
preferPax bool // use pax header instead of binary numeric header
|
||||||
|
hdrBuff [blockSize]byte // buffer to use in writeHeader when writing a regular header
|
||||||
|
paxHdrBuff [blockSize]byte // buffer to use in writeHeader when writing a pax header
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWriter creates a new Writer writing to w.
|
// NewWriter creates a new Writer writing to w.
|
||||||
|
@ -160,7 +162,18 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
|
||||||
// subsecond time resolution, but for now let's just capture
|
// subsecond time resolution, but for now let's just capture
|
||||||
// too long fields or non ascii characters
|
// too long fields or non ascii characters
|
||||||
|
|
||||||
header := make([]byte, blockSize)
|
var header []byte
|
||||||
|
|
||||||
|
// We need to select which scratch buffer to use carefully,
|
||||||
|
// since this method is called recursively to write PAX headers.
|
||||||
|
// If allowPax is true, this is the non-recursive call, and we will use hdrBuff.
|
||||||
|
// If allowPax is false, we are being called by writePAXHeader, and hdrBuff is
|
||||||
|
// already being used by the non-recursive call, so we must use paxHdrBuff.
|
||||||
|
header = tw.hdrBuff[:]
|
||||||
|
if !allowPax {
|
||||||
|
header = tw.paxHdrBuff[:]
|
||||||
|
}
|
||||||
|
copy(header, zeroBlock)
|
||||||
s := slicer(header)
|
s := slicer(header)
|
||||||
|
|
||||||
// keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
|
// keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
|
||||||
|
|
|
@ -454,3 +454,38 @@ func TestUSTARLongName(t *testing.T) {
|
||||||
t.Fatal("Couldn't recover long name")
|
t.Fatal("Couldn't recover long name")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidTypeflagWithPAXHeader(t *testing.T) {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
tw := NewWriter(&buffer)
|
||||||
|
|
||||||
|
fileName := strings.Repeat("ab", 100)
|
||||||
|
|
||||||
|
hdr := &Header{
|
||||||
|
Name: fileName,
|
||||||
|
Size: 4,
|
||||||
|
Typeflag: 0,
|
||||||
|
}
|
||||||
|
if err := tw.WriteHeader(hdr); err != nil {
|
||||||
|
t.Fatalf("Failed to write header: %s", err)
|
||||||
|
}
|
||||||
|
if _, err := tw.Write([]byte("fooo")); err != nil {
|
||||||
|
t.Fatalf("Failed to write the file's data: %s", err)
|
||||||
|
}
|
||||||
|
tw.Close()
|
||||||
|
|
||||||
|
tr := NewReader(&buffer)
|
||||||
|
|
||||||
|
for {
|
||||||
|
header, err := tr.Next()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to read header: %s", err)
|
||||||
|
}
|
||||||
|
if header.Typeflag != 0 {
|
||||||
|
t.Fatalf("Typeflag should've been 0, found %d", header.Typeflag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -267,8 +267,13 @@ func readDirectoryHeader(f *File, r io.Reader) error {
|
||||||
b = b[size:]
|
b = b[size:]
|
||||||
}
|
}
|
||||||
// Should have consumed the whole header.
|
// Should have consumed the whole header.
|
||||||
if len(b) != 0 {
|
// But popular zip & JAR creation tools are broken and
|
||||||
return ErrFormat
|
// may pad extra zeros at the end, so accept those
|
||||||
|
// too. See golang.org/issue/8186.
|
||||||
|
for _, v := range b {
|
||||||
|
if v != 0 {
|
||||||
|
return ErrFormat
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -508,3 +509,25 @@ func returnRecursiveZip() (r io.ReaderAt, size int64) {
|
||||||
b := rZipBytes()
|
b := rZipBytes()
|
||||||
return bytes.NewReader(b), int64(len(b))
|
return bytes.NewReader(b), int64(len(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIssue8186(t *testing.T) {
|
||||||
|
// Directory headers & data found in the TOC of a JAR file.
|
||||||
|
dirEnts := []string{
|
||||||
|
"PK\x01\x02\n\x00\n\x00\x00\b\x00\x004\x9d3?\xaa\x1b\x06\xf0\x81\x02\x00\x00\x81\x02\x00\x00-\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00res/drawable-xhdpi-v4/ic_actionbar_accept.png\xfe\xca\x00\x00\x00",
|
||||||
|
"PK\x01\x02\n\x00\n\x00\x00\b\x00\x004\x9d3?\x90K\x89\xc7t\n\x00\x00t\n\x00\x00\x0e\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\x02\x00\x00resources.arsc\x00\x00\x00",
|
||||||
|
"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xff$\x18\xed3\x03\x00\x00\xb4\b\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\r\x00\x00AndroidManifest.xml",
|
||||||
|
"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\x14\xc5K\xab\x192\x02\x00\xc8\xcd\x04\x00\v\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x10\x00\x00classes.dex",
|
||||||
|
"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?E\x96\nD\xac\x01\x00\x00P\x03\x00\x00&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:C\x02\x00res/layout/actionbar_set_wallpaper.xml",
|
||||||
|
"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?Ļ\x14\xe3\xd8\x01\x00\x00\xd8\x03\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:E\x02\x00res/layout/wallpaper_cropper.xml",
|
||||||
|
"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?}\xc1\x15\x9eZ\x01\x00\x00!\x02\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`G\x02\x00META-INF/MANIFEST.MF",
|
||||||
|
"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xe6\x98Ьo\x01\x00\x00\x84\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfcH\x02\x00META-INF/CERT.SF",
|
||||||
|
"PK\x01\x02\x14\x00\x14\x00\b\b\b\x004\x9d3?\xbfP\x96b\x86\x04\x00\x00\xb2\x06\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9J\x02\x00META-INF/CERT.RSA",
|
||||||
|
}
|
||||||
|
for i, s := range dirEnts {
|
||||||
|
var f File
|
||||||
|
err := readDirectoryHeader(&f, strings.NewReader(s))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error reading #%d: %v", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,12 @@ func NewWriter(w io.Writer) *Writer {
|
||||||
return &Writer{cw: &countWriter{w: bufio.NewWriter(w)}}
|
return &Writer{cw: &countWriter{w: bufio.NewWriter(w)}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flush flushes any buffered data to the underlying writer.
|
||||||
|
// Calling Flush is not normally necessary; calling Close is sufficient.
|
||||||
|
func (w *Writer) Flush() error {
|
||||||
|
return w.cw.w.(*bufio.Writer).Flush()
|
||||||
|
}
|
||||||
|
|
||||||
// Close finishes writing the zip file by writing the central directory.
|
// Close finishes writing the zip file by writing the central directory.
|
||||||
// It does not (and can not) close the underlying writer.
|
// It does not (and can not) close the underlying writer.
|
||||||
func (w *Writer) Close() error {
|
func (w *Writer) Close() error {
|
||||||
|
|
|
@ -6,6 +6,7 @@ package zip
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
|
@ -86,6 +87,24 @@ func TestWriter(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWriterFlush(t *testing.T) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
w := NewWriter(struct{ io.Writer }{&buf})
|
||||||
|
_, err := w.Create("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if buf.Len() > 0 {
|
||||||
|
t.Fatalf("Unexpected %d bytes already in buffer", buf.Len())
|
||||||
|
}
|
||||||
|
if err := w.Flush(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if buf.Len() == 0 {
|
||||||
|
t.Fatal("No bytes written after Flush")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testCreate(t *testing.T, w *Writer, wt *WriteTest) {
|
func testCreate(t *testing.T, w *Writer, wt *WriteTest) {
|
||||||
header := &FileHeader{
|
header := &FileHeader{
|
||||||
Name: wt.Name,
|
Name: wt.Name,
|
||||||
|
|
|
@ -30,8 +30,8 @@ var (
|
||||||
// Reader implements buffering for an io.Reader object.
|
// Reader implements buffering for an io.Reader object.
|
||||||
type Reader struct {
|
type Reader struct {
|
||||||
buf []byte
|
buf []byte
|
||||||
rd io.Reader
|
rd io.Reader // reader provided by the client
|
||||||
r, w int
|
r, w int // buf read and write positions
|
||||||
err error
|
err error
|
||||||
lastByte int
|
lastByte int
|
||||||
lastRuneSize int
|
lastRuneSize int
|
||||||
|
@ -131,18 +131,17 @@ func (b *Reader) Peek(n int) ([]byte, error) {
|
||||||
for b.w-b.r < n && b.err == nil {
|
for b.w-b.r < n && b.err == nil {
|
||||||
b.fill() // b.w-b.r < len(b.buf) => buffer is not full
|
b.fill() // b.w-b.r < len(b.buf) => buffer is not full
|
||||||
}
|
}
|
||||||
m := b.w - b.r
|
|
||||||
if m > n {
|
|
||||||
m = n
|
|
||||||
}
|
|
||||||
var err error
|
var err error
|
||||||
if m < n {
|
if avail := b.w - b.r; avail < n {
|
||||||
|
// not enough data in buffer
|
||||||
|
n = avail
|
||||||
err = b.readErr()
|
err = b.readErr()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = ErrBufferFull
|
err = ErrBufferFull
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b.buf[b.r : b.r+m], err
|
return b.buf[b.r : b.r+n], err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read reads data into p.
|
// Read reads data into p.
|
||||||
|
@ -173,15 +172,13 @@ func (b *Reader) Read(p []byte) (n int, err error) {
|
||||||
return n, b.readErr()
|
return n, b.readErr()
|
||||||
}
|
}
|
||||||
b.fill() // buffer is empty
|
b.fill() // buffer is empty
|
||||||
if b.w == b.r {
|
if b.r == b.w {
|
||||||
return 0, b.readErr()
|
return 0, b.readErr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if n > b.w-b.r {
|
// copy as much as we can
|
||||||
n = b.w - b.r
|
n = copy(p, b.buf[b.r:b.w])
|
||||||
}
|
|
||||||
copy(p[0:n], b.buf[b.r:])
|
|
||||||
b.r += n
|
b.r += n
|
||||||
b.lastByte = int(b.buf[b.r-1])
|
b.lastByte = int(b.buf[b.r-1])
|
||||||
b.lastRuneSize = -1
|
b.lastRuneSize = -1
|
||||||
|
@ -288,7 +285,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer full?
|
// Buffer full?
|
||||||
if n := b.Buffered(); n >= len(b.buf) {
|
if b.Buffered() >= len(b.buf) {
|
||||||
b.r = b.w
|
b.r = b.w
|
||||||
line = b.buf
|
line = b.buf
|
||||||
err = ErrBufferFull
|
err = ErrBufferFull
|
||||||
|
@ -301,6 +298,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
|
||||||
// Handle last byte, if any.
|
// Handle last byte, if any.
|
||||||
if i := len(line) - 1; i >= 0 {
|
if i := len(line) - 1; i >= 0 {
|
||||||
b.lastByte = int(line[i])
|
b.lastByte = int(line[i])
|
||||||
|
b.lastRuneSize = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -458,11 +456,13 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
return n, b.readErr()
|
return n, b.readErr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errNegativeWrite = errors.New("bufio: writer returned negative count from Write")
|
||||||
|
|
||||||
// writeBuf writes the Reader's buffer to the writer.
|
// writeBuf writes the Reader's buffer to the writer.
|
||||||
func (b *Reader) writeBuf(w io.Writer) (int64, error) {
|
func (b *Reader) writeBuf(w io.Writer) (int64, error) {
|
||||||
n, err := w.Write(b.buf[b.r:b.w])
|
n, err := w.Write(b.buf[b.r:b.w])
|
||||||
if n < b.r-b.w {
|
if n < 0 {
|
||||||
panic(errors.New("bufio: writer did not write all data"))
|
panic(errNegativeWrite)
|
||||||
}
|
}
|
||||||
b.r += n
|
b.r += n
|
||||||
return int64(n), err
|
return int64(n), err
|
||||||
|
|
|
@ -31,9 +31,6 @@ func newRot13Reader(r io.Reader) *rot13Reader {
|
||||||
|
|
||||||
func (r13 *rot13Reader) Read(p []byte) (int, error) {
|
func (r13 *rot13Reader) Read(p []byte) (int, error) {
|
||||||
n, err := r13.r.Read(p)
|
n, err := r13.r.Read(p)
|
||||||
if err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
c := p[i] | 0x20 // lowercase byte
|
c := p[i] | 0x20 // lowercase byte
|
||||||
if 'a' <= c && c <= 'm' {
|
if 'a' <= c && c <= 'm' {
|
||||||
|
@ -42,7 +39,7 @@ func (r13 *rot13Reader) Read(p []byte) (int, error) {
|
||||||
p[i] -= 13
|
p[i] -= 13
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n, nil
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call ReadByte to accumulate the text of a file
|
// Call ReadByte to accumulate the text of a file
|
||||||
|
@ -438,7 +435,7 @@ func TestUnreadRuneError(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("unexpected error on ReadRune (2):", err)
|
t.Error("unexpected error on ReadRune (2):", err)
|
||||||
}
|
}
|
||||||
for _ = range buf {
|
for range buf {
|
||||||
_, err = r.ReadByte()
|
_, err = r.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("unexpected error on ReadByte (2):", err)
|
t.Error("unexpected error on ReadByte (2):", err)
|
||||||
|
@ -463,6 +460,18 @@ func TestUnreadRuneError(t *testing.T) {
|
||||||
if r.UnreadRune() == nil {
|
if r.UnreadRune() == nil {
|
||||||
t.Error("expected error after UnreadByte (3)")
|
t.Error("expected error after UnreadByte (3)")
|
||||||
}
|
}
|
||||||
|
// Test error after ReadSlice.
|
||||||
|
_, _, err = r.ReadRune() // reset state
|
||||||
|
if err != nil {
|
||||||
|
t.Error("unexpected error on ReadRune (4):", err)
|
||||||
|
}
|
||||||
|
_, err = r.ReadSlice(0)
|
||||||
|
if err != io.EOF {
|
||||||
|
t.Error("unexpected error on ReadSlice (4):", err)
|
||||||
|
}
|
||||||
|
if r.UnreadRune() == nil {
|
||||||
|
t.Error("expected error after ReadSlice (4)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnreadRuneAtEOF(t *testing.T) {
|
func TestUnreadRuneAtEOF(t *testing.T) {
|
||||||
|
|
|
@ -36,6 +36,7 @@ type Scanner struct {
|
||||||
start int // First non-processed byte in buf.
|
start int // First non-processed byte in buf.
|
||||||
end int // End of data in buf.
|
end int // End of data in buf.
|
||||||
err error // Sticky error.
|
err error // Sticky error.
|
||||||
|
empties int // Count of successive empty tokens.
|
||||||
}
|
}
|
||||||
|
|
||||||
// SplitFunc is the signature of the split function used to tokenize the
|
// SplitFunc is the signature of the split function used to tokenize the
|
||||||
|
@ -64,8 +65,9 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Maximum size used to buffer a token. The actual maximum token size
|
// MaxScanTokenSize is the maximum size used to buffer a token.
|
||||||
// may be smaller as the buffer may need to include, for instance, a newline.
|
// The actual maximum token size may be smaller as the buffer
|
||||||
|
// may need to include, for instance, a newline.
|
||||||
MaxScanTokenSize = 64 * 1024
|
MaxScanTokenSize = 64 * 1024
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -107,11 +109,15 @@ func (s *Scanner) Text() string {
|
||||||
// After Scan returns false, the Err method will return any error that
|
// After Scan returns false, the Err method will return any error that
|
||||||
// occurred during scanning, except that if it was io.EOF, Err
|
// occurred during scanning, except that if it was io.EOF, Err
|
||||||
// will return nil.
|
// will return nil.
|
||||||
|
// Split panics if the split function returns 100 empty tokens without
|
||||||
|
// advancing the input. This is a common error mode for scanners.
|
||||||
func (s *Scanner) Scan() bool {
|
func (s *Scanner) Scan() bool {
|
||||||
// Loop until we have a token.
|
// Loop until we have a token.
|
||||||
for {
|
for {
|
||||||
// See if we can get a token with what we already have.
|
// See if we can get a token with what we already have.
|
||||||
if s.end > s.start {
|
// If we've run out of data but have an error, give the split function
|
||||||
|
// a chance to recover any remaining, possibly empty token.
|
||||||
|
if s.end > s.start || s.err != nil {
|
||||||
advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil)
|
advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.setErr(err)
|
s.setErr(err)
|
||||||
|
@ -122,6 +128,15 @@ func (s *Scanner) Scan() bool {
|
||||||
}
|
}
|
||||||
s.token = token
|
s.token = token
|
||||||
if token != nil {
|
if token != nil {
|
||||||
|
if s.err == nil || advance > 0 {
|
||||||
|
s.empties = 0
|
||||||
|
} else {
|
||||||
|
// Returning tokens not advancing input at EOF.
|
||||||
|
s.empties++
|
||||||
|
if s.empties > 100 {
|
||||||
|
panic("bufio.Scan: 100 empty tokens without progressing")
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,6 +184,7 @@ func (s *Scanner) Scan() bool {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
|
s.empties = 0
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
loop++
|
loop++
|
||||||
|
@ -326,9 +342,6 @@ func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if atEOF && len(data) == 0 {
|
|
||||||
return 0, nil, nil
|
|
||||||
}
|
|
||||||
// Scan until space, marking end of word.
|
// Scan until space, marking end of word.
|
||||||
for width, i := 0, start; i < len(data); i += width {
|
for width, i := 0, start; i < len(data); i += width {
|
||||||
var r rune
|
var r rune
|
||||||
|
@ -342,5 +355,5 @@ func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||||
return len(data), data[start:], nil
|
return len(data), data[start:], nil
|
||||||
}
|
}
|
||||||
// Request more data.
|
// Request more data.
|
||||||
return 0, nil, nil
|
return start, nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ import (
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const smallMaxTokenSize = 256 // Much smaller for more efficient testing.
|
||||||
|
|
||||||
// Test white space table matches the Unicode definition.
|
// Test white space table matches the Unicode definition.
|
||||||
func TestSpace(t *testing.T) {
|
func TestSpace(t *testing.T) {
|
||||||
for r := rune(0); r <= utf8.MaxRune; r++ {
|
for r := rune(0); r <= utf8.MaxRune; r++ {
|
||||||
|
@ -172,7 +174,6 @@ func genLine(buf *bytes.Buffer, lineNum, n int, addNewline bool) {
|
||||||
|
|
||||||
// Test the line splitter, including some carriage returns but no long lines.
|
// Test the line splitter, including some carriage returns but no long lines.
|
||||||
func TestScanLongLines(t *testing.T) {
|
func TestScanLongLines(t *testing.T) {
|
||||||
const smallMaxTokenSize = 256 // Much smaller for more efficient testing.
|
|
||||||
// Build a buffer of lots of line lengths up to but not exceeding smallMaxTokenSize.
|
// Build a buffer of lots of line lengths up to but not exceeding smallMaxTokenSize.
|
||||||
tmp := new(bytes.Buffer)
|
tmp := new(bytes.Buffer)
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
|
@ -404,3 +405,120 @@ func TestBadReader(t *testing.T) {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestScanWordsExcessiveWhiteSpace(t *testing.T) {
|
||||||
|
const word = "ipsum"
|
||||||
|
s := strings.Repeat(" ", 4*smallMaxTokenSize) + word
|
||||||
|
scanner := NewScanner(strings.NewReader(s))
|
||||||
|
scanner.MaxTokenSize(smallMaxTokenSize)
|
||||||
|
scanner.Split(ScanWords)
|
||||||
|
if !scanner.Scan() {
|
||||||
|
t.Fatalf("scan failed: %v", scanner.Err())
|
||||||
|
}
|
||||||
|
if token := scanner.Text(); token != word {
|
||||||
|
t.Fatalf("unexpected token: %v", token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that empty tokens, including at end of line or end of file, are found by the scanner.
|
||||||
|
// Issue 8672: Could miss final empty token.
|
||||||
|
|
||||||
|
func commaSplit(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||||
|
for i := 0; i < len(data); i++ {
|
||||||
|
if data[i] == ',' {
|
||||||
|
return i + 1, data[:i], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !atEOF {
|
||||||
|
return 0, nil, nil
|
||||||
|
}
|
||||||
|
return 0, data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptyTokens(t *testing.T) {
|
||||||
|
s := NewScanner(strings.NewReader("1,2,3,"))
|
||||||
|
values := []string{"1", "2", "3", ""}
|
||||||
|
s.Split(commaSplit)
|
||||||
|
var i int
|
||||||
|
for i = 0; i < len(values); i++ {
|
||||||
|
if !s.Scan() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if s.Text() != values[i] {
|
||||||
|
t.Errorf("%d: expected %q got %q", i, values[i], s.Text())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i != len(values) {
|
||||||
|
t.Errorf("got %d fields, expected %d", i, len(values))
|
||||||
|
}
|
||||||
|
if err := s.Err(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loopAtEOFSplit(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||||
|
if len(data) > 0 {
|
||||||
|
return 1, data[:1], nil
|
||||||
|
}
|
||||||
|
return 0, data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDontLoopForever(t *testing.T) {
|
||||||
|
s := NewScanner(strings.NewReader("abc"))
|
||||||
|
s.Split(loopAtEOFSplit)
|
||||||
|
// Expect a panic
|
||||||
|
defer func() {
|
||||||
|
err := recover()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("should have panicked")
|
||||||
|
}
|
||||||
|
if msg, ok := err.(string); !ok || !strings.Contains(msg, "empty tokens") {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
for count := 0; s.Scan(); count++ {
|
||||||
|
if count > 1000 {
|
||||||
|
t.Fatal("looping")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s.Err() != nil {
|
||||||
|
t.Fatal("after scan:", s.Err())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBlankLines(t *testing.T) {
|
||||||
|
s := NewScanner(strings.NewReader(strings.Repeat("\n", 1000)))
|
||||||
|
for count := 0; s.Scan(); count++ {
|
||||||
|
if count > 2000 {
|
||||||
|
t.Fatal("looping")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s.Err() != nil {
|
||||||
|
t.Fatal("after scan:", s.Err())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type countdown int
|
||||||
|
|
||||||
|
func (c *countdown) split(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||||
|
if *c > 0 {
|
||||||
|
*c--
|
||||||
|
return 1, data[:1], nil
|
||||||
|
}
|
||||||
|
return 0, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the looping-at-EOF check doesn't trigger for merely empty tokens.
|
||||||
|
func TestEmptyLinesOK(t *testing.T) {
|
||||||
|
c := countdown(10000)
|
||||||
|
s := NewScanner(strings.NewReader(strings.Repeat("\n", 10000)))
|
||||||
|
s.Split(c.split)
|
||||||
|
for s.Scan() {
|
||||||
|
}
|
||||||
|
if s.Err() != nil {
|
||||||
|
t.Fatal("after scan:", s.Err())
|
||||||
|
}
|
||||||
|
if c != 0 {
|
||||||
|
t.Fatalf("stopped with %d left to process", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -267,6 +267,8 @@ func Fields(s []byte) [][]byte {
|
||||||
// It splits the slice s at each run of code points c satisfying f(c) and
|
// It splits the slice s at each run of code points c satisfying f(c) and
|
||||||
// returns a slice of subslices of s. If all code points in s satisfy f(c), or
|
// returns a slice of subslices of s. If all code points in s satisfy f(c), or
|
||||||
// len(s) == 0, an empty slice is returned.
|
// len(s) == 0, an empty slice is returned.
|
||||||
|
// FieldsFunc makes no guarantees about the order in which it calls f(c).
|
||||||
|
// If f does not return consistent results for a given c, FieldsFunc may crash.
|
||||||
func FieldsFunc(s []byte, f func(rune) bool) [][]byte {
|
func FieldsFunc(s []byte, f func(rune) bool) [][]byte {
|
||||||
n := 0
|
n := 0
|
||||||
inField := false
|
inField := false
|
||||||
|
@ -377,9 +379,10 @@ func Map(mapping func(r rune) rune, s []byte) []byte {
|
||||||
// Repeat returns a new byte slice consisting of count copies of b.
|
// Repeat returns a new byte slice consisting of count copies of b.
|
||||||
func Repeat(b []byte, count int) []byte {
|
func Repeat(b []byte, count int) []byte {
|
||||||
nb := make([]byte, len(b)*count)
|
nb := make([]byte, len(b)*count)
|
||||||
bp := 0
|
bp := copy(nb, b)
|
||||||
for i := 0; i < count; i++ {
|
for bp < len(nb) {
|
||||||
bp += copy(nb[bp:], b)
|
copy(nb[bp:], nb[:bp])
|
||||||
|
bp *= 2
|
||||||
}
|
}
|
||||||
return nb
|
return nb
|
||||||
}
|
}
|
||||||
|
@ -604,6 +607,9 @@ func Runes(s []byte) []rune {
|
||||||
|
|
||||||
// Replace returns a copy of the slice s with the first n
|
// Replace returns a copy of the slice s with the first n
|
||||||
// non-overlapping instances of old replaced by new.
|
// non-overlapping instances of old replaced by new.
|
||||||
|
// If old is empty, it matches at the beginning of the slice
|
||||||
|
// and after each UTF-8 sequence, yielding up to k+1 replacements
|
||||||
|
// for a k-rune slice.
|
||||||
// If n < 0, there is no limit on the number of replacements.
|
// If n < 0, there is no limit on the number of replacements.
|
||||||
func Replace(s, old, new []byte, n int) []byte {
|
func Replace(s, old, new []byte, n int) []byte {
|
||||||
m := 0
|
m := 0
|
||||||
|
|
|
@ -1232,3 +1232,9 @@ func BenchmarkTrimSpace(b *testing.B) {
|
||||||
TrimSpace(s)
|
TrimSpace(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkRepeat(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Repeat([]byte("-"), 80)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -272,7 +272,7 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
|
||||||
|
|
||||||
case nil:
|
case nil:
|
||||||
|
|
||||||
// These are ordered and grouped to match ../../pkg/go/ast/ast.go
|
// These are ordered and grouped to match ../../go/ast/ast.go
|
||||||
case *ast.Field:
|
case *ast.Field:
|
||||||
if len(n.Names) == 0 && context == "field" {
|
if len(n.Names) == 0 && context == "field" {
|
||||||
f.walk(&n.Type, "embed-type", visit)
|
f.walk(&n.Type, "embed-type", visit)
|
||||||
|
@ -308,6 +308,9 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
|
||||||
if n.High != nil {
|
if n.High != nil {
|
||||||
f.walk(&n.High, "expr", visit)
|
f.walk(&n.High, "expr", visit)
|
||||||
}
|
}
|
||||||
|
if n.Max != nil {
|
||||||
|
f.walk(&n.Max, "expr", visit)
|
||||||
|
}
|
||||||
case *ast.TypeAssertExpr:
|
case *ast.TypeAssertExpr:
|
||||||
f.walk(&n.X, "expr", visit)
|
f.walk(&n.X, "expr", visit)
|
||||||
f.walk(&n.Type, "type", visit)
|
f.walk(&n.Type, "type", visit)
|
||||||
|
|
|
@ -152,7 +152,7 @@ In C, a function argument written as a fixed size array
|
||||||
actually requires a pointer to the first element of the array.
|
actually requires a pointer to the first element of the array.
|
||||||
C compilers are aware of this calling convention and adjust
|
C compilers are aware of this calling convention and adjust
|
||||||
the call accordingly, but Go cannot. In Go, you must pass
|
the call accordingly, but Go cannot. In Go, you must pass
|
||||||
the pointer to the first element explicitly: C.f(&x[0]).
|
the pointer to the first element explicitly: C.f(&C.x[0]).
|
||||||
|
|
||||||
A few special functions convert between Go and C types
|
A few special functions convert between Go and C types
|
||||||
by making copies of the data. In pseudo-Go definitions:
|
by making copies of the data. In pseudo-Go definitions:
|
||||||
|
|
|
@ -229,7 +229,8 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
// Determine kinds for names we already know about,
|
// Determine kinds for names we already know about,
|
||||||
// like #defines or 'struct foo', before bothering with gcc.
|
// like #defines or 'struct foo', before bothering with gcc.
|
||||||
var names, needType []*Name
|
var names, needType []*Name
|
||||||
for _, n := range f.Name {
|
for _, key := range nameKeys(f.Name) {
|
||||||
|
n := f.Name[key]
|
||||||
// If we've already found this name as a #define
|
// If we've already found this name as a #define
|
||||||
// and we can translate it as a constant value, do so.
|
// and we can translate it as a constant value, do so.
|
||||||
if n.Define != "" {
|
if n.Define != "" {
|
||||||
|
@ -331,6 +332,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
const (
|
const (
|
||||||
notType = 1 << iota
|
notType = 1 << iota
|
||||||
notConst
|
notConst
|
||||||
|
notDeclared
|
||||||
)
|
)
|
||||||
for _, line := range strings.Split(stderr, "\n") {
|
for _, line := range strings.Split(stderr, "\n") {
|
||||||
if !strings.Contains(line, ": error:") {
|
if !strings.Contains(line, ": error:") {
|
||||||
|
@ -365,7 +367,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
completed = true
|
completed = true
|
||||||
|
|
||||||
case "not-declared":
|
case "not-declared":
|
||||||
error_(token.NoPos, "%s", strings.TrimSpace(line[c2+1:]))
|
sniff[i] |= notDeclared
|
||||||
case "not-type":
|
case "not-type":
|
||||||
sniff[i] |= notType
|
sniff[i] |= notType
|
||||||
case "not-const":
|
case "not-const":
|
||||||
|
@ -374,12 +376,12 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !completed {
|
if !completed {
|
||||||
fatalf("%s did not produce error at completed:1\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
|
fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", p.gccBaseCmd()[0], b.Bytes(), stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, n := range names {
|
for i, n := range names {
|
||||||
switch sniff[i] {
|
switch sniff[i] {
|
||||||
case 0:
|
default:
|
||||||
error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
|
error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
|
||||||
case notType:
|
case notType:
|
||||||
n.Kind = "const"
|
n.Kind = "const"
|
||||||
|
@ -390,6 +392,14 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if nerrors > 0 {
|
if nerrors > 0 {
|
||||||
|
// Check if compiling the preamble by itself causes any errors,
|
||||||
|
// because the messages we've printed out so far aren't helpful
|
||||||
|
// to users debugging preamble mistakes. See issue 8442.
|
||||||
|
preambleErrors := p.gccErrors([]byte(f.Preamble))
|
||||||
|
if len(preambleErrors) > 0 {
|
||||||
|
error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors)
|
||||||
|
}
|
||||||
|
|
||||||
fatalf("unresolved names")
|
fatalf("unresolved names")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,7 +659,13 @@ func (p *Package) rewriteRef(f *File) {
|
||||||
f.Name[fpName] = name
|
f.Name[fpName] = name
|
||||||
}
|
}
|
||||||
r.Name = name
|
r.Name = name
|
||||||
expr = ast.NewIdent(name.Mangle)
|
// Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
|
||||||
|
// function is defined in out.go and simply returns its argument. See
|
||||||
|
// issue 7757.
|
||||||
|
expr = &ast.CallExpr{
|
||||||
|
Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
|
||||||
|
Args: []ast.Expr{ast.NewIdent(name.Mangle)},
|
||||||
|
}
|
||||||
} else if r.Name.Kind == "type" {
|
} else if r.Name.Kind == "type" {
|
||||||
// Okay - might be new(T)
|
// Okay - might be new(T)
|
||||||
expr = r.Name.Type.Go
|
expr = r.Name.Type.Go
|
||||||
|
@ -928,9 +944,8 @@ type typeConv struct {
|
||||||
|
|
||||||
// Map from types to incomplete pointers to those types.
|
// Map from types to incomplete pointers to those types.
|
||||||
ptrs map[dwarf.Type][]*Type
|
ptrs map[dwarf.Type][]*Type
|
||||||
|
// Keys of ptrs in insertion order (deterministic worklist)
|
||||||
// Fields to be processed by godefsField after completing pointers.
|
ptrKeys []dwarf.Type
|
||||||
todoFlds [][]*ast.Field
|
|
||||||
|
|
||||||
// Predeclared types.
|
// Predeclared types.
|
||||||
bool ast.Expr
|
bool ast.Expr
|
||||||
|
@ -940,9 +955,9 @@ type typeConv struct {
|
||||||
float32, float64 ast.Expr
|
float32, float64 ast.Expr
|
||||||
complex64, complex128 ast.Expr
|
complex64, complex128 ast.Expr
|
||||||
void ast.Expr
|
void ast.Expr
|
||||||
unsafePointer ast.Expr
|
|
||||||
string ast.Expr
|
string ast.Expr
|
||||||
goVoid ast.Expr // _Ctype_void, denotes C's void
|
goVoid ast.Expr // _Ctype_void, denotes C's void
|
||||||
|
goVoidPtr ast.Expr // unsafe.Pointer or *byte
|
||||||
|
|
||||||
ptrSize int64
|
ptrSize int64
|
||||||
intSize int64
|
intSize int64
|
||||||
|
@ -972,10 +987,17 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
|
||||||
c.float64 = c.Ident("float64")
|
c.float64 = c.Ident("float64")
|
||||||
c.complex64 = c.Ident("complex64")
|
c.complex64 = c.Ident("complex64")
|
||||||
c.complex128 = c.Ident("complex128")
|
c.complex128 = c.Ident("complex128")
|
||||||
c.unsafePointer = c.Ident("unsafe.Pointer")
|
|
||||||
c.void = c.Ident("void")
|
c.void = c.Ident("void")
|
||||||
c.string = c.Ident("string")
|
c.string = c.Ident("string")
|
||||||
c.goVoid = c.Ident("_Ctype_void")
|
c.goVoid = c.Ident("_Ctype_void")
|
||||||
|
|
||||||
|
// Normally cgo translates void* to unsafe.Pointer,
|
||||||
|
// but for historical reasons -cdefs and -godefs use *byte instead.
|
||||||
|
if *cdefs || *godefs {
|
||||||
|
c.goVoidPtr = &ast.StarExpr{X: c.byte}
|
||||||
|
} else {
|
||||||
|
c.goVoidPtr = c.Ident("unsafe.Pointer")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// base strips away qualifiers and typedefs to get the underlying type
|
// base strips away qualifiers and typedefs to get the underlying type
|
||||||
|
@ -1037,29 +1059,22 @@ func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FinishType completes any outstanding type mapping work.
|
// FinishType completes any outstanding type mapping work.
|
||||||
// In particular, it resolves incomplete pointer types and also runs
|
// In particular, it resolves incomplete pointer types.
|
||||||
// godefsFields on any new struct types.
|
|
||||||
func (c *typeConv) FinishType(pos token.Pos) {
|
func (c *typeConv) FinishType(pos token.Pos) {
|
||||||
// Completing one pointer type might produce more to complete.
|
// Completing one pointer type might produce more to complete.
|
||||||
// Keep looping until they're all done.
|
// Keep looping until they're all done.
|
||||||
for len(c.ptrs) > 0 {
|
for len(c.ptrKeys) > 0 {
|
||||||
for dtype := range c.ptrs {
|
dtype := c.ptrKeys[0]
|
||||||
// Note Type might invalidate c.ptrs[dtype].
|
c.ptrKeys = c.ptrKeys[1:]
|
||||||
t := c.Type(dtype, pos)
|
|
||||||
for _, ptr := range c.ptrs[dtype] {
|
|
||||||
ptr.Go.(*ast.StarExpr).X = t.Go
|
|
||||||
ptr.C.Set("%s*", t.C)
|
|
||||||
}
|
|
||||||
delete(c.ptrs, dtype)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that pointer types are completed, we can invoke godefsFields
|
// Note Type might invalidate c.ptrs[dtype].
|
||||||
// to rewrite struct definitions.
|
t := c.Type(dtype, pos)
|
||||||
for _, fld := range c.todoFlds {
|
for _, ptr := range c.ptrs[dtype] {
|
||||||
godefsFields(fld)
|
ptr.Go.(*ast.StarExpr).X = t.Go
|
||||||
|
ptr.C.Set("%s*", t.C)
|
||||||
|
}
|
||||||
|
c.ptrs[dtype] = nil // retain the map key
|
||||||
}
|
}
|
||||||
c.todoFlds = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type returns a *Type with the same memory layout as
|
// Type returns a *Type with the same memory layout as
|
||||||
|
@ -1072,12 +1087,6 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
// clang won't generate DW_AT_byte_size for pointer types,
|
|
||||||
// so we have to fix it here.
|
|
||||||
if dt, ok := base(dtype).(*dwarf.PtrType); ok && dt.ByteSize == -1 {
|
|
||||||
dt.ByteSize = c.ptrSize
|
|
||||||
}
|
|
||||||
|
|
||||||
t := new(Type)
|
t := new(Type)
|
||||||
t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
|
t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
|
||||||
t.Align = -1
|
t.Align = -1
|
||||||
|
@ -1101,12 +1110,20 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||||
t.Go = c.Opaque(t.Size)
|
t.Go = c.Opaque(t.Size)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
count := dt.Count
|
||||||
|
if count == -1 {
|
||||||
|
// Indicates flexible array member, which Go doesn't support.
|
||||||
|
// Translate to zero-length array instead.
|
||||||
|
count = 0
|
||||||
|
}
|
||||||
sub := c.Type(dt.Type, pos)
|
sub := c.Type(dt.Type, pos)
|
||||||
t.Align = sub.Align
|
t.Align = sub.Align
|
||||||
t.Go = &ast.ArrayType{
|
t.Go = &ast.ArrayType{
|
||||||
Len: c.intExpr(dt.Count),
|
Len: c.intExpr(count),
|
||||||
Elt: sub.Go,
|
Elt: sub.Go,
|
||||||
}
|
}
|
||||||
|
// Recalculate t.Size now that we know sub.Size.
|
||||||
|
t.Size = count * sub.Size
|
||||||
t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
|
t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
|
||||||
|
|
||||||
case *dwarf.BoolType:
|
case *dwarf.BoolType:
|
||||||
|
@ -1207,11 +1224,15 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
case *dwarf.PtrType:
|
case *dwarf.PtrType:
|
||||||
|
// Clang doesn't emit DW_AT_byte_size for pointer types.
|
||||||
|
if t.Size != c.ptrSize && t.Size != -1 {
|
||||||
|
fatalf("%s: unexpected: %d-byte pointer type - %s", lineno(pos), t.Size, dtype)
|
||||||
|
}
|
||||||
|
t.Size = c.ptrSize
|
||||||
t.Align = c.ptrSize
|
t.Align = c.ptrSize
|
||||||
|
|
||||||
// Translate void* as unsafe.Pointer
|
|
||||||
if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
|
if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
|
||||||
t.Go = c.unsafePointer
|
t.Go = c.goVoidPtr
|
||||||
t.C.Set("void*")
|
t.C.Set("void*")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -1219,6 +1240,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||||
// Placeholder initialization; completed in FinishType.
|
// Placeholder initialization; completed in FinishType.
|
||||||
t.Go = &ast.StarExpr{}
|
t.Go = &ast.StarExpr{}
|
||||||
t.C.Set("<incomplete>*")
|
t.C.Set("<incomplete>*")
|
||||||
|
if _, ok := c.ptrs[dt.Type]; !ok {
|
||||||
|
c.ptrKeys = append(c.ptrKeys, dt.Type)
|
||||||
|
}
|
||||||
c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t)
|
c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t)
|
||||||
|
|
||||||
case *dwarf.QualType:
|
case *dwarf.QualType:
|
||||||
|
@ -1379,34 +1403,24 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Size <= 0 {
|
if t.Size < 0 {
|
||||||
// Clang does not record the size of a pointer in its DWARF entry,
|
// Unsized types are [0]byte, unless they're typedefs of other types
|
||||||
// so if dtype is an array, the call to dtype.Size at the top of the function
|
// or structs with tags.
|
||||||
// computed the size as the array length * 0 = 0.
|
// if so, use the name we've already defined.
|
||||||
// The type switch called Type (this function) recursively on the pointer
|
t.Size = 0
|
||||||
// entry, and the code near the top of the function updated the size to
|
switch dt := dtype.(type) {
|
||||||
// be correct, so calling dtype.Size again will produce the correct value.
|
case *dwarf.TypedefType:
|
||||||
t.Size = dtype.Size()
|
// ok
|
||||||
if t.Size < 0 {
|
case *dwarf.StructType:
|
||||||
// Unsized types are [0]byte, unless they're typedefs of other types
|
if dt.StructName != "" {
|
||||||
// or structs with tags.
|
break
|
||||||
// if so, use the name we've already defined.
|
|
||||||
t.Size = 0
|
|
||||||
switch dt := dtype.(type) {
|
|
||||||
case *dwarf.TypedefType:
|
|
||||||
// ok
|
|
||||||
case *dwarf.StructType:
|
|
||||||
if dt.StructName != "" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
t.Go = c.Opaque(0)
|
|
||||||
default:
|
|
||||||
t.Go = c.Opaque(0)
|
|
||||||
}
|
}
|
||||||
if t.C.Empty() {
|
t.Go = c.Opaque(0)
|
||||||
t.C.Set("void")
|
default:
|
||||||
}
|
t.Go = c.Opaque(0)
|
||||||
return t
|
}
|
||||||
|
if t.C.Empty() {
|
||||||
|
t.C.Set("void")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1538,6 +1552,9 @@ func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
|
||||||
|
|
||||||
// Struct conversion: return Go and (6g) C syntax for type.
|
// Struct conversion: return Go and (6g) C syntax for type.
|
||||||
func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
|
func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
|
||||||
|
// Minimum alignment for a struct is 1 byte.
|
||||||
|
align = 1
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString("struct {")
|
buf.WriteString("struct {")
|
||||||
fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
|
fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
|
||||||
|
@ -1579,7 +1596,27 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
|
||||||
fld = c.pad(fld, f.ByteOffset-off)
|
fld = c.pad(fld, f.ByteOffset-off)
|
||||||
off = f.ByteOffset
|
off = f.ByteOffset
|
||||||
}
|
}
|
||||||
t := c.Type(f.Type, pos)
|
|
||||||
|
name := f.Name
|
||||||
|
ft := f.Type
|
||||||
|
|
||||||
|
// In godefs or cdefs mode, if this field is a C11
|
||||||
|
// anonymous union then treat the first field in the
|
||||||
|
// union as the field in the struct. This handles
|
||||||
|
// cases like the glibc <sys/resource.h> file; see
|
||||||
|
// issue 6677.
|
||||||
|
if *godefs || *cdefs {
|
||||||
|
if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] {
|
||||||
|
name = st.Field[0].Name
|
||||||
|
ident[name] = name
|
||||||
|
ft = st.Field[0].Type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Handle fields that are anonymous structs by
|
||||||
|
// promoting the fields of the inner struct.
|
||||||
|
|
||||||
|
t := c.Type(ft, pos)
|
||||||
tgo := t.Go
|
tgo := t.Go
|
||||||
size := t.Size
|
size := t.Size
|
||||||
talign := t.Align
|
talign := t.Align
|
||||||
|
@ -1598,17 +1635,18 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
|
||||||
talign = size
|
talign = size
|
||||||
}
|
}
|
||||||
|
|
||||||
if talign > 0 && f.ByteOffset%talign != 0 {
|
if talign > 0 && f.ByteOffset%talign != 0 && !*cdefs {
|
||||||
// Drop misaligned fields, the same way we drop integer bit fields.
|
// Drop misaligned fields, the same way we drop integer bit fields.
|
||||||
// The goal is to make available what can be made available.
|
// The goal is to make available what can be made available.
|
||||||
// Otherwise one bad and unneeded field in an otherwise okay struct
|
// Otherwise one bad and unneeded field in an otherwise okay struct
|
||||||
// makes the whole program not compile. Much of the time these
|
// makes the whole program not compile. Much of the time these
|
||||||
// structs are in system headers that cannot be corrected.
|
// structs are in system headers that cannot be corrected.
|
||||||
|
// Exception: In -cdefs mode, we use #pragma pack, so misaligned
|
||||||
|
// fields should still work.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
n := len(fld)
|
n := len(fld)
|
||||||
fld = fld[0 : n+1]
|
fld = fld[0 : n+1]
|
||||||
name := f.Name
|
|
||||||
if name == "" {
|
if name == "" {
|
||||||
name = fmt.Sprintf("anon%d", anon)
|
name = fmt.Sprintf("anon%d", anon)
|
||||||
anon++
|
anon++
|
||||||
|
@ -1635,7 +1673,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
|
||||||
csyntax = buf.String()
|
csyntax = buf.String()
|
||||||
|
|
||||||
if *godefs || *cdefs {
|
if *godefs || *cdefs {
|
||||||
c.todoFlds = append(c.todoFlds, fld)
|
godefsFields(fld)
|
||||||
}
|
}
|
||||||
expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
|
expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
|
||||||
return
|
return
|
||||||
|
@ -1673,19 +1711,6 @@ func godefsFields(fld []*ast.Field) {
|
||||||
n.Name = upper(n.Name)
|
n.Name = upper(n.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p := &f.Type
|
|
||||||
t := *p
|
|
||||||
if star, ok := t.(*ast.StarExpr); ok {
|
|
||||||
star = &ast.StarExpr{X: star.X}
|
|
||||||
*p = star
|
|
||||||
p = &star.X
|
|
||||||
t = *p
|
|
||||||
}
|
|
||||||
if id, ok := t.(*ast.Ident); ok {
|
|
||||||
if id.Name == "unsafe.Pointer" {
|
|
||||||
*p = ast.NewIdent("*byte")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ func (p *Package) writeDefs() {
|
||||||
fmt.Fprintf(fm, "int main() { return 0; }\n")
|
fmt.Fprintf(fm, "int main() { return 0; }\n")
|
||||||
if *importRuntimeCgo {
|
if *importRuntimeCgo {
|
||||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
|
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
|
||||||
|
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
|
||||||
} else {
|
} else {
|
||||||
// If we're not importing runtime/cgo, we *are* runtime/cgo,
|
// If we're not importing runtime/cgo, we *are* runtime/cgo,
|
||||||
// which provides crosscall2. We just need a prototype.
|
// which provides crosscall2. We just need a prototype.
|
||||||
|
@ -58,16 +59,14 @@ func (p *Package) writeDefs() {
|
||||||
fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
|
fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
|
||||||
fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
|
fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
|
||||||
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
|
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
|
||||||
if *importSyscall {
|
|
||||||
fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
|
|
||||||
}
|
|
||||||
if !*gccgo && *importRuntimeCgo {
|
if !*gccgo && *importRuntimeCgo {
|
||||||
fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
|
fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n")
|
|
||||||
if *importSyscall {
|
if *importSyscall {
|
||||||
fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int32) { *dst = syscall.Errno(x) }\n")
|
fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
|
||||||
|
fmt.Fprintf(fgo2, "var _ syscall.Errno\n")
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
|
||||||
|
|
||||||
typedefNames := make([]string, 0, len(typedef))
|
typedefNames := make([]string, 0, len(typedef))
|
||||||
for name := range typedef {
|
for name := range typedef {
|
||||||
|
@ -87,9 +86,10 @@ func (p *Package) writeDefs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if *gccgo {
|
if *gccgo {
|
||||||
fmt.Fprintf(fc, p.cPrologGccgo())
|
fmt.Fprint(fc, p.cPrologGccgo())
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(fc, cProlog)
|
fmt.Fprint(fc, cProlog)
|
||||||
|
fmt.Fprint(fgo2, goProlog)
|
||||||
}
|
}
|
||||||
|
|
||||||
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
|
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
|
||||||
|
@ -130,6 +130,7 @@ func (p *Package) writeDefs() {
|
||||||
fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle)
|
fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle)
|
||||||
fmt.Fprintf(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C)
|
fmt.Fprintf(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C)
|
||||||
} else {
|
} else {
|
||||||
|
fmt.Fprintf(fc, "#pragma dataflag NOPTR /* C pointer, not heap pointer */ \n")
|
||||||
fmt.Fprintf(fc, "void *·%s = %s%s;\n", n.Mangle, amp, n.C)
|
fmt.Fprintf(fc, "void *·%s = %s%s;\n", n.Mangle, amp, n.C)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fc, "\n")
|
fmt.Fprintf(fc, "\n")
|
||||||
|
@ -296,10 +297,6 @@ func (p *Package) structType(n *Name) (string, int64) {
|
||||||
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
|
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
|
||||||
off += pad
|
off += pad
|
||||||
}
|
}
|
||||||
if n.AddError {
|
|
||||||
fmt.Fprint(&buf, "\t\tint e[2*sizeof(void *)/sizeof(int)]; /* error */\n")
|
|
||||||
off += 2 * p.PtrSize
|
|
||||||
}
|
|
||||||
if off == 0 {
|
if off == 0 {
|
||||||
fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
|
fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
|
||||||
}
|
}
|
||||||
|
@ -334,19 +331,18 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builtins defined in the C prolog.
|
// Builtins defined in the C prolog.
|
||||||
inProlog := name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" || name == "_CMalloc"
|
inProlog := builtinDefs[name] != ""
|
||||||
|
cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
|
||||||
|
paramnames := []string(nil)
|
||||||
|
for i, param := range d.Type.Params.List {
|
||||||
|
paramName := fmt.Sprintf("p%d", i)
|
||||||
|
param.Names = []*ast.Ident{ast.NewIdent(paramName)}
|
||||||
|
paramnames = append(paramnames, paramName)
|
||||||
|
}
|
||||||
|
|
||||||
if *gccgo {
|
if *gccgo {
|
||||||
// Gccgo style hooks.
|
// Gccgo style hooks.
|
||||||
fmt.Fprint(fgo2, "\n")
|
fmt.Fprint(fgo2, "\n")
|
||||||
cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
|
|
||||||
paramnames := []string(nil)
|
|
||||||
for i, param := range d.Type.Params.List {
|
|
||||||
paramName := fmt.Sprintf("p%d", i)
|
|
||||||
param.Names = []*ast.Ident{ast.NewIdent(paramName)}
|
|
||||||
paramnames = append(paramnames, paramName)
|
|
||||||
}
|
|
||||||
|
|
||||||
conf.Fprint(fgo2, fset, d)
|
conf.Fprint(fgo2, fset, d)
|
||||||
fmt.Fprint(fgo2, " {\n")
|
fmt.Fprint(fgo2, " {\n")
|
||||||
if !inProlog {
|
if !inProlog {
|
||||||
|
@ -383,7 +379,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
|
||||||
fmt.Fprint(fgo2, "}\n")
|
fmt.Fprint(fgo2, "}\n")
|
||||||
|
|
||||||
// declare the C function.
|
// declare the C function.
|
||||||
fmt.Fprintf(fgo2, "//extern _cgo%s%s\n", cPrefix, n.Mangle)
|
fmt.Fprintf(fgo2, "//extern %s\n", cname)
|
||||||
d.Name = ast.NewIdent(cname)
|
d.Name = ast.NewIdent(cname)
|
||||||
if n.AddError {
|
if n.AddError {
|
||||||
l := d.Type.Results.List
|
l := d.Type.Results.List
|
||||||
|
@ -394,61 +390,50 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conf.Fprint(fgo2, fset, d)
|
|
||||||
fmt.Fprint(fgo2, "\n")
|
|
||||||
|
|
||||||
if inProlog {
|
if inProlog {
|
||||||
|
fmt.Fprint(fgo2, builtinDefs[name])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var argSize int64
|
|
||||||
_, argSize = p.structType(n)
|
|
||||||
|
|
||||||
// C wrapper calls into gcc, passing a pointer to the argument frame.
|
// C wrapper calls into gcc, passing a pointer to the argument frame.
|
||||||
fmt.Fprintf(fc, "#pragma cgo_import_static _cgo%s%s\n", cPrefix, n.Mangle)
|
fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", cname)
|
||||||
fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle)
|
fmt.Fprintf(fc, "void %s(void*);\n", cname)
|
||||||
fmt.Fprintf(fc, "\n")
|
fmt.Fprintf(fc, "#pragma dataflag NOPTR\n")
|
||||||
fmt.Fprintf(fc, "void\n")
|
fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname)
|
||||||
if argSize == 0 {
|
|
||||||
argSize++
|
nret := 0
|
||||||
|
if !void {
|
||||||
|
d.Type.Results.List[0].Names = []*ast.Ident{ast.NewIdent("r1")}
|
||||||
|
nret = 1
|
||||||
}
|
}
|
||||||
// TODO(rsc): The struct here should declare pointers only where
|
|
||||||
// there are pointers in the actual argument frame.
|
|
||||||
// This is a workaround for golang.org/issue/6397.
|
|
||||||
fmt.Fprintf(fc, "·%s(struct{", n.Mangle)
|
|
||||||
if n := argSize / p.PtrSize; n > 0 {
|
|
||||||
fmt.Fprintf(fc, "void *y[%d];", n)
|
|
||||||
}
|
|
||||||
if n := argSize % p.PtrSize; n > 0 {
|
|
||||||
fmt.Fprintf(fc, "uint8 x[%d];", n)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(fc, "}p)\n")
|
|
||||||
fmt.Fprintf(fc, "{\n")
|
|
||||||
fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle)
|
|
||||||
if n.AddError {
|
if n.AddError {
|
||||||
// gcc leaves errno in first word of interface at end of p.
|
d.Type.Results.List[nret].Names = []*ast.Ident{ast.NewIdent("r2")}
|
||||||
// check whether it is zero; if so, turn interface into nil.
|
|
||||||
// if not, turn interface into errno.
|
|
||||||
// Go init function initializes ·_Cerrno with an os.Errno
|
|
||||||
// for us to copy.
|
|
||||||
fmt.Fprintln(fc, ` {
|
|
||||||
int32 e;
|
|
||||||
void **v;
|
|
||||||
v = (void**)(&p+1) - 2; /* v = final two void* of p */
|
|
||||||
e = *(int32*)v;
|
|
||||||
v[0] = (void*)0xdeadbeef;
|
|
||||||
v[1] = (void*)0xdeadbeef;
|
|
||||||
if(e == 0) {
|
|
||||||
/* nil interface */
|
|
||||||
v[0] = 0;
|
|
||||||
v[1] = 0;
|
|
||||||
} else {
|
|
||||||
·_Cerrno(v, e); /* fill in v as error for errno e */
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fc, "}\n")
|
|
||||||
fmt.Fprintf(fc, "\n")
|
fmt.Fprint(fgo2, "\n")
|
||||||
|
fmt.Fprintf(fgo2, "var %s unsafe.Pointer\n", cname)
|
||||||
|
conf.Fprint(fgo2, fset, d)
|
||||||
|
fmt.Fprint(fgo2, " {\n")
|
||||||
|
|
||||||
|
// NOTE: Using uintptr to hide from escape analysis.
|
||||||
|
arg := "0"
|
||||||
|
if len(paramnames) > 0 {
|
||||||
|
arg = "uintptr(unsafe.Pointer(&p0))"
|
||||||
|
} else if !void {
|
||||||
|
arg = "uintptr(unsafe.Pointer(&r1))"
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix := ""
|
||||||
|
if n.AddError {
|
||||||
|
prefix = "errno := "
|
||||||
|
}
|
||||||
|
fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall_errno(%s, %s)\n", prefix, cname, arg)
|
||||||
|
if n.AddError {
|
||||||
|
fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(fgo2, "\treturn\n")
|
||||||
|
fmt.Fprintf(fgo2, "}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeOutput creates stubs for a specific source file to be compiled by 6g
|
// writeOutput creates stubs for a specific source file to be compiled by 6g
|
||||||
|
@ -521,7 +506,11 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
|
||||||
|
|
||||||
// Gcc wrapper unpacks the C argument struct
|
// Gcc wrapper unpacks the C argument struct
|
||||||
// and calls the actual C function.
|
// and calls the actual C function.
|
||||||
fmt.Fprintf(fgcc, "void\n")
|
if n.AddError {
|
||||||
|
fmt.Fprintf(fgcc, "int\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(fgcc, "void\n")
|
||||||
|
}
|
||||||
fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
|
fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
|
||||||
fmt.Fprintf(fgcc, "{\n")
|
fmt.Fprintf(fgcc, "{\n")
|
||||||
if n.AddError {
|
if n.AddError {
|
||||||
|
@ -531,9 +520,13 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
|
||||||
// Use packed attribute to force no padding in this struct in case
|
// Use packed attribute to force no padding in this struct in case
|
||||||
// gcc has different packing requirements.
|
// gcc has different packing requirements.
|
||||||
fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute())
|
fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute())
|
||||||
|
if n.FuncType.Result != nil {
|
||||||
|
// Save the stack top for use below.
|
||||||
|
fmt.Fprintf(fgcc, "\tchar *stktop = _cgo_topofstack();\n")
|
||||||
|
}
|
||||||
fmt.Fprintf(fgcc, "\t")
|
fmt.Fprintf(fgcc, "\t")
|
||||||
if t := n.FuncType.Result; t != nil {
|
if t := n.FuncType.Result; t != nil {
|
||||||
fmt.Fprintf(fgcc, "a->r = ")
|
fmt.Fprintf(fgcc, "__typeof__(a->r) r = ")
|
||||||
if c := t.C.String(); c[len(c)-1] == '*' {
|
if c := t.C.String(); c[len(c)-1] == '*' {
|
||||||
fmt.Fprint(fgcc, "(__typeof__(a->r)) ")
|
fmt.Fprint(fgcc, "(__typeof__(a->r)) ")
|
||||||
}
|
}
|
||||||
|
@ -556,8 +549,15 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
|
||||||
fmt.Fprintf(fgcc, "a->p%d", i)
|
fmt.Fprintf(fgcc, "a->p%d", i)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgcc, ");\n")
|
fmt.Fprintf(fgcc, ");\n")
|
||||||
|
if n.FuncType.Result != nil {
|
||||||
|
// The cgo call may have caused a stack copy (via a callback).
|
||||||
|
// Adjust the return value pointer appropriately.
|
||||||
|
fmt.Fprintf(fgcc, "\ta = (void*)((char*)a + (_cgo_topofstack() - stktop));\n")
|
||||||
|
// Save the return value.
|
||||||
|
fmt.Fprintf(fgcc, "\ta->r = r;\n")
|
||||||
|
}
|
||||||
if n.AddError {
|
if n.AddError {
|
||||||
fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n")
|
fmt.Fprintf(fgcc, "\treturn errno;\n")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgcc, "}\n")
|
fmt.Fprintf(fgcc, "}\n")
|
||||||
fmt.Fprintf(fgcc, "\n")
|
fmt.Fprintf(fgcc, "\n")
|
||||||
|
@ -1016,7 +1016,7 @@ func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {
|
||||||
fn(i, r.Type)
|
fn(i, r.Type)
|
||||||
i++
|
i++
|
||||||
} else {
|
} else {
|
||||||
for _ = range r.Names {
|
for range r.Names {
|
||||||
fn(i, r.Type)
|
fn(i, r.Type)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
@ -1143,21 +1143,17 @@ __cgo_size_assert(__cgo_long_long, 8)
|
||||||
__cgo_size_assert(float, 4)
|
__cgo_size_assert(float, 4)
|
||||||
__cgo_size_assert(double, 8)
|
__cgo_size_assert(double, 8)
|
||||||
|
|
||||||
|
extern char* _cgo_topofstack(void);
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
`
|
`
|
||||||
|
|
||||||
const builtinProlog = `
|
const builtinProlog = `
|
||||||
#include <sys/types.h> /* for size_t below */
|
#include <stddef.h> /* for ptrdiff_t and size_t below */
|
||||||
|
|
||||||
/* Define intgo when compiling with GCC. */
|
/* Define intgo when compiling with GCC. */
|
||||||
#ifdef __PTRDIFF_TYPE__
|
typedef ptrdiff_t intgo;
|
||||||
typedef __PTRDIFF_TYPE__ intgo;
|
|
||||||
#elif defined(_LP64)
|
|
||||||
typedef long long intgo;
|
|
||||||
#else
|
|
||||||
typedef int intgo;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct { char *p; intgo n; } _GoString_;
|
typedef struct { char *p; intgo n; } _GoString_;
|
||||||
typedef struct { char *p; intgo n; intgo c; } _GoBytes_;
|
typedef struct { char *p; intgo n; intgo c; } _GoBytes_;
|
||||||
|
@ -1171,47 +1167,86 @@ void *_CMalloc(size_t);
|
||||||
const cProlog = `
|
const cProlog = `
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
#include "cgocall.h"
|
#include "cgocall.h"
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
#pragma dataflag NOPTR
|
||||||
|
static void *cgocall_errno = runtime·cgocall_errno;
|
||||||
|
#pragma dataflag NOPTR
|
||||||
|
void *·_cgo_runtime_cgocall_errno = &cgocall_errno;
|
||||||
|
|
||||||
|
#pragma dataflag NOPTR
|
||||||
|
static void *runtime_gostring = runtime·gostring;
|
||||||
|
#pragma dataflag NOPTR
|
||||||
|
void *·_cgo_runtime_gostring = &runtime_gostring;
|
||||||
|
|
||||||
|
#pragma dataflag NOPTR
|
||||||
|
static void *runtime_gostringn = runtime·gostringn;
|
||||||
|
#pragma dataflag NOPTR
|
||||||
|
void *·_cgo_runtime_gostringn = &runtime_gostringn;
|
||||||
|
|
||||||
|
#pragma dataflag NOPTR
|
||||||
|
static void *runtime_gobytes = runtime·gobytes;
|
||||||
|
#pragma dataflag NOPTR
|
||||||
|
void *·_cgo_runtime_gobytes = &runtime_gobytes;
|
||||||
|
|
||||||
|
#pragma dataflag NOPTR
|
||||||
|
static void *runtime_cmalloc = runtime·cmalloc;
|
||||||
|
#pragma dataflag NOPTR
|
||||||
|
void *·_cgo_runtime_cmalloc = &runtime_cmalloc;
|
||||||
|
|
||||||
void ·_Cerrno(void*, int32);
|
void ·_Cerrno(void*, int32);
|
||||||
|
`
|
||||||
|
|
||||||
void
|
const goProlog = `
|
||||||
·_Cfunc_GoString(int8 *p, String s)
|
var _cgo_runtime_cgocall_errno func(unsafe.Pointer, uintptr) int32
|
||||||
{
|
var _cgo_runtime_cmalloc func(uintptr) unsafe.Pointer
|
||||||
s = runtime·gostring((byte*)p);
|
`
|
||||||
FLUSH(&s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
const goStringDef = `
|
||||||
·_Cfunc_GoStringN(int8 *p, int32 l, String s)
|
var _cgo_runtime_gostring func(*_Ctype_char) string
|
||||||
{
|
func _Cfunc_GoString(p *_Ctype_char) string {
|
||||||
s = runtime·gostringn((byte*)p, l);
|
return _cgo_runtime_gostring(p)
|
||||||
FLUSH(&s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
·_Cfunc_GoBytes(int8 *p, int32 l, Slice s)
|
|
||||||
{
|
|
||||||
s = runtime·gobytes((byte*)p, l);
|
|
||||||
FLUSH(&s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
·_Cfunc_CString(String s, int8 *p)
|
|
||||||
{
|
|
||||||
p = runtime·cmalloc(s.len+1);
|
|
||||||
runtime·memmove((byte*)p, s.str, s.len);
|
|
||||||
p[s.len] = 0;
|
|
||||||
FLUSH(&p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
·_Cfunc__CMalloc(uintptr n, int8 *p)
|
|
||||||
{
|
|
||||||
p = runtime·cmalloc(n);
|
|
||||||
FLUSH(&p);
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const goStringNDef = `
|
||||||
|
var _cgo_runtime_gostringn func(*_Ctype_char, int) string
|
||||||
|
func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string {
|
||||||
|
return _cgo_runtime_gostringn(p, int(l))
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const goBytesDef = `
|
||||||
|
var _cgo_runtime_gobytes func(unsafe.Pointer, int) []byte
|
||||||
|
func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
|
||||||
|
return _cgo_runtime_gobytes(p, int(l))
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const cStringDef = `
|
||||||
|
func _Cfunc_CString(s string) *_Ctype_char {
|
||||||
|
p := _cgo_runtime_cmalloc(uintptr(len(s)+1))
|
||||||
|
pp := (*[1<<30]byte)(p)
|
||||||
|
copy(pp[:], s)
|
||||||
|
pp[len(s)] = 0
|
||||||
|
return (*_Ctype_char)(p)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const cMallocDef = `
|
||||||
|
func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
|
||||||
|
return _cgo_runtime_cmalloc(uintptr(n))
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
var builtinDefs = map[string]string{
|
||||||
|
"GoString": goStringDef,
|
||||||
|
"GoStringN": goStringNDef,
|
||||||
|
"GoBytes": goBytesDef,
|
||||||
|
"CString": cStringDef,
|
||||||
|
"_CMalloc": cMallocDef,
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Package) cPrologGccgo() string {
|
func (p *Package) cPrologGccgo() string {
|
||||||
return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1)
|
return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ and test commands:
|
||||||
|
|
||||||
-a
|
-a
|
||||||
force rebuilding of packages that are already up-to-date.
|
force rebuilding of packages that are already up-to-date.
|
||||||
|
In Go releases, does not apply to the standard library.
|
||||||
-n
|
-n
|
||||||
print the commands but do not run them.
|
print the commands but do not run them.
|
||||||
-p n
|
-p n
|
||||||
|
@ -64,7 +65,7 @@ and test commands:
|
||||||
The default is the number of CPUs available.
|
The default is the number of CPUs available.
|
||||||
-race
|
-race
|
||||||
enable data race detection.
|
enable data race detection.
|
||||||
Supported only on linux/amd64, darwin/amd64 and windows/amd64.
|
Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
|
||||||
-v
|
-v
|
||||||
print the names of packages as they are compiled.
|
print the names of packages as they are compiled.
|
||||||
-work
|
-work
|
||||||
|
@ -291,23 +292,26 @@ func runBuild(cmd *Command, args []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
depMode := modeBuild
|
||||||
|
if buildI {
|
||||||
|
depMode = modeInstall
|
||||||
|
}
|
||||||
|
|
||||||
if *buildO != "" {
|
if *buildO != "" {
|
||||||
if len(pkgs) > 1 {
|
if len(pkgs) > 1 {
|
||||||
fatalf("go build: cannot use -o with multiple packages")
|
fatalf("go build: cannot use -o with multiple packages")
|
||||||
|
} else if len(pkgs) == 0 {
|
||||||
|
fatalf("no packages to build")
|
||||||
}
|
}
|
||||||
p := pkgs[0]
|
p := pkgs[0]
|
||||||
p.target = "" // must build - not up to date
|
p.target = "" // must build - not up to date
|
||||||
a := b.action(modeInstall, modeBuild, p)
|
a := b.action(modeInstall, depMode, p)
|
||||||
a.target = *buildO
|
a.target = *buildO
|
||||||
b.do(a)
|
b.do(a)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
a := &action{}
|
a := &action{}
|
||||||
depMode := modeBuild
|
|
||||||
if buildI {
|
|
||||||
depMode = modeInstall
|
|
||||||
}
|
|
||||||
for _, p := range packages(args) {
|
for _, p := range packages(args) {
|
||||||
a.deps = append(a.deps, b.action(modeBuild, depMode, p))
|
a.deps = append(a.deps, b.action(modeBuild, depMode, p))
|
||||||
}
|
}
|
||||||
|
@ -438,12 +442,11 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
goroot = filepath.Clean(runtime.GOROOT())
|
goroot = filepath.Clean(runtime.GOROOT())
|
||||||
gobin = os.Getenv("GOBIN")
|
gobin = os.Getenv("GOBIN")
|
||||||
gorootBin = filepath.Join(goroot, "bin")
|
gorootBin = filepath.Join(goroot, "bin")
|
||||||
gorootSrcPkg = filepath.Join(goroot, "src/pkg")
|
gorootPkg = filepath.Join(goroot, "pkg")
|
||||||
gorootPkg = filepath.Join(goroot, "pkg")
|
gorootSrc = filepath.Join(goroot, "src")
|
||||||
gorootSrc = filepath.Join(goroot, "src")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *builder) init() {
|
func (b *builder) init() {
|
||||||
|
@ -510,8 +513,13 @@ func goFilesPackage(gofiles []string) *Package {
|
||||||
}
|
}
|
||||||
ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
|
ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
|
||||||
|
|
||||||
if !filepath.IsAbs(dir) {
|
var err error
|
||||||
dir = filepath.Join(cwd, dir)
|
if dir == "" {
|
||||||
|
dir = cwd
|
||||||
|
}
|
||||||
|
dir, err = filepath.Abs(dir)
|
||||||
|
if err != nil {
|
||||||
|
fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bp, err := ctxt.ImportDir(dir, 0)
|
bp, err := ctxt.ImportDir(dir, 0)
|
||||||
|
@ -833,12 +841,17 @@ func (b *builder) build(a *action) (err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var gofiles, cfiles, sfiles, objects, cgoObjects []string
|
var gofiles, cfiles, sfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
|
||||||
|
|
||||||
gofiles = append(gofiles, a.p.GoFiles...)
|
gofiles = append(gofiles, a.p.GoFiles...)
|
||||||
cfiles = append(cfiles, a.p.CFiles...)
|
cfiles = append(cfiles, a.p.CFiles...)
|
||||||
sfiles = append(sfiles, a.p.SFiles...)
|
sfiles = append(sfiles, a.p.SFiles...)
|
||||||
|
|
||||||
|
if a.p.usesCgo() || a.p.usesSwig() {
|
||||||
|
if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
// Run cgo.
|
// Run cgo.
|
||||||
if a.p.usesCgo() {
|
if a.p.usesCgo() {
|
||||||
// In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.
|
// In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.
|
||||||
|
@ -869,7 +882,7 @@ func (b *builder) build(a *action) (err error) {
|
||||||
if a.cgo != nil && a.cgo.target != "" {
|
if a.cgo != nil && a.cgo.target != "" {
|
||||||
cgoExe = a.cgo.target
|
cgoExe = a.cgo.target
|
||||||
}
|
}
|
||||||
outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles, a.p.CXXFiles, a.p.MFiles)
|
outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, gccfiles, a.p.CXXFiles, a.p.MFiles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -882,9 +895,18 @@ func (b *builder) build(a *action) (err error) {
|
||||||
// In a package using SWIG, any .c or .s files are
|
// In a package using SWIG, any .c or .s files are
|
||||||
// compiled with gcc.
|
// compiled with gcc.
|
||||||
gccfiles := append(cfiles, sfiles...)
|
gccfiles := append(cfiles, sfiles...)
|
||||||
|
cxxfiles, mfiles := a.p.CXXFiles, a.p.MFiles
|
||||||
cfiles = nil
|
cfiles = nil
|
||||||
sfiles = nil
|
sfiles = nil
|
||||||
outGo, outObj, err := b.swig(a.p, obj, gccfiles, a.p.CXXFiles, a.p.MFiles)
|
|
||||||
|
// Don't build c/c++ files twice if cgo is enabled (mainly for pkg-config).
|
||||||
|
if a.p.usesCgo() {
|
||||||
|
cxxfiles = nil
|
||||||
|
gccfiles = nil
|
||||||
|
mfiles = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
outGo, outObj, err := b.swig(a.p, obj, pcCFLAGS, gccfiles, cxxfiles, mfiles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -893,7 +915,7 @@ func (b *builder) build(a *action) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(gofiles) == 0 {
|
if len(gofiles) == 0 {
|
||||||
return &build.NoGoError{a.p.Dir}
|
return &build.NoGoError{Dir: a.p.Dir}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're doing coverage, preprocess the .go files and put them in the work directory
|
// If we're doing coverage, preprocess the .go files and put them in the work directory
|
||||||
|
@ -1028,6 +1050,34 @@ func (b *builder) build(a *action) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
|
||||||
|
func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) {
|
||||||
|
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
|
||||||
|
var out []byte
|
||||||
|
out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs)
|
||||||
|
if err != nil {
|
||||||
|
b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
|
||||||
|
b.print(err.Error() + "\n")
|
||||||
|
err = errPrintedOutput
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(out) > 0 {
|
||||||
|
cflags = strings.Fields(string(out))
|
||||||
|
}
|
||||||
|
out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs)
|
||||||
|
if err != nil {
|
||||||
|
b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out))
|
||||||
|
b.print(err.Error() + "\n")
|
||||||
|
err = errPrintedOutput
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(out) > 0 {
|
||||||
|
ldflags = strings.Fields(string(out))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// install is the action for installing a single package or executable.
|
// install is the action for installing a single package or executable.
|
||||||
func (b *builder) install(a *action) (err error) {
|
func (b *builder) install(a *action) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -1263,7 +1313,7 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) {
|
||||||
// the source directory for the package that has failed to build.
|
// the source directory for the package that has failed to build.
|
||||||
// showOutput rewrites mentions of dir with a relative path to dir
|
// showOutput rewrites mentions of dir with a relative path to dir
|
||||||
// when the relative path is shorter. This is usually more pleasant.
|
// when the relative path is shorter. This is usually more pleasant.
|
||||||
// For example, if fmt doesn't compile and we are in src/pkg/html,
|
// For example, if fmt doesn't compile and we are in src/html,
|
||||||
// the output is
|
// the output is
|
||||||
//
|
//
|
||||||
// $ go build
|
// $ go build
|
||||||
|
@ -1275,7 +1325,7 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) {
|
||||||
//
|
//
|
||||||
// $ go build
|
// $ go build
|
||||||
// # fmt
|
// # fmt
|
||||||
// /usr/gopher/go/src/pkg/fmt/print.go:1090: undefined: asdf
|
// /usr/gopher/go/src/fmt/print.go:1090: undefined: asdf
|
||||||
// $
|
// $
|
||||||
//
|
//
|
||||||
// showOutput also replaces references to the work directory with $WORK.
|
// showOutput also replaces references to the work directory with $WORK.
|
||||||
|
@ -1435,6 +1485,14 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// err can be something like 'exit status 1'.
|
||||||
|
// Add information about what program was running.
|
||||||
|
// Note that if buf.Bytes() is non-empty, the caller usually
|
||||||
|
// shows buf.Bytes() and does not print err at all, so the
|
||||||
|
// prefix here does not make most output any more verbose.
|
||||||
|
if err != nil {
|
||||||
|
err = errors.New(cmdline[0] + ": " + err.Error())
|
||||||
|
}
|
||||||
return buf.Bytes(), err
|
return buf.Bytes(), err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1597,7 +1655,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []
|
||||||
extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
|
extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
|
||||||
if p.Standard {
|
if p.Standard {
|
||||||
switch p.ImportPath {
|
switch p.ImportPath {
|
||||||
case "os", "runtime/pprof", "sync", "time":
|
case "bytes", "net", "os", "runtime/pprof", "sync", "time":
|
||||||
extFiles++
|
extFiles++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1621,8 +1679,10 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
|
func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
|
||||||
|
// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
|
||||||
|
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
|
||||||
sfile = mkAbs(p.Dir, sfile)
|
sfile = mkAbs(p.Dir, sfile)
|
||||||
return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
|
return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-I", inc, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gcToolchain) pkgpath(basedir string, p *Package) string {
|
func (gcToolchain) pkgpath(basedir string, p *Package) string {
|
||||||
|
@ -1716,7 +1776,7 @@ func packInternal(b *builder, afile string, ofiles []string) error {
|
||||||
|
|
||||||
func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
|
func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
|
||||||
importArgs := b.includeArgs("-L", allactions)
|
importArgs := b.includeArgs("-L", allactions)
|
||||||
cxx := false
|
cxx := len(p.CXXFiles) > 0
|
||||||
for _, a := range allactions {
|
for _, a := range allactions {
|
||||||
if a.p != nil && len(a.p.CXXFiles) > 0 {
|
if a.p != nil && len(a.p.CXXFiles) > 0 {
|
||||||
cxx = true
|
cxx = true
|
||||||
|
@ -1776,7 +1836,15 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,
|
||||||
func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
|
func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
|
||||||
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
|
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
|
||||||
cfile = mkAbs(p.Dir, cfile)
|
cfile = mkAbs(p.Dir, cfile)
|
||||||
args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
|
warn := []string{"-w"}
|
||||||
|
if p.usesSwig() {
|
||||||
|
// When using SWIG, this compiler is only used to
|
||||||
|
// compile the C files generated by SWIG.
|
||||||
|
// We don't want warnings.
|
||||||
|
// See issue 9065 for details.
|
||||||
|
warn = nil
|
||||||
|
}
|
||||||
|
args := stringList(tool(archChar+"c"), "-F", "-V", warn, "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
|
||||||
return b.run(p.Dir, p.ImportPath, nil, args)
|
return b.run(p.Dir, p.ImportPath, nil, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1802,7 +1870,7 @@ func (gccgoToolchain) linker() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
|
func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
|
||||||
out := p.Name + ".o"
|
out := "_go_.o"
|
||||||
ofile = obj + out
|
ofile = obj + out
|
||||||
gcargs := []string{"-g"}
|
gcargs := []string{"-g"}
|
||||||
gcargs = append(gcargs, b.gccArchArgs()...)
|
gcargs = append(gcargs, b.gccArchArgs()...)
|
||||||
|
@ -1828,6 +1896,7 @@ func (tools gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string
|
||||||
defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
|
defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
|
||||||
}
|
}
|
||||||
defs = append(defs, b.gccArchArgs()...)
|
defs = append(defs, b.gccArchArgs()...)
|
||||||
|
|
||||||
return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-c", "-I", obj, "-o", ofile, defs, sfile)
|
return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-c", "-I", obj, "-o", ofile, defs, sfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1854,8 +1923,8 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []
|
||||||
ldflags := b.gccArchArgs()
|
ldflags := b.gccArchArgs()
|
||||||
cgoldflags := []string{}
|
cgoldflags := []string{}
|
||||||
usesCgo := false
|
usesCgo := false
|
||||||
cxx := false
|
cxx := len(p.CXXFiles) > 0
|
||||||
objc := false
|
objc := len(p.MFiles) > 0
|
||||||
|
|
||||||
// Prefer the output of an install action to the output of a build action,
|
// Prefer the output of an install action to the output of a build action,
|
||||||
// because the install action will delete the output of the build action.
|
// because the install action will delete the output of the build action.
|
||||||
|
@ -1917,8 +1986,7 @@ func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) er
|
||||||
if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
|
if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
|
||||||
defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
|
defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
|
||||||
}
|
}
|
||||||
// TODO: Support using clang here (during gccgo build)?
|
return b.run(p.Dir, p.ImportPath, nil, envList("CC", defaultCC), "-Wall", "-g",
|
||||||
return b.run(p.Dir, p.ImportPath, nil, "gcc", "-Wall", "-g",
|
|
||||||
"-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
|
"-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1969,9 +2037,9 @@ func (b *builder) libgcc(p *Package) (string, error) {
|
||||||
return "$LIBGCC", nil
|
return "$LIBGCC", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// clang might not be able to find libgcc, and in that case,
|
// The compiler might not be able to find libgcc, and in that case,
|
||||||
// it will simply return "libgcc.a", which is of no use to us.
|
// it will simply return "libgcc.a", which is of no use to us.
|
||||||
if strings.Contains(gccCmd[0], "clang") && !filepath.IsAbs(string(f)) {
|
if !filepath.IsAbs(string(f)) {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2109,36 +2177,16 @@ var (
|
||||||
cgoLibGccFileOnce sync.Once
|
cgoLibGccFileOnce sync.Once
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
|
func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
|
||||||
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true)
|
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true)
|
||||||
_, cgoexeCFLAGS, _, _ := b.cflags(p, false)
|
_, cgoexeCFLAGS, _, _ := b.cflags(p, false)
|
||||||
|
cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
|
||||||
|
cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
|
||||||
// If we are compiling Objective-C code, then we need to link against libobjc
|
// If we are compiling Objective-C code, then we need to link against libobjc
|
||||||
if len(mfiles) > 0 {
|
if len(mfiles) > 0 {
|
||||||
cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
|
cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
|
|
||||||
out, err := b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs)
|
|
||||||
if err != nil {
|
|
||||||
b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
|
|
||||||
b.print(err.Error() + "\n")
|
|
||||||
return nil, nil, errPrintedOutput
|
|
||||||
}
|
|
||||||
if len(out) > 0 {
|
|
||||||
cgoCPPFLAGS = append(cgoCPPFLAGS, strings.Fields(string(out))...)
|
|
||||||
}
|
|
||||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs)
|
|
||||||
if err != nil {
|
|
||||||
b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out))
|
|
||||||
b.print(err.Error() + "\n")
|
|
||||||
return nil, nil, errPrintedOutput
|
|
||||||
}
|
|
||||||
if len(out) > 0 {
|
|
||||||
cgoLDFLAGS = append(cgoLDFLAGS, strings.Fields(string(out))...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allows including _cgo_export.h from .[ch] files in the package.
|
// Allows including _cgo_export.h from .[ch] files in the package.
|
||||||
cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj)
|
cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj)
|
||||||
|
|
||||||
|
@ -2215,6 +2263,14 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles
|
||||||
strings.HasSuffix(f, ".so"),
|
strings.HasSuffix(f, ".so"),
|
||||||
strings.HasSuffix(f, ".dll"):
|
strings.HasSuffix(f, ".dll"):
|
||||||
continue
|
continue
|
||||||
|
// Remove any -fsanitize=foo flags.
|
||||||
|
// Otherwise the compiler driver thinks that we are doing final link
|
||||||
|
// and links sanitizer runtime into the object file. But we are not doing
|
||||||
|
// the final link, we will link the resulting object file again. And
|
||||||
|
// so the program ends up with two copies of sanitizer runtime.
|
||||||
|
// See issue 8788 for details.
|
||||||
|
case strings.HasPrefix(f, "-fsanitize="):
|
||||||
|
continue
|
||||||
default:
|
default:
|
||||||
bareLDFLAGS = append(bareLDFLAGS, f)
|
bareLDFLAGS = append(bareLDFLAGS, f)
|
||||||
}
|
}
|
||||||
|
@ -2281,13 +2337,14 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles
|
||||||
|
|
||||||
linkobj = append(linkobj, p.SysoFiles...)
|
linkobj = append(linkobj, p.SysoFiles...)
|
||||||
dynobj := obj + "_cgo_.o"
|
dynobj := obj + "_cgo_.o"
|
||||||
if goarch == "arm" && goos == "linux" { // we need to use -pie for Linux/ARM to get accurate imported sym
|
pie := goarch == "arm" && (goos == "linux" || goos == "android")
|
||||||
|
if pie { // we need to use -pie for Linux/ARM to get accurate imported sym
|
||||||
cgoLDFLAGS = append(cgoLDFLAGS, "-pie")
|
cgoLDFLAGS = append(cgoLDFLAGS, "-pie")
|
||||||
}
|
}
|
||||||
if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
|
if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if goarch == "arm" && goos == "linux" { // but we don't need -pie for normal cgo programs
|
if pie { // but we don't need -pie for normal cgo programs
|
||||||
cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]
|
cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2321,7 +2378,23 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles
|
||||||
nonGccObjs = append(nonGccObjs, f)
|
nonGccObjs = append(nonGccObjs, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := b.gccld(p, ofile, stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs), gccObjs); err != nil {
|
ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs)
|
||||||
|
|
||||||
|
// Some systems, such as Ubuntu, always add --build-id to
|
||||||
|
// every link, but we don't want a build ID since we are
|
||||||
|
// producing an object file. On some of those system a plain
|
||||||
|
// -r (not -Wl,-r) will turn off --build-id, but clang 3.0
|
||||||
|
// doesn't support a plain -r. I don't know how to turn off
|
||||||
|
// --build-id when using clang other than passing a trailing
|
||||||
|
// --build-id=none. So that is what we do, but only on
|
||||||
|
// systems likely to support it, which is to say, systems that
|
||||||
|
// normally use gold or the GNU linker.
|
||||||
|
switch goos {
|
||||||
|
case "android", "dragonfly", "linux", "netbsd":
|
||||||
|
ldflags = append(ldflags, "-Wl,--build-id=none")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2336,7 +2409,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles
|
||||||
// Run SWIG on all SWIG input files.
|
// Run SWIG on all SWIG input files.
|
||||||
// TODO: Don't build a shared library, once SWIG emits the necessary
|
// TODO: Don't build a shared library, once SWIG emits the necessary
|
||||||
// pragmas for external linking.
|
// pragmas for external linking.
|
||||||
func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
|
func (b *builder) swig(p *Package, obj string, pcCFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
|
||||||
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
|
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
|
||||||
cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
|
cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
|
||||||
cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS)
|
cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS)
|
||||||
|
@ -2377,7 +2450,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []stri
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range p.SwigFiles {
|
for _, f := range p.SwigFiles {
|
||||||
goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, false, intgosize)
|
goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -2392,7 +2465,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []stri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, f := range p.SwigCXXFiles {
|
for _, f := range p.SwigCXXFiles {
|
||||||
goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, true, intgosize)
|
goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -2471,13 +2544,13 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run SWIG on one SWIG input file.
|
// Run SWIG on one SWIG input file.
|
||||||
func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) {
|
func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) {
|
||||||
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
|
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
|
||||||
var cflags []string
|
var cflags []string
|
||||||
if cxx {
|
if cxx {
|
||||||
cflags = stringList(cgoCPPFLAGS, cgoCXXFLAGS)
|
cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
|
||||||
} else {
|
} else {
|
||||||
cflags = stringList(cgoCPPFLAGS, cgoCFLAGS)
|
cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
n := 5 // length of ".swig"
|
n := 5 // length of ".swig"
|
||||||
|
@ -2503,6 +2576,13 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri
|
||||||
"-o", obj + gccBase + gccExt,
|
"-o", obj + gccBase + gccExt,
|
||||||
"-outdir", obj,
|
"-outdir", obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, f := range cflags {
|
||||||
|
if len(f) > 3 && f[:2] == "-I" {
|
||||||
|
args = append(args, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if gccgo {
|
if gccgo {
|
||||||
args = append(args, "-gccgo")
|
args = append(args, "-gccgo")
|
||||||
if pkgpath := gccgoPkgpath(p); pkgpath != "" {
|
if pkgpath := gccgoPkgpath(p); pkgpath != "" {
|
||||||
|
@ -2575,8 +2655,8 @@ func raceInit() {
|
||||||
if !buildRace {
|
if !buildRace {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if goarch != "amd64" || goos != "linux" && goos != "darwin" && goos != "windows" {
|
if goarch != "amd64" || goos != "linux" && goos != "freebsd" && goos != "darwin" && goos != "windows" {
|
||||||
fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
|
fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
buildGcflags = append(buildGcflags, "-race")
|
buildGcflags = append(buildGcflags, "-race")
|
||||||
|
|
|
@ -19,6 +19,7 @@ The commands are:
|
||||||
env print Go environment information
|
env print Go environment information
|
||||||
fix run go tool fix on packages
|
fix run go tool fix on packages
|
||||||
fmt run gofmt on package sources
|
fmt run gofmt on package sources
|
||||||
|
generate generate Go files by processing source
|
||||||
get download and install packages and dependencies
|
get download and install packages and dependencies
|
||||||
install compile and install packages and dependencies
|
install compile and install packages and dependencies
|
||||||
list list packages
|
list list packages
|
||||||
|
@ -75,6 +76,7 @@ and test commands:
|
||||||
|
|
||||||
-a
|
-a
|
||||||
force rebuilding of packages that are already up-to-date.
|
force rebuilding of packages that are already up-to-date.
|
||||||
|
In Go releases, does not apply to the standard library.
|
||||||
-n
|
-n
|
||||||
print the commands but do not run them.
|
print the commands but do not run them.
|
||||||
-p n
|
-p n
|
||||||
|
@ -82,7 +84,7 @@ and test commands:
|
||||||
The default is the number of CPUs available.
|
The default is the number of CPUs available.
|
||||||
-race
|
-race
|
||||||
enable data race detection.
|
enable data race detection.
|
||||||
Supported only on linux/amd64, darwin/amd64 and windows/amd64.
|
Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
|
||||||
-v
|
-v
|
||||||
print the names of packages as they are compiled.
|
print the names of packages as they are compiled.
|
||||||
-work
|
-work
|
||||||
|
@ -219,11 +221,110 @@ To run gofmt with specific options, run gofmt itself.
|
||||||
See also: go fix, go vet.
|
See also: go fix, go vet.
|
||||||
|
|
||||||
|
|
||||||
|
Generate Go files by processing source
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
go generate [-run regexp] [file.go... | packages]
|
||||||
|
|
||||||
|
Generate runs commands described by directives within existing
|
||||||
|
files. Those commands can run any process but the intent is to
|
||||||
|
create or update Go source files, for instance by running yacc.
|
||||||
|
|
||||||
|
Go generate is never run automatically by go build, go get, go test,
|
||||||
|
and so on. It must be run explicitly.
|
||||||
|
|
||||||
|
Go generate scans the file for directives, which are lines of
|
||||||
|
the form,
|
||||||
|
|
||||||
|
//go:generate command argument...
|
||||||
|
|
||||||
|
(note: no leading spaces and no space in "//go") where command
|
||||||
|
is the generator to be run, corresponding to an executable file
|
||||||
|
that can be run locally. It must either be in the shell path
|
||||||
|
(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
|
||||||
|
command alias, described below.
|
||||||
|
|
||||||
|
Note that go generate does not parse the file, so lines that look
|
||||||
|
like directives in comments or multiline strings will be treated
|
||||||
|
as directives.
|
||||||
|
|
||||||
|
The arguments to the directive are space-separated tokens or
|
||||||
|
double-quoted strings passed to the generator as individual
|
||||||
|
arguments when it is run.
|
||||||
|
|
||||||
|
Quoted strings use Go syntax and are evaluated before execution; a
|
||||||
|
quoted string appears as a single argument to the generator.
|
||||||
|
|
||||||
|
Go generate sets several variables when it runs the generator:
|
||||||
|
|
||||||
|
$GOARCH
|
||||||
|
The execution architecture (arm, amd64, etc.)
|
||||||
|
$GOOS
|
||||||
|
The execution operating system (linux, windows, etc.)
|
||||||
|
$GOFILE
|
||||||
|
The base name of the file.
|
||||||
|
$GOPACKAGE
|
||||||
|
The name of the package of the file containing the directive.
|
||||||
|
|
||||||
|
Other than variable substitution and quoted-string evaluation, no
|
||||||
|
special processing such as "globbing" is performed on the command
|
||||||
|
line.
|
||||||
|
|
||||||
|
As a last step before running the command, any invocations of any
|
||||||
|
environment variables with alphanumeric names, such as $GOFILE or
|
||||||
|
$HOME, are expanded throughout the command line. The syntax for
|
||||||
|
variable expansion is $NAME on all operating systems. Due to the
|
||||||
|
order of evaluation, variables are expanded even inside quoted
|
||||||
|
strings. If the variable NAME is not set, $NAME expands to the
|
||||||
|
empty string.
|
||||||
|
|
||||||
|
A directive of the form,
|
||||||
|
|
||||||
|
//go:generate -command xxx args...
|
||||||
|
|
||||||
|
specifies, for the remainder of this source file only, that the
|
||||||
|
string xxx represents the command identified by the arguments. This
|
||||||
|
can be used to create aliases or to handle multiword generators.
|
||||||
|
For example,
|
||||||
|
|
||||||
|
//go:generate -command yacc go tool yacc
|
||||||
|
|
||||||
|
specifies that the command "yacc" represents the generator
|
||||||
|
"go tool yacc".
|
||||||
|
|
||||||
|
Generate processes packages in the order given on the command line,
|
||||||
|
one at a time. If the command line lists .go files, they are treated
|
||||||
|
as a single package. Within a package, generate processes the
|
||||||
|
source files in a package in file name order, one at a time. Within
|
||||||
|
a source file, generate runs generators in the order they appear
|
||||||
|
in the file, one at a time.
|
||||||
|
|
||||||
|
If any generator returns an error exit status, "go generate" skips
|
||||||
|
all further processing for that package.
|
||||||
|
|
||||||
|
The generator is run in the package's source directory.
|
||||||
|
|
||||||
|
Go generate accepts one specific flag:
|
||||||
|
|
||||||
|
-run=""
|
||||||
|
if non-empty, specifies a regular expression to
|
||||||
|
select directives whose command matches the expression.
|
||||||
|
|
||||||
|
It also accepts the standard build flags -v, -n, and -x.
|
||||||
|
The -v flag prints the names of packages and files as they are
|
||||||
|
processed.
|
||||||
|
The -n flag prints commands that would be executed.
|
||||||
|
The -x flag prints commands as they are executed.
|
||||||
|
|
||||||
|
For more about specifying packages, see 'go help packages'.
|
||||||
|
|
||||||
|
|
||||||
Download and install packages and dependencies
|
Download and install packages and dependencies
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
go get [-d] [-fix] [-t] [-u] [build flags] [packages]
|
go get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]
|
||||||
|
|
||||||
Get downloads and installs the packages named by the import paths,
|
Get downloads and installs the packages named by the import paths,
|
||||||
along with their dependencies.
|
along with their dependencies.
|
||||||
|
@ -231,6 +332,11 @@ along with their dependencies.
|
||||||
The -d flag instructs get to stop after downloading the packages; that is,
|
The -d flag instructs get to stop after downloading the packages; that is,
|
||||||
it instructs get not to install the packages.
|
it instructs get not to install the packages.
|
||||||
|
|
||||||
|
The -f flag, valid only when -u is set, forces get -u not to verify that
|
||||||
|
each package has been checked out from the source control repository
|
||||||
|
implied by its import path. This can be useful if the source is a local fork
|
||||||
|
of the original.
|
||||||
|
|
||||||
The -fix flag instructs get to run the fix tool on the downloaded packages
|
The -fix flag instructs get to run the fix tool on the downloaded packages
|
||||||
before resolving dependencies or building the code.
|
before resolving dependencies or building the code.
|
||||||
|
|
||||||
|
@ -291,28 +397,29 @@ syntax of package template. The default output is equivalent to -f
|
||||||
'{{.ImportPath}}'. The struct being passed to the template is:
|
'{{.ImportPath}}'. The struct being passed to the template is:
|
||||||
|
|
||||||
type Package struct {
|
type Package struct {
|
||||||
Dir string // directory containing package sources
|
Dir string // directory containing package sources
|
||||||
ImportPath string // import path of package in dir
|
ImportPath string // import path of package in dir
|
||||||
Name string // package name
|
ImportComment string // path in import comment on package statement
|
||||||
Doc string // package documentation string
|
Name string // package name
|
||||||
Target string // install path
|
Doc string // package documentation string
|
||||||
Goroot bool // is this package in the Go root?
|
Target string // install path
|
||||||
Standard bool // is this package part of the standard Go library?
|
Goroot bool // is this package in the Go root?
|
||||||
Stale bool // would 'go install' do anything for this package?
|
Standard bool // is this package part of the standard Go library?
|
||||||
Root string // Go root or Go path dir containing this package
|
Stale bool // would 'go install' do anything for this package?
|
||||||
|
Root string // Go root or Go path dir containing this package
|
||||||
|
|
||||||
// Source files
|
// Source files
|
||||||
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||||
CgoFiles []string // .go sources files that import "C"
|
CgoFiles []string // .go sources files that import "C"
|
||||||
IgnoredGoFiles []string // .go sources ignored due to build constraints
|
IgnoredGoFiles []string // .go sources ignored due to build constraints
|
||||||
CFiles []string // .c source files
|
CFiles []string // .c source files
|
||||||
CXXFiles []string // .cc, .cxx and .cpp source files
|
CXXFiles []string // .cc, .cxx and .cpp source files
|
||||||
MFiles []string // .m source files
|
MFiles []string // .m source files
|
||||||
HFiles []string // .h, .hh, .hpp and .hxx source files
|
HFiles []string // .h, .hh, .hpp and .hxx source files
|
||||||
SFiles []string // .s source files
|
SFiles []string // .s source files
|
||||||
SwigFiles []string // .swig files
|
SwigFiles []string // .swig files
|
||||||
SwigCXXFiles []string // .swigcxx files
|
SwigCXXFiles []string // .swigcxx files
|
||||||
SysoFiles []string // .syso object files to add to archive
|
SysoFiles []string // .syso object files to add to archive
|
||||||
|
|
||||||
// Cgo directives
|
// Cgo directives
|
||||||
CgoCFLAGS []string // cgo: flags for C compiler
|
CgoCFLAGS []string // cgo: flags for C compiler
|
||||||
|
@ -431,16 +538,23 @@ non-test installation.
|
||||||
|
|
||||||
In addition to the build flags, the flags handled by 'go test' itself are:
|
In addition to the build flags, the flags handled by 'go test' itself are:
|
||||||
|
|
||||||
-c Compile the test binary to pkg.test but do not run it.
|
-c
|
||||||
(Where pkg is the last element of the package's import path.)
|
Compile the test binary to pkg.test but do not run it
|
||||||
|
(where pkg is the last element of the package's import path).
|
||||||
|
The file name can be changed with the -o flag.
|
||||||
|
|
||||||
|
-exec xprog
|
||||||
|
Run the test binary using xprog. The behavior is the same as
|
||||||
|
in 'go run'. See 'go help run' for details.
|
||||||
|
|
||||||
-i
|
-i
|
||||||
Install packages that are dependencies of the test.
|
Install packages that are dependencies of the test.
|
||||||
Do not run the test.
|
Do not run the test.
|
||||||
|
|
||||||
-exec xprog
|
-o file
|
||||||
Run the test binary using xprog. The behavior is the same as
|
Compile the test binary to the named file.
|
||||||
in 'go run'. See 'go help run' for details.
|
The test still runs (unless -c or -i is specified).
|
||||||
|
|
||||||
|
|
||||||
The test binary also accepts flags that control execution of the test; these
|
The test binary also accepts flags that control execution of the test; these
|
||||||
flags are also accessible by 'go test'. See 'go help testflag' for details.
|
flags are also accessible by 'go test'. See 'go help testflag' for details.
|
||||||
|
@ -488,7 +602,7 @@ Usage:
|
||||||
|
|
||||||
Vet runs the Go vet command on the packages named by the import paths.
|
Vet runs the Go vet command on the packages named by the import paths.
|
||||||
|
|
||||||
For more about vet, see 'godoc code.google.com/p/go.tools/cmd/vet'.
|
For more about vet, see 'godoc golang.org/x/tools/cmd/vet'.
|
||||||
For more about specifying packages, see 'go help packages'.
|
For more about specifying packages, see 'go help packages'.
|
||||||
|
|
||||||
To run the vet tool with specific options, run 'go tool vet'.
|
To run the vet tool with specific options, run 'go tool vet'.
|
||||||
|
@ -681,6 +795,11 @@ A few common code hosting sites have special syntax:
|
||||||
import "launchpad.net/~user/project/branch"
|
import "launchpad.net/~user/project/branch"
|
||||||
import "launchpad.net/~user/project/branch/sub/directory"
|
import "launchpad.net/~user/project/branch/sub/directory"
|
||||||
|
|
||||||
|
IBM DevOps Services (Git)
|
||||||
|
|
||||||
|
import "hub.jazz.net/git/user/project"
|
||||||
|
import "hub.jazz.net/git/user/project/sub/directory"
|
||||||
|
|
||||||
For code hosted on other servers, import paths may either be qualified
|
For code hosted on other servers, import paths may either be qualified
|
||||||
with the version control type, or the go tool can dynamically fetch
|
with the version control type, or the go tool can dynamically fetch
|
||||||
the import path over https/http and discover where the code resides
|
the import path over https/http and discover where the code resides
|
||||||
|
@ -756,7 +875,26 @@ listed in the GOPATH environment variable (see 'go help gopath').
|
||||||
|
|
||||||
The go command attempts to download the version of the
|
The go command attempts to download the version of the
|
||||||
package appropriate for the Go release being used.
|
package appropriate for the Go release being used.
|
||||||
Run 'go help install' for more.
|
Run 'go help get' for more.
|
||||||
|
|
||||||
|
Import path checking
|
||||||
|
|
||||||
|
When the custom import path feature described above redirects to a
|
||||||
|
known code hosting site, each of the resulting packages has two possible
|
||||||
|
import paths, using the custom domain or the known hosting site.
|
||||||
|
|
||||||
|
A package statement is said to have an "import comment" if it is immediately
|
||||||
|
followed (before the next newline) by a comment of one of these two forms:
|
||||||
|
|
||||||
|
package math // import "path"
|
||||||
|
package math /* import "path" * /
|
||||||
|
|
||||||
|
The go command will refuse to install a package with an import comment
|
||||||
|
unless it is being referred to by that import path. In this way, import comments
|
||||||
|
let package authors make sure the custom import path is used and not a
|
||||||
|
direct path to the underlying code hosting site.
|
||||||
|
|
||||||
|
See https://golang.org/s/go14customimport for details.
|
||||||
|
|
||||||
|
|
||||||
Description of package lists
|
Description of package lists
|
||||||
|
@ -812,7 +950,8 @@ single directory, the command is applied to a single synthesized
|
||||||
package made up of exactly those files, ignoring any build constraints
|
package made up of exactly those files, ignoring any build constraints
|
||||||
in those files and ignoring any other files in the directory.
|
in those files and ignoring any other files in the directory.
|
||||||
|
|
||||||
File names that begin with "." or "_" are ignored by the go tool.
|
Directory and file names that begin with "." or "_" are ignored
|
||||||
|
by the go tool, as are directories named "testdata".
|
||||||
|
|
||||||
|
|
||||||
Description of testing flags
|
Description of testing flags
|
||||||
|
@ -844,6 +983,7 @@ control the execution of any test:
|
||||||
-blockprofile block.out
|
-blockprofile block.out
|
||||||
Write a goroutine blocking profile to the specified file
|
Write a goroutine blocking profile to the specified file
|
||||||
when all tests are complete.
|
when all tests are complete.
|
||||||
|
Writes test binary as -c would.
|
||||||
|
|
||||||
-blockprofilerate n
|
-blockprofilerate n
|
||||||
Control the detail provided in goroutine blocking profiles by
|
Control the detail provided in goroutine blocking profiles by
|
||||||
|
@ -875,8 +1015,7 @@ control the execution of any test:
|
||||||
Sets -cover.
|
Sets -cover.
|
||||||
|
|
||||||
-coverprofile cover.out
|
-coverprofile cover.out
|
||||||
Write a coverage profile to the specified file after all tests
|
Write a coverage profile to the file after all tests have passed.
|
||||||
have passed.
|
|
||||||
Sets -cover.
|
Sets -cover.
|
||||||
|
|
||||||
-cpu 1,2,4
|
-cpu 1,2,4
|
||||||
|
@ -886,10 +1025,11 @@ control the execution of any test:
|
||||||
|
|
||||||
-cpuprofile cpu.out
|
-cpuprofile cpu.out
|
||||||
Write a CPU profile to the specified file before exiting.
|
Write a CPU profile to the specified file before exiting.
|
||||||
|
Writes test binary as -c would.
|
||||||
|
|
||||||
-memprofile mem.out
|
-memprofile mem.out
|
||||||
Write a memory profile to the specified file after all tests
|
Write a memory profile to the file after all tests have passed.
|
||||||
have passed.
|
Writes test binary as -c would.
|
||||||
|
|
||||||
-memprofilerate n
|
-memprofilerate n
|
||||||
Enable more precise (and expensive) memory profiles by setting
|
Enable more precise (and expensive) memory profiles by setting
|
||||||
|
|
|
@ -0,0 +1,398 @@
|
||||||
|
// 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 (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cmdGenerate = &Command{
|
||||||
|
Run: runGenerate,
|
||||||
|
UsageLine: "generate [-run regexp] [file.go... | packages]",
|
||||||
|
Short: "generate Go files by processing source",
|
||||||
|
Long: `
|
||||||
|
Generate runs commands described by directives within existing
|
||||||
|
files. Those commands can run any process but the intent is to
|
||||||
|
create or update Go source files, for instance by running yacc.
|
||||||
|
|
||||||
|
Go generate is never run automatically by go build, go get, go test,
|
||||||
|
and so on. It must be run explicitly.
|
||||||
|
|
||||||
|
Go generate scans the file for directives, which are lines of
|
||||||
|
the form,
|
||||||
|
|
||||||
|
//go:generate command argument...
|
||||||
|
|
||||||
|
(note: no leading spaces and no space in "//go") where command
|
||||||
|
is the generator to be run, corresponding to an executable file
|
||||||
|
that can be run locally. It must either be in the shell path
|
||||||
|
(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
|
||||||
|
command alias, described below.
|
||||||
|
|
||||||
|
Note that go generate does not parse the file, so lines that look
|
||||||
|
like directives in comments or multiline strings will be treated
|
||||||
|
as directives.
|
||||||
|
|
||||||
|
The arguments to the directive are space-separated tokens or
|
||||||
|
double-quoted strings passed to the generator as individual
|
||||||
|
arguments when it is run.
|
||||||
|
|
||||||
|
Quoted strings use Go syntax and are evaluated before execution; a
|
||||||
|
quoted string appears as a single argument to the generator.
|
||||||
|
|
||||||
|
Go generate sets several variables when it runs the generator:
|
||||||
|
|
||||||
|
$GOARCH
|
||||||
|
The execution architecture (arm, amd64, etc.)
|
||||||
|
$GOOS
|
||||||
|
The execution operating system (linux, windows, etc.)
|
||||||
|
$GOFILE
|
||||||
|
The base name of the file.
|
||||||
|
$GOPACKAGE
|
||||||
|
The name of the package of the file containing the directive.
|
||||||
|
|
||||||
|
Other than variable substitution and quoted-string evaluation, no
|
||||||
|
special processing such as "globbing" is performed on the command
|
||||||
|
line.
|
||||||
|
|
||||||
|
As a last step before running the command, any invocations of any
|
||||||
|
environment variables with alphanumeric names, such as $GOFILE or
|
||||||
|
$HOME, are expanded throughout the command line. The syntax for
|
||||||
|
variable expansion is $NAME on all operating systems. Due to the
|
||||||
|
order of evaluation, variables are expanded even inside quoted
|
||||||
|
strings. If the variable NAME is not set, $NAME expands to the
|
||||||
|
empty string.
|
||||||
|
|
||||||
|
A directive of the form,
|
||||||
|
|
||||||
|
//go:generate -command xxx args...
|
||||||
|
|
||||||
|
specifies, for the remainder of this source file only, that the
|
||||||
|
string xxx represents the command identified by the arguments. This
|
||||||
|
can be used to create aliases or to handle multiword generators.
|
||||||
|
For example,
|
||||||
|
|
||||||
|
//go:generate -command yacc go tool yacc
|
||||||
|
|
||||||
|
specifies that the command "yacc" represents the generator
|
||||||
|
"go tool yacc".
|
||||||
|
|
||||||
|
Generate processes packages in the order given on the command line,
|
||||||
|
one at a time. If the command line lists .go files, they are treated
|
||||||
|
as a single package. Within a package, generate processes the
|
||||||
|
source files in a package in file name order, one at a time. Within
|
||||||
|
a source file, generate runs generators in the order they appear
|
||||||
|
in the file, one at a time.
|
||||||
|
|
||||||
|
If any generator returns an error exit status, "go generate" skips
|
||||||
|
all further processing for that package.
|
||||||
|
|
||||||
|
The generator is run in the package's source directory.
|
||||||
|
|
||||||
|
Go generate accepts one specific flag:
|
||||||
|
|
||||||
|
-run=""
|
||||||
|
if non-empty, specifies a regular expression to
|
||||||
|
select directives whose command matches the expression.
|
||||||
|
|
||||||
|
It also accepts the standard build flags -v, -n, and -x.
|
||||||
|
The -v flag prints the names of packages and files as they are
|
||||||
|
processed.
|
||||||
|
The -n flag prints commands that would be executed.
|
||||||
|
The -x flag prints commands as they are executed.
|
||||||
|
|
||||||
|
For more about specifying packages, see 'go help packages'.
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
|
||||||
|
var generateRunFlag string // generate -run flag
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
addBuildFlags(cmdGenerate)
|
||||||
|
cmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func runGenerate(cmd *Command, args []string) {
|
||||||
|
// Even if the arguments are .go files, this loop suffices.
|
||||||
|
for _, pkg := range packages(args) {
|
||||||
|
for _, file := range pkg.gofiles {
|
||||||
|
if !generate(pkg.Name, file) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate runs the generation directives for a single file.
|
||||||
|
func generate(pkg, absFile string) bool {
|
||||||
|
fd, err := os.Open(absFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("generate: %s", err)
|
||||||
|
}
|
||||||
|
defer fd.Close()
|
||||||
|
g := &Generator{
|
||||||
|
r: fd,
|
||||||
|
path: absFile,
|
||||||
|
pkg: pkg,
|
||||||
|
commands: make(map[string][]string),
|
||||||
|
}
|
||||||
|
return g.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Generator represents the state of a single Go source file
|
||||||
|
// being scanned for generator commands.
|
||||||
|
type Generator struct {
|
||||||
|
r io.Reader
|
||||||
|
path string // full rooted path name.
|
||||||
|
dir string // full rooted directory of file.
|
||||||
|
file string // base name of file.
|
||||||
|
pkg string
|
||||||
|
commands map[string][]string
|
||||||
|
lineNum int
|
||||||
|
}
|
||||||
|
|
||||||
|
// run runs the generators in the current file.
|
||||||
|
func (g *Generator) run() (ok bool) {
|
||||||
|
// Processing below here calls g.errorf on failure, which does panic(stop).
|
||||||
|
// If we encounter an error, we abort the package.
|
||||||
|
defer func() {
|
||||||
|
e := recover()
|
||||||
|
if e != nil {
|
||||||
|
ok = false
|
||||||
|
if e != stop {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
setExitStatus(1)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
g.dir, g.file = filepath.Split(g.path)
|
||||||
|
g.dir = filepath.Clean(g.dir) // No final separator please.
|
||||||
|
if buildV {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s\n", shortPath(g.path))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan for lines that start "//go:generate".
|
||||||
|
// Can't use bufio.Scanner because it can't handle long lines,
|
||||||
|
// which are likely to appear when using generate.
|
||||||
|
input := bufio.NewReader(g.r)
|
||||||
|
var err error
|
||||||
|
// One line per loop.
|
||||||
|
for {
|
||||||
|
g.lineNum++ // 1-indexed.
|
||||||
|
var buf []byte
|
||||||
|
buf, err = input.ReadSlice('\n')
|
||||||
|
if err == bufio.ErrBufferFull {
|
||||||
|
// Line too long - consume and ignore.
|
||||||
|
if isGoGenerate(buf) {
|
||||||
|
g.errorf("directive too long")
|
||||||
|
}
|
||||||
|
for err == bufio.ErrBufferFull {
|
||||||
|
_, err = input.ReadSlice('\n')
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// Check for marker at EOF without final \n.
|
||||||
|
if err == io.EOF && isGoGenerate(buf) {
|
||||||
|
err = io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isGoGenerate(buf) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
words := g.split(string(buf))
|
||||||
|
if len(words) == 0 {
|
||||||
|
g.errorf("no arguments to directive")
|
||||||
|
}
|
||||||
|
if words[0] == "-command" {
|
||||||
|
g.setShorthand(words)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Run the command line.
|
||||||
|
if buildN || buildX {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s\n", strings.Join(words, " "))
|
||||||
|
}
|
||||||
|
if buildN {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
g.exec(words)
|
||||||
|
}
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
g.errorf("error reading %s: %s", shortPath(g.path), err)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func isGoGenerate(buf []byte) bool {
|
||||||
|
return bytes.HasPrefix(buf, []byte("//go:generate ")) || bytes.HasPrefix(buf, []byte("//go:generate\t"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// split breaks the line into words, evaluating quoted
|
||||||
|
// strings and evaluating environment variables.
|
||||||
|
// The initial //go:generate element is present in line.
|
||||||
|
func (g *Generator) split(line string) []string {
|
||||||
|
// Parse line, obeying quoted strings.
|
||||||
|
var words []string
|
||||||
|
line = line[len("//go:generate ") : len(line)-1] // Drop preamble and final newline.
|
||||||
|
// One (possibly quoted) word per iteration.
|
||||||
|
Words:
|
||||||
|
for {
|
||||||
|
line = strings.TrimLeft(line, " \t")
|
||||||
|
if len(line) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if line[0] == '"' {
|
||||||
|
for i := 1; i < len(line); i++ {
|
||||||
|
c := line[i] // Only looking for ASCII so this is OK.
|
||||||
|
switch c {
|
||||||
|
case '\\':
|
||||||
|
if i+1 == len(line) {
|
||||||
|
g.errorf("bad backslash")
|
||||||
|
}
|
||||||
|
i++ // Absorb next byte (If it's a multibyte we'll get an error in Unquote).
|
||||||
|
case '"':
|
||||||
|
word, err := strconv.Unquote(line[0 : i+1])
|
||||||
|
if err != nil {
|
||||||
|
g.errorf("bad quoted string")
|
||||||
|
}
|
||||||
|
words = append(words, word)
|
||||||
|
line = line[i+1:]
|
||||||
|
// Check the next character is space or end of line.
|
||||||
|
if len(line) > 0 && line[0] != ' ' && line[0] != '\t' {
|
||||||
|
g.errorf("expect space after quoted argument")
|
||||||
|
}
|
||||||
|
continue Words
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.errorf("mismatched quoted string")
|
||||||
|
}
|
||||||
|
i := strings.IndexAny(line, " \t")
|
||||||
|
if i < 0 {
|
||||||
|
i = len(line)
|
||||||
|
}
|
||||||
|
words = append(words, line[0:i])
|
||||||
|
line = line[i:]
|
||||||
|
}
|
||||||
|
// Substitute command if required.
|
||||||
|
if len(words) > 0 && g.commands[words[0]] != nil {
|
||||||
|
// Replace 0th word by command substitution.
|
||||||
|
words = append(g.commands[words[0]], words[1:]...)
|
||||||
|
}
|
||||||
|
// Substitute environment variables.
|
||||||
|
for i, word := range words {
|
||||||
|
words[i] = g.expandEnv(word)
|
||||||
|
}
|
||||||
|
return words
|
||||||
|
}
|
||||||
|
|
||||||
|
var stop = fmt.Errorf("error in generation")
|
||||||
|
|
||||||
|
// errorf logs an error message prefixed with the file and line number.
|
||||||
|
// It then exits the program (with exit status 1) because generation stops
|
||||||
|
// at the first error.
|
||||||
|
func (g *Generator) errorf(format string, args ...interface{}) {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s:%d: %s\n", shortPath(g.path), g.lineNum,
|
||||||
|
fmt.Sprintf(format, args...))
|
||||||
|
panic(stop)
|
||||||
|
}
|
||||||
|
|
||||||
|
// expandEnv expands any $XXX invocations in word.
|
||||||
|
func (g *Generator) expandEnv(word string) string {
|
||||||
|
if !strings.ContainsRune(word, '$') {
|
||||||
|
return word
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
var w int
|
||||||
|
var r rune
|
||||||
|
for i := 0; i < len(word); i += w {
|
||||||
|
r, w = utf8.DecodeRuneInString(word[i:])
|
||||||
|
if r != '$' {
|
||||||
|
buf.WriteRune(r)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
w += g.identLength(word[i+w:])
|
||||||
|
envVar := word[i+1 : i+w]
|
||||||
|
var sub string
|
||||||
|
switch envVar {
|
||||||
|
case "GOARCH":
|
||||||
|
sub = runtime.GOARCH
|
||||||
|
case "GOOS":
|
||||||
|
sub = runtime.GOOS
|
||||||
|
case "GOFILE":
|
||||||
|
sub = g.file
|
||||||
|
case "GOPACKAGE":
|
||||||
|
sub = g.pkg
|
||||||
|
default:
|
||||||
|
sub = os.Getenv(envVar)
|
||||||
|
}
|
||||||
|
buf.WriteString(sub)
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// identLength returns the length of the identifier beginning the string.
|
||||||
|
func (g *Generator) identLength(word string) int {
|
||||||
|
for i, r := range word {
|
||||||
|
if r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
return len(word)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setShorthand installs a new shorthand as defined by a -command directive.
|
||||||
|
func (g *Generator) setShorthand(words []string) {
|
||||||
|
// Create command shorthand.
|
||||||
|
if len(words) == 1 {
|
||||||
|
g.errorf("no command specified for -command")
|
||||||
|
}
|
||||||
|
command := words[1]
|
||||||
|
if g.commands[command] != nil {
|
||||||
|
g.errorf("command %q defined multiply defined", command)
|
||||||
|
}
|
||||||
|
g.commands[command] = words[2:len(words):len(words)] // force later append to make copy
|
||||||
|
}
|
||||||
|
|
||||||
|
// exec runs the command specified by the argument. The first word is
|
||||||
|
// the command name itself.
|
||||||
|
func (g *Generator) exec(words []string) {
|
||||||
|
cmd := exec.Command(words[0], words[1:]...)
|
||||||
|
// Standard in and out of generator should be the usual.
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
// Run the command in the package directory.
|
||||||
|
cmd.Dir = g.dir
|
||||||
|
env := []string{
|
||||||
|
"GOARCH=" + runtime.GOARCH,
|
||||||
|
"GOOS=" + runtime.GOOS,
|
||||||
|
"GOFILE=" + g.file,
|
||||||
|
"GOPACKAGE=" + g.pkg,
|
||||||
|
}
|
||||||
|
cmd.Env = mergeEnvLists(env, os.Environ())
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
g.errorf("running %q: %s", words[0], err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
// 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 (
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type splitTest struct {
|
||||||
|
in string
|
||||||
|
out []string
|
||||||
|
}
|
||||||
|
|
||||||
|
var splitTests = []splitTest{
|
||||||
|
{"", nil},
|
||||||
|
{"x", []string{"x"}},
|
||||||
|
{" a b\tc ", []string{"a", "b", "c"}},
|
||||||
|
{` " a " `, []string{" a "}},
|
||||||
|
{"$GOARCH", []string{runtime.GOARCH}},
|
||||||
|
{"$GOOS", []string{runtime.GOOS}},
|
||||||
|
{"$GOFILE", []string{"proc.go"}},
|
||||||
|
{"$GOPACKAGE", []string{"sys"}},
|
||||||
|
{"a $XXNOTDEFINEDXX b", []string{"a", "", "b"}},
|
||||||
|
{"/$XXNOTDEFINED/", []string{"//"}},
|
||||||
|
{"yacc -o $GOARCH/yacc_$GOFILE", []string{"go", "tool", "yacc", "-o", runtime.GOARCH + "/yacc_proc.go"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateCommandParse(t *testing.T) {
|
||||||
|
g := &Generator{
|
||||||
|
r: nil, // Unused here.
|
||||||
|
path: "/usr/ken/sys/proc.go",
|
||||||
|
dir: "/usr/ken/sys",
|
||||||
|
file: "proc.go",
|
||||||
|
pkg: "sys",
|
||||||
|
commands: make(map[string][]string),
|
||||||
|
}
|
||||||
|
g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"})
|
||||||
|
for _, test := range splitTests {
|
||||||
|
got := g.split("//go:generate " + test.in + "\n")
|
||||||
|
if !reflect.DeepEqual(got, test.out) {
|
||||||
|
t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var cmdGet = &Command{
|
var cmdGet = &Command{
|
||||||
UsageLine: "get [-d] [-fix] [-t] [-u] [build flags] [packages]",
|
UsageLine: "get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]",
|
||||||
Short: "download and install packages and dependencies",
|
Short: "download and install packages and dependencies",
|
||||||
Long: `
|
Long: `
|
||||||
Get downloads and installs the packages named by the import paths,
|
Get downloads and installs the packages named by the import paths,
|
||||||
|
@ -25,6 +25,11 @@ along with their dependencies.
|
||||||
The -d flag instructs get to stop after downloading the packages; that is,
|
The -d flag instructs get to stop after downloading the packages; that is,
|
||||||
it instructs get not to install the packages.
|
it instructs get not to install the packages.
|
||||||
|
|
||||||
|
The -f flag, valid only when -u is set, forces get -u not to verify that
|
||||||
|
each package has been checked out from the source control repository
|
||||||
|
implied by its import path. This can be useful if the source is a local fork
|
||||||
|
of the original.
|
||||||
|
|
||||||
The -fix flag instructs get to run the fix tool on the downloaded packages
|
The -fix flag instructs get to run the fix tool on the downloaded packages
|
||||||
before resolving dependencies or building the code.
|
before resolving dependencies or building the code.
|
||||||
|
|
||||||
|
@ -53,6 +58,7 @@ See also: go build, go install, go clean.
|
||||||
}
|
}
|
||||||
|
|
||||||
var getD = cmdGet.Flag.Bool("d", false, "")
|
var getD = cmdGet.Flag.Bool("d", false, "")
|
||||||
|
var getF = cmdGet.Flag.Bool("f", false, "")
|
||||||
var getT = cmdGet.Flag.Bool("t", false, "")
|
var getT = cmdGet.Flag.Bool("t", false, "")
|
||||||
var getU = cmdGet.Flag.Bool("u", false, "")
|
var getU = cmdGet.Flag.Bool("u", false, "")
|
||||||
var getFix = cmdGet.Flag.Bool("fix", false, "")
|
var getFix = cmdGet.Flag.Bool("fix", false, "")
|
||||||
|
@ -63,6 +69,10 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGet(cmd *Command, args []string) {
|
func runGet(cmd *Command, args []string) {
|
||||||
|
if *getF && !*getU {
|
||||||
|
fatalf("go get: cannot use -f flag without -u")
|
||||||
|
}
|
||||||
|
|
||||||
// Phase 1. Download/update.
|
// Phase 1. Download/update.
|
||||||
var stk importStack
|
var stk importStack
|
||||||
for _, arg := range downloadPaths(args) {
|
for _, arg := range downloadPaths(args) {
|
||||||
|
@ -151,7 +161,9 @@ func download(arg string, stk *importStack, getTestDeps bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only process each package once.
|
// Only process each package once.
|
||||||
if downloadCache[arg] {
|
// (Unless we're fetching test dependencies for this package,
|
||||||
|
// in which case we want to process it again.)
|
||||||
|
if downloadCache[arg] && !getTestDeps {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
downloadCache[arg] = true
|
downloadCache[arg] = true
|
||||||
|
@ -264,6 +276,25 @@ func downloadPackage(p *Package) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
repo = "<local>" // should be unused; make distinctive
|
repo = "<local>" // should be unused; make distinctive
|
||||||
|
|
||||||
|
// Double-check where it came from.
|
||||||
|
if *getU && vcs.remoteRepo != nil && !*getF {
|
||||||
|
dir := filepath.Join(p.build.SrcRoot, rootPath)
|
||||||
|
if remote, err := vcs.remoteRepo(vcs, dir); err == nil {
|
||||||
|
if rr, err := repoRootForImportPath(p.ImportPath); err == nil {
|
||||||
|
repo := rr.repo
|
||||||
|
if rr.vcs.resolveRepo != nil {
|
||||||
|
resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
|
||||||
|
if err == nil {
|
||||||
|
repo = resolved
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if remote != repo {
|
||||||
|
return fmt.Errorf("%s is from %s, should be from %s", dir, remote, repo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Analyze the import path to determine the version control system,
|
// Analyze the import path to determine the version control system,
|
||||||
// repository, and the import path for the root of the repository.
|
// repository, and the import path for the root of the repository.
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Copyright 2014 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 (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAbsolutePath(t *testing.T) {
|
||||||
|
tmp, err := ioutil.TempDir("", "TestAbsolutePath")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmp)
|
||||||
|
|
||||||
|
file := filepath.Join(tmp, "a.go")
|
||||||
|
err = ioutil.WriteFile(file, []byte{}, 0644)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
dir := filepath.Join(tmp, "dir")
|
||||||
|
err = os.Mkdir(dir, 0777)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Chdir(wd)
|
||||||
|
|
||||||
|
// Chdir so current directory and a.go reside on the same drive.
|
||||||
|
err = os.Chdir(dir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
noVolume := file[len(filepath.VolumeName(file)):]
|
||||||
|
wrongPath := filepath.Join(dir, noVolume)
|
||||||
|
output, err := exec.Command("go", "build", noVolume).CombinedOutput()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("build should fail")
|
||||||
|
}
|
||||||
|
if strings.Contains(string(output), wrongPath) {
|
||||||
|
t.Fatalf("wrong output found: %v %v", err, string(output))
|
||||||
|
}
|
||||||
|
}
|
|
@ -81,7 +81,8 @@ single directory, the command is applied to a single synthesized
|
||||||
package made up of exactly those files, ignoring any build constraints
|
package made up of exactly those files, ignoring any build constraints
|
||||||
in those files and ignoring any other files in the directory.
|
in those files and ignoring any other files in the directory.
|
||||||
|
|
||||||
File names that begin with "." or "_" are ignored by the go tool.
|
Directory and file names that begin with "." or "_" are ignored
|
||||||
|
by the go tool, as are directories named "testdata".
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +155,11 @@ A few common code hosting sites have special syntax:
|
||||||
import "launchpad.net/~user/project/branch"
|
import "launchpad.net/~user/project/branch"
|
||||||
import "launchpad.net/~user/project/branch/sub/directory"
|
import "launchpad.net/~user/project/branch/sub/directory"
|
||||||
|
|
||||||
|
IBM DevOps Services (Git)
|
||||||
|
|
||||||
|
import "hub.jazz.net/git/user/project"
|
||||||
|
import "hub.jazz.net/git/user/project/sub/directory"
|
||||||
|
|
||||||
For code hosted on other servers, import paths may either be qualified
|
For code hosted on other servers, import paths may either be qualified
|
||||||
with the version control type, or the go tool can dynamically fetch
|
with the version control type, or the go tool can dynamically fetch
|
||||||
the import path over https/http and discover where the code resides
|
the import path over https/http and discover where the code resides
|
||||||
|
@ -229,7 +235,26 @@ listed in the GOPATH environment variable (see 'go help gopath').
|
||||||
|
|
||||||
The go command attempts to download the version of the
|
The go command attempts to download the version of the
|
||||||
package appropriate for the Go release being used.
|
package appropriate for the Go release being used.
|
||||||
Run 'go help install' for more.
|
Run 'go help get' for more.
|
||||||
|
|
||||||
|
Import path checking
|
||||||
|
|
||||||
|
When the custom import path feature described above redirects to a
|
||||||
|
known code hosting site, each of the resulting packages has two possible
|
||||||
|
import paths, using the custom domain or the known hosting site.
|
||||||
|
|
||||||
|
A package statement is said to have an "import comment" if it is immediately
|
||||||
|
followed (before the next newline) by a comment of one of these two forms:
|
||||||
|
|
||||||
|
package math // import "path"
|
||||||
|
package math /* import "path" */
|
||||||
|
|
||||||
|
The go command will refuse to install a package with an import comment
|
||||||
|
unless it is being referred to by that import path. In this way, import comments
|
||||||
|
let package authors make sure the custom import path is used and not a
|
||||||
|
direct path to the underlying code hosting site.
|
||||||
|
|
||||||
|
See https://golang.org/s/go14customimport for details.
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,28 +30,29 @@ syntax of package template. The default output is equivalent to -f
|
||||||
'{{.ImportPath}}'. The struct being passed to the template is:
|
'{{.ImportPath}}'. The struct being passed to the template is:
|
||||||
|
|
||||||
type Package struct {
|
type Package struct {
|
||||||
Dir string // directory containing package sources
|
Dir string // directory containing package sources
|
||||||
ImportPath string // import path of package in dir
|
ImportPath string // import path of package in dir
|
||||||
Name string // package name
|
ImportComment string // path in import comment on package statement
|
||||||
Doc string // package documentation string
|
Name string // package name
|
||||||
Target string // install path
|
Doc string // package documentation string
|
||||||
Goroot bool // is this package in the Go root?
|
Target string // install path
|
||||||
Standard bool // is this package part of the standard Go library?
|
Goroot bool // is this package in the Go root?
|
||||||
Stale bool // would 'go install' do anything for this package?
|
Standard bool // is this package part of the standard Go library?
|
||||||
Root string // Go root or Go path dir containing this package
|
Stale bool // would 'go install' do anything for this package?
|
||||||
|
Root string // Go root or Go path dir containing this package
|
||||||
|
|
||||||
// Source files
|
// Source files
|
||||||
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||||
CgoFiles []string // .go sources files that import "C"
|
CgoFiles []string // .go sources files that import "C"
|
||||||
IgnoredGoFiles []string // .go sources ignored due to build constraints
|
IgnoredGoFiles []string // .go sources ignored due to build constraints
|
||||||
CFiles []string // .c source files
|
CFiles []string // .c source files
|
||||||
CXXFiles []string // .cc, .cxx and .cpp source files
|
CXXFiles []string // .cc, .cxx and .cpp source files
|
||||||
MFiles []string // .m source files
|
MFiles []string // .m source files
|
||||||
HFiles []string // .h, .hh, .hpp and .hxx source files
|
HFiles []string // .h, .hh, .hpp and .hxx source files
|
||||||
SFiles []string // .s source files
|
SFiles []string // .s source files
|
||||||
SwigFiles []string // .swig files
|
SwigFiles []string // .swig files
|
||||||
SwigCXXFiles []string // .swigcxx files
|
SwigCXXFiles []string // .swigcxx files
|
||||||
SysoFiles []string // .syso object files to add to archive
|
SysoFiles []string // .syso object files to add to archive
|
||||||
|
|
||||||
// Cgo directives
|
// Cgo directives
|
||||||
CgoCFLAGS []string // cgo: flags for C compiler
|
CgoCFLAGS []string // cgo: flags for C compiler
|
||||||
|
|
|
@ -79,6 +79,7 @@ var commands = []*Command{
|
||||||
cmdEnv,
|
cmdEnv,
|
||||||
cmdFix,
|
cmdFix,
|
||||||
cmdFmt,
|
cmdFmt,
|
||||||
|
cmdGenerate,
|
||||||
cmdGet,
|
cmdGet,
|
||||||
cmdInstall,
|
cmdInstall,
|
||||||
cmdList,
|
cmdList,
|
||||||
|
@ -536,7 +537,7 @@ func matchPackages(pattern string) []string {
|
||||||
})
|
})
|
||||||
|
|
||||||
for _, src := range buildContext.SrcDirs() {
|
for _, src := range buildContext.SrcDirs() {
|
||||||
if pattern == "std" && src != gorootSrcPkg {
|
if pattern == "std" && src != gorootSrc {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
src = filepath.Clean(src) + string(filepath.Separator)
|
src = filepath.Clean(src) + string(filepath.Separator)
|
||||||
|
@ -618,7 +619,7 @@ func matchPackagesInFS(pattern string) []string {
|
||||||
// The initial case is not Cleaned, though, so we do this explicitly.
|
// The initial case is not Cleaned, though, so we do this explicitly.
|
||||||
//
|
//
|
||||||
// This converts a path like "./io/" to "io". Without this step, running
|
// This converts a path like "./io/" to "io". Without this step, running
|
||||||
// "cd $GOROOT/src/pkg; go list ./io/..." would incorrectly skip the io
|
// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
|
||||||
// package, because prepending the prefix "./" to the unclean path would
|
// package, because prepending the prefix "./" to the unclean path would
|
||||||
// result in "././io", and match("././io") returns false.
|
// result in "././io", and match("././io") returns false.
|
||||||
path = filepath.Clean(path)
|
path = filepath.Clean(path)
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
pathpkg "path"
|
pathpkg "path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -25,16 +26,17 @@ type Package struct {
|
||||||
// Note: These fields are part of the go command's public API.
|
// Note: These fields are part of the go command's public API.
|
||||||
// See list.go. It is okay to add fields, but not to change or
|
// See list.go. It is okay to add fields, but not to change or
|
||||||
// remove existing ones. Keep in sync with list.go
|
// remove existing ones. Keep in sync with list.go
|
||||||
Dir string `json:",omitempty"` // directory containing package sources
|
Dir string `json:",omitempty"` // directory containing package sources
|
||||||
ImportPath string `json:",omitempty"` // import path of package in dir
|
ImportPath string `json:",omitempty"` // import path of package in dir
|
||||||
Name string `json:",omitempty"` // package name
|
ImportComment string `json:",omitempty"` // path in import comment on package statement
|
||||||
Doc string `json:",omitempty"` // package documentation string
|
Name string `json:",omitempty"` // package name
|
||||||
Target string `json:",omitempty"` // install path
|
Doc string `json:",omitempty"` // package documentation string
|
||||||
Goroot bool `json:",omitempty"` // is this package found in the Go root?
|
Target string `json:",omitempty"` // install path
|
||||||
Standard bool `json:",omitempty"` // is this package part of the standard Go library?
|
Goroot bool `json:",omitempty"` // is this package found in the Go root?
|
||||||
Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
|
Standard bool `json:",omitempty"` // is this package part of the standard Go library?
|
||||||
Root string `json:",omitempty"` // Go root or Go path dir containing this package
|
Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
|
||||||
ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
|
Root string `json:",omitempty"` // Go root or Go path dir containing this package
|
||||||
|
ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
|
||||||
|
|
||||||
// Source files
|
// Source files
|
||||||
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||||
|
@ -103,6 +105,7 @@ func (p *Package) copyBuild(pp *build.Package) {
|
||||||
|
|
||||||
p.Dir = pp.Dir
|
p.Dir = pp.Dir
|
||||||
p.ImportPath = pp.ImportPath
|
p.ImportPath = pp.ImportPath
|
||||||
|
p.ImportComment = pp.ImportComment
|
||||||
p.Name = pp.Name
|
p.Name = pp.Name
|
||||||
p.Doc = pp.Doc
|
p.Doc = pp.Doc
|
||||||
p.Root = pp.Root
|
p.Root = pp.Root
|
||||||
|
@ -218,7 +221,7 @@ func dirToImportPath(dir string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeImportValid(r rune) rune {
|
func makeImportValid(r rune) rune {
|
||||||
// Should match Go spec, compilers, and ../../pkg/go/parser/parser.go:/isValidImport.
|
// Should match Go spec, compilers, and ../../go/parser/parser.go:/isValidImport.
|
||||||
const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
|
const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
|
||||||
if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
|
if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
|
||||||
return '_'
|
return '_'
|
||||||
|
@ -244,6 +247,9 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
|
||||||
importPath = dirToImportPath(filepath.Join(srcDir, path))
|
importPath = dirToImportPath(filepath.Join(srcDir, path))
|
||||||
}
|
}
|
||||||
if p := packageCache[importPath]; p != nil {
|
if p := packageCache[importPath]; p != nil {
|
||||||
|
if perr := disallowInternal(srcDir, p, stk); perr != p {
|
||||||
|
return perr
|
||||||
|
}
|
||||||
return reusePackage(p, stk)
|
return reusePackage(p, stk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,11 +264,14 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
|
||||||
//
|
//
|
||||||
// TODO: After Go 1, decide when to pass build.AllowBinary here.
|
// TODO: After Go 1, decide when to pass build.AllowBinary here.
|
||||||
// See issue 3268 for mistakes to avoid.
|
// See issue 3268 for mistakes to avoid.
|
||||||
bp, err := buildContext.Import(path, srcDir, 0)
|
bp, err := buildContext.Import(path, srcDir, build.ImportComment)
|
||||||
bp.ImportPath = importPath
|
bp.ImportPath = importPath
|
||||||
if gobin != "" {
|
if gobin != "" {
|
||||||
bp.BinDir = gobin
|
bp.BinDir = gobin
|
||||||
}
|
}
|
||||||
|
if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path {
|
||||||
|
err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
|
||||||
|
}
|
||||||
p.load(stk, bp, err)
|
p.load(stk, bp, err)
|
||||||
if p.Error != nil && len(importPos) > 0 {
|
if p.Error != nil && len(importPos) > 0 {
|
||||||
pos := importPos[0]
|
pos := importPos[0]
|
||||||
|
@ -270,6 +279,10 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
|
||||||
p.Error.Pos = pos.String()
|
p.Error.Pos = pos.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if perr := disallowInternal(srcDir, p, stk); perr != p {
|
||||||
|
return perr
|
||||||
|
}
|
||||||
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,12 +311,82 @@ func reusePackage(p *Package, stk *importStack) *Package {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// disallowInternal checks that srcDir is allowed to import p.
|
||||||
|
// If the import is allowed, disallowInternal returns the original package p.
|
||||||
|
// If not, it returns a new package containing just an appropriate error.
|
||||||
|
func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
|
||||||
|
// golang.org/s/go14internal:
|
||||||
|
// An import of a path containing the element “internal”
|
||||||
|
// is disallowed if the importing code is outside the tree
|
||||||
|
// rooted at the parent of the “internal” directory.
|
||||||
|
//
|
||||||
|
// ... For Go 1.4, we will implement the rule first for $GOROOT, but not $GOPATH.
|
||||||
|
|
||||||
|
// Only applies to $GOROOT.
|
||||||
|
if !p.Standard {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// The stack includes p.ImportPath.
|
||||||
|
// If that's the only thing on the stack, we started
|
||||||
|
// with a name given on the command line, not an
|
||||||
|
// import. Anything listed on the command line is fine.
|
||||||
|
if len(*stk) == 1 {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for "internal" element: four cases depending on begin of string and/or end of string.
|
||||||
|
i, ok := findInternal(p.ImportPath)
|
||||||
|
if !ok {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal is present.
|
||||||
|
// Map import path back to directory corresponding to parent of internal.
|
||||||
|
if i > 0 {
|
||||||
|
i-- // rewind over slash in ".../internal"
|
||||||
|
}
|
||||||
|
parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
|
||||||
|
if hasPathPrefix(filepath.ToSlash(srcDir), filepath.ToSlash(parent)) {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal is present, and srcDir is outside parent's tree. Not allowed.
|
||||||
|
perr := *p
|
||||||
|
perr.Error = &PackageError{
|
||||||
|
ImportStack: stk.copy(),
|
||||||
|
Err: "use of internal package not allowed",
|
||||||
|
}
|
||||||
|
perr.Incomplete = true
|
||||||
|
return &perr
|
||||||
|
}
|
||||||
|
|
||||||
|
// findInternal looks for the final "internal" path element in the given import path.
|
||||||
|
// If there isn't one, findInternal returns ok=false.
|
||||||
|
// Otherwise, findInternal returns ok=true and the index of the "internal".
|
||||||
|
func findInternal(path string) (index int, ok bool) {
|
||||||
|
// Four cases, depending on internal at start/end of string or not.
|
||||||
|
// The order matters: we must return the index of the final element,
|
||||||
|
// because the final one produces the most restrictive requirement
|
||||||
|
// on the importer.
|
||||||
|
switch {
|
||||||
|
case strings.HasSuffix(path, "/internal"):
|
||||||
|
return len(path) - len("internal"), true
|
||||||
|
case strings.Contains(path, "/internal/"):
|
||||||
|
return strings.LastIndex(path, "/internal/") + 1, true
|
||||||
|
case path == "internal", strings.HasPrefix(path, "internal/"):
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
type targetDir int
|
type targetDir int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
toRoot targetDir = iota // to bin dir inside package root (default)
|
toRoot targetDir = iota // to bin dir inside package root (default)
|
||||||
toTool // GOROOT/pkg/tool
|
toTool // GOROOT/pkg/tool
|
||||||
toBin // GOROOT/bin
|
toBin // GOROOT/bin
|
||||||
|
stalePath // the old import path; fail to build
|
||||||
)
|
)
|
||||||
|
|
||||||
// goTools is a map of Go program import path to install target directory.
|
// goTools is a map of Go program import path to install target directory.
|
||||||
|
@ -316,10 +399,14 @@ var goTools = map[string]targetDir{
|
||||||
"cmd/nm": toTool,
|
"cmd/nm": toTool,
|
||||||
"cmd/objdump": toTool,
|
"cmd/objdump": toTool,
|
||||||
"cmd/pack": toTool,
|
"cmd/pack": toTool,
|
||||||
|
"cmd/pprof": toTool,
|
||||||
"cmd/yacc": toTool,
|
"cmd/yacc": toTool,
|
||||||
"code.google.com/p/go.tools/cmd/cover": toTool,
|
"golang.org/x/tools/cmd/cover": toTool,
|
||||||
"code.google.com/p/go.tools/cmd/godoc": toBin,
|
"golang.org/x/tools/cmd/godoc": toBin,
|
||||||
"code.google.com/p/go.tools/cmd/vet": toTool,
|
"golang.org/x/tools/cmd/vet": toTool,
|
||||||
|
"code.google.com/p/go.tools/cmd/cover": stalePath,
|
||||||
|
"code.google.com/p/go.tools/cmd/godoc": stalePath,
|
||||||
|
"code.google.com/p/go.tools/cmd/vet": stalePath,
|
||||||
}
|
}
|
||||||
|
|
||||||
// expandScanner expands a scanner.List error into all the errors in the list.
|
// expandScanner expands a scanner.List error into all the errors in the list.
|
||||||
|
@ -380,6 +467,13 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Name == "main" {
|
if p.Name == "main" {
|
||||||
|
// Report an error when the old code.google.com/p/go.tools paths are used.
|
||||||
|
if goTools[p.ImportPath] == stalePath {
|
||||||
|
newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
|
||||||
|
e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath)
|
||||||
|
p.Error = &PackageError{Err: e}
|
||||||
|
return p
|
||||||
|
}
|
||||||
_, elem := filepath.Split(p.Dir)
|
_, elem := filepath.Split(p.Dir)
|
||||||
full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem
|
full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem
|
||||||
if buildContext.GOOS != toolGOOS || buildContext.GOARCH != toolGOARCH {
|
if buildContext.GOOS != toolGOOS || buildContext.GOARCH != toolGOARCH {
|
||||||
|
@ -482,7 +576,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
|
||||||
|
|
||||||
// Build list of imported packages and full dependency list.
|
// Build list of imported packages and full dependency list.
|
||||||
imports := make([]*Package, 0, len(p.Imports))
|
imports := make([]*Package, 0, len(p.Imports))
|
||||||
deps := make(map[string]bool)
|
deps := make(map[string]*Package)
|
||||||
for i, path := range importPaths {
|
for i, path := range importPaths {
|
||||||
if path == "C" {
|
if path == "C" {
|
||||||
continue
|
continue
|
||||||
|
@ -505,10 +599,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
|
||||||
path = p1.ImportPath
|
path = p1.ImportPath
|
||||||
importPaths[i] = path
|
importPaths[i] = path
|
||||||
}
|
}
|
||||||
deps[path] = true
|
deps[path] = p1
|
||||||
imports = append(imports, p1)
|
imports = append(imports, p1)
|
||||||
for _, dep := range p1.Deps {
|
for _, dep := range p1.deps {
|
||||||
deps[dep] = true
|
deps[dep.ImportPath] = dep
|
||||||
}
|
}
|
||||||
if p1.Incomplete {
|
if p1.Incomplete {
|
||||||
p.Incomplete = true
|
p.Incomplete = true
|
||||||
|
@ -522,7 +616,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
|
||||||
}
|
}
|
||||||
sort.Strings(p.Deps)
|
sort.Strings(p.Deps)
|
||||||
for _, dep := range p.Deps {
|
for _, dep := range p.Deps {
|
||||||
p1 := packageCache[dep]
|
p1 := deps[dep]
|
||||||
if p1 == nil {
|
if p1 == nil {
|
||||||
panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
|
panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
|
||||||
}
|
}
|
||||||
|
@ -538,6 +632,16 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
|
||||||
}
|
}
|
||||||
p.Target = p.target
|
p.Target = p.target
|
||||||
|
|
||||||
|
// Check for C code compiled with Plan 9 C compiler.
|
||||||
|
// No longer allowed except in runtime and runtime/cgo, for now.
|
||||||
|
if len(p.CFiles) > 0 && !p.usesCgo() && (!p.Standard || p.ImportPath != "runtime") {
|
||||||
|
p.Error = &PackageError{
|
||||||
|
ImportStack: stk.copy(),
|
||||||
|
Err: fmt.Sprintf("C source files not allowed when not using cgo: %s", strings.Join(p.CFiles, " ")),
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
// In the absence of errors lower in the dependency tree,
|
// In the absence of errors lower in the dependency tree,
|
||||||
// check for case-insensitive collisions of import paths.
|
// check for case-insensitive collisions of import paths.
|
||||||
if len(p.DepsErrors) == 0 {
|
if len(p.DepsErrors) == 0 {
|
||||||
|
@ -599,6 +703,12 @@ func computeStale(pkgs ...*Package) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The runtime version string takes one of two forms:
|
||||||
|
// "go1.X[.Y]" for Go releases, and "devel +hash" at tip.
|
||||||
|
// Determine whether we are in a released copy by
|
||||||
|
// inspecting the version.
|
||||||
|
var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
|
||||||
|
|
||||||
// isStale reports whether package p needs to be rebuilt.
|
// isStale reports whether package p needs to be rebuilt.
|
||||||
func isStale(p *Package, topRoot map[string]bool) bool {
|
func isStale(p *Package, topRoot map[string]bool) bool {
|
||||||
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
|
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
|
||||||
|
@ -619,7 +729,16 @@ func isStale(p *Package, topRoot map[string]bool) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if buildA || p.target == "" || p.Stale {
|
// If we are running a release copy of Go, do not rebuild the standard packages.
|
||||||
|
// They may not be writable anyway, but they are certainly not changing.
|
||||||
|
// This makes 'go build -a' skip the standard packages when using an official release.
|
||||||
|
// See issue 4106 and issue 8290.
|
||||||
|
pkgBuildA := buildA
|
||||||
|
if p.Standard && isGoRelease {
|
||||||
|
pkgBuildA = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkgBuildA || p.target == "" || p.Stale {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,24 +826,13 @@ func loadPackage(arg string, stk *importStack) *Package {
|
||||||
arg = sub
|
arg = sub
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(arg, "cmd/") {
|
if strings.HasPrefix(arg, "cmd/") && !strings.Contains(arg[4:], "/") {
|
||||||
if p := cmdCache[arg]; p != nil {
|
if p := cmdCache[arg]; p != nil {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
stk.push(arg)
|
stk.push(arg)
|
||||||
defer stk.pop()
|
defer stk.pop()
|
||||||
|
|
||||||
if strings.Contains(arg[4:], "/") {
|
|
||||||
p := &Package{
|
|
||||||
Error: &PackageError{
|
|
||||||
ImportStack: stk.copy(),
|
|
||||||
Err: fmt.Sprintf("invalid import path: cmd/... is reserved for Go commands"),
|
|
||||||
hard: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
bp, err := buildContext.ImportDir(filepath.Join(gorootSrc, arg), 0)
|
bp, err := buildContext.ImportDir(filepath.Join(gorootSrc, arg), 0)
|
||||||
bp.ImportPath = arg
|
bp.ImportPath = arg
|
||||||
bp.Goroot = true
|
bp.Goroot = true
|
||||||
|
|
|
@ -6,6 +6,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/build"
|
"go/build"
|
||||||
|
@ -65,16 +66,23 @@ non-test installation.
|
||||||
|
|
||||||
In addition to the build flags, the flags handled by 'go test' itself are:
|
In addition to the build flags, the flags handled by 'go test' itself are:
|
||||||
|
|
||||||
-c Compile the test binary to pkg.test but do not run it.
|
-c
|
||||||
(Where pkg is the last element of the package's import path.)
|
Compile the test binary to pkg.test but do not run it
|
||||||
|
(where pkg is the last element of the package's import path).
|
||||||
|
The file name can be changed with the -o flag.
|
||||||
|
|
||||||
|
-exec xprog
|
||||||
|
Run the test binary using xprog. The behavior is the same as
|
||||||
|
in 'go run'. See 'go help run' for details.
|
||||||
|
|
||||||
-i
|
-i
|
||||||
Install packages that are dependencies of the test.
|
Install packages that are dependencies of the test.
|
||||||
Do not run the test.
|
Do not run the test.
|
||||||
|
|
||||||
-exec xprog
|
-o file
|
||||||
Run the test binary using xprog. The behavior is the same as
|
Compile the test binary to the named file.
|
||||||
in 'go run'. See 'go help run' for details.
|
The test still runs (unless -c or -i is specified).
|
||||||
|
|
||||||
|
|
||||||
The test binary also accepts flags that control execution of the test; these
|
The test binary also accepts flags that control execution of the test; these
|
||||||
flags are also accessible by 'go test'. See 'go help testflag' for details.
|
flags are also accessible by 'go test'. See 'go help testflag' for details.
|
||||||
|
@ -122,6 +130,7 @@ control the execution of any test:
|
||||||
-blockprofile block.out
|
-blockprofile block.out
|
||||||
Write a goroutine blocking profile to the specified file
|
Write a goroutine blocking profile to the specified file
|
||||||
when all tests are complete.
|
when all tests are complete.
|
||||||
|
Writes test binary as -c would.
|
||||||
|
|
||||||
-blockprofilerate n
|
-blockprofilerate n
|
||||||
Control the detail provided in goroutine blocking profiles by
|
Control the detail provided in goroutine blocking profiles by
|
||||||
|
@ -153,8 +162,7 @@ control the execution of any test:
|
||||||
Sets -cover.
|
Sets -cover.
|
||||||
|
|
||||||
-coverprofile cover.out
|
-coverprofile cover.out
|
||||||
Write a coverage profile to the specified file after all tests
|
Write a coverage profile to the file after all tests have passed.
|
||||||
have passed.
|
|
||||||
Sets -cover.
|
Sets -cover.
|
||||||
|
|
||||||
-cpu 1,2,4
|
-cpu 1,2,4
|
||||||
|
@ -164,10 +172,11 @@ control the execution of any test:
|
||||||
|
|
||||||
-cpuprofile cpu.out
|
-cpuprofile cpu.out
|
||||||
Write a CPU profile to the specified file before exiting.
|
Write a CPU profile to the specified file before exiting.
|
||||||
|
Writes test binary as -c would.
|
||||||
|
|
||||||
-memprofile mem.out
|
-memprofile mem.out
|
||||||
Write a memory profile to the specified file after all tests
|
Write a memory profile to the file after all tests have passed.
|
||||||
have passed.
|
Writes test binary as -c would.
|
||||||
|
|
||||||
-memprofilerate n
|
-memprofilerate n
|
||||||
Enable more precise (and expensive) memory profiles by setting
|
Enable more precise (and expensive) memory profiles by setting
|
||||||
|
@ -274,10 +283,10 @@ var (
|
||||||
testCoverMode string // -covermode flag
|
testCoverMode string // -covermode flag
|
||||||
testCoverPaths []string // -coverpkg flag
|
testCoverPaths []string // -coverpkg flag
|
||||||
testCoverPkgs []*Package // -coverpkg flag
|
testCoverPkgs []*Package // -coverpkg flag
|
||||||
|
testO string // -o flag
|
||||||
testProfile bool // some profiling flag
|
testProfile bool // some profiling flag
|
||||||
testNeedBinary bool // profile needs to keep binary around
|
testNeedBinary bool // profile needs to keep binary around
|
||||||
testV bool // -v flag
|
testV bool // -v flag
|
||||||
testFiles []string // -file flag(s) TODO: not respected
|
|
||||||
testTimeout string // -timeout flag
|
testTimeout string // -timeout flag
|
||||||
testArgs []string
|
testArgs []string
|
||||||
testBench bool
|
testBench bool
|
||||||
|
@ -291,6 +300,7 @@ var testMainDeps = map[string]bool{
|
||||||
// Dependencies for testmain.
|
// Dependencies for testmain.
|
||||||
"testing": true,
|
"testing": true,
|
||||||
"regexp": true,
|
"regexp": true,
|
||||||
|
"os": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTest(cmd *Command, args []string) {
|
func runTest(cmd *Command, args []string) {
|
||||||
|
@ -308,6 +318,9 @@ func runTest(cmd *Command, args []string) {
|
||||||
if testC && len(pkgs) != 1 {
|
if testC && len(pkgs) != 1 {
|
||||||
fatalf("cannot use -c flag with multiple packages")
|
fatalf("cannot use -c flag with multiple packages")
|
||||||
}
|
}
|
||||||
|
if testO != "" && len(pkgs) != 1 {
|
||||||
|
fatalf("cannot use -o flag with multiple packages")
|
||||||
|
}
|
||||||
if testProfile && len(pkgs) != 1 {
|
if testProfile && len(pkgs) != 1 {
|
||||||
fatalf("cannot use test profile flag with multiple packages")
|
fatalf("cannot use test profile flag with multiple packages")
|
||||||
}
|
}
|
||||||
|
@ -524,6 +537,13 @@ func contains(x []string, s string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var windowsBadWords = []string{
|
||||||
|
"install",
|
||||||
|
"patch",
|
||||||
|
"setup",
|
||||||
|
"update",
|
||||||
|
}
|
||||||
|
|
||||||
func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) {
|
func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) {
|
||||||
if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
|
if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
|
||||||
build := b.action(modeBuild, modeBuild, p)
|
build := b.action(modeBuild, modeBuild, p)
|
||||||
|
@ -695,7 +715,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
|
||||||
omitDWARF: !testC && !testNeedBinary,
|
omitDWARF: !testC && !testNeedBinary,
|
||||||
}
|
}
|
||||||
|
|
||||||
// The generated main also imports testing and regexp.
|
// The generated main also imports testing, regexp, and os.
|
||||||
stk.push("testmain")
|
stk.push("testmain")
|
||||||
for dep := range testMainDeps {
|
for dep := range testMainDeps {
|
||||||
if dep == ptest.ImportPath {
|
if dep == ptest.ImportPath {
|
||||||
|
@ -734,11 +754,13 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
if t.NeedTest || ptest.coverMode != "" {
|
if len(ptest.GoFiles) > 0 {
|
||||||
pmain.imports = append(pmain.imports, ptest)
|
pmain.imports = append(pmain.imports, ptest)
|
||||||
|
t.ImportTest = true
|
||||||
}
|
}
|
||||||
if t.NeedXtest {
|
if pxtest != nil {
|
||||||
pmain.imports = append(pmain.imports, pxtest)
|
pmain.imports = append(pmain.imports, pxtest)
|
||||||
|
t.ImportXtest = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if ptest != p && localCover {
|
if ptest != p && localCover {
|
||||||
|
@ -790,17 +812,54 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
|
||||||
a.objdir = testDir + string(filepath.Separator)
|
a.objdir = testDir + string(filepath.Separator)
|
||||||
a.objpkg = filepath.Join(testDir, "main.a")
|
a.objpkg = filepath.Join(testDir, "main.a")
|
||||||
a.target = filepath.Join(testDir, testBinary) + exeSuffix
|
a.target = filepath.Join(testDir, testBinary) + exeSuffix
|
||||||
pmainAction := a
|
if goos == "windows" {
|
||||||
|
// There are many reserved words on Windows that,
|
||||||
|
// if used in the name of an executable, cause Windows
|
||||||
|
// to try to ask for extra permissions.
|
||||||
|
// The word list includes setup, install, update, and patch,
|
||||||
|
// but it does not appear to be defined anywhere.
|
||||||
|
// We have run into this trying to run the
|
||||||
|
// go.codereview/patch tests.
|
||||||
|
// For package names containing those words, use test.test.exe
|
||||||
|
// instead of pkgname.test.exe.
|
||||||
|
// Note that this file name is only used in the Go command's
|
||||||
|
// temporary directory. If the -c or other flags are
|
||||||
|
// given, the code below will still use pkgname.test.exe.
|
||||||
|
// There are two user-visible effects of this change.
|
||||||
|
// First, you can actually run 'go test' in directories that
|
||||||
|
// have names that Windows thinks are installer-like,
|
||||||
|
// without getting a dialog box asking for more permissions.
|
||||||
|
// Second, in the Windows process listing during go test,
|
||||||
|
// the test shows up as test.test.exe, not pkgname.test.exe.
|
||||||
|
// That second one is a drawback, but it seems a small
|
||||||
|
// price to pay for the test running at all.
|
||||||
|
// If maintaining the list of bad words is too onerous,
|
||||||
|
// we could just do this always on Windows.
|
||||||
|
for _, bad := range windowsBadWords {
|
||||||
|
if strings.Contains(testBinary, bad) {
|
||||||
|
a.target = filepath.Join(testDir, "test.test") + exeSuffix
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buildAction = a
|
||||||
|
|
||||||
if testC || testNeedBinary {
|
if testC || testNeedBinary {
|
||||||
// -c or profiling flag: create action to copy binary to ./test.out.
|
// -c or profiling flag: create action to copy binary to ./test.out.
|
||||||
runAction = &action{
|
target := filepath.Join(cwd, testBinary+exeSuffix)
|
||||||
f: (*builder).install,
|
if testO != "" {
|
||||||
deps: []*action{pmainAction},
|
target = testO
|
||||||
p: pmain,
|
if !filepath.IsAbs(target) {
|
||||||
target: filepath.Join(cwd, testBinary+exeSuffix),
|
target = filepath.Join(cwd, target)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pmainAction = runAction // in case we are running the test
|
buildAction = &action{
|
||||||
|
f: (*builder).install,
|
||||||
|
deps: []*action{buildAction},
|
||||||
|
p: pmain,
|
||||||
|
target: target,
|
||||||
|
}
|
||||||
|
runAction = buildAction // make sure runAction != nil even if not running test
|
||||||
}
|
}
|
||||||
if testC {
|
if testC {
|
||||||
printAction = &action{p: p, deps: []*action{runAction}} // nop
|
printAction = &action{p: p, deps: []*action{runAction}} // nop
|
||||||
|
@ -808,7 +867,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
|
||||||
// run test
|
// run test
|
||||||
runAction = &action{
|
runAction = &action{
|
||||||
f: (*builder).runTest,
|
f: (*builder).runTest,
|
||||||
deps: []*action{pmainAction},
|
deps: []*action{buildAction},
|
||||||
p: p,
|
p: p,
|
||||||
ignoreFail: true,
|
ignoreFail: true,
|
||||||
}
|
}
|
||||||
|
@ -824,7 +883,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pmainAction, runAction, printAction, nil
|
return buildAction, runAction, printAction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testImportStack(top string, p *Package, target string) []string {
|
func testImportStack(top string, p *Package, target string) []string {
|
||||||
|
@ -1068,6 +1127,31 @@ func (b *builder) notest(a *action) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isTestMain tells whether fn is a TestMain(m *testing.M) function.
|
||||||
|
func isTestMain(fn *ast.FuncDecl) bool {
|
||||||
|
if fn.Name.String() != "TestMain" ||
|
||||||
|
fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
|
||||||
|
fn.Type.Params == nil ||
|
||||||
|
len(fn.Type.Params.List) != 1 ||
|
||||||
|
len(fn.Type.Params.List[0].Names) > 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// We can't easily check that the type is *testing.M
|
||||||
|
// because we don't know how testing has been imported,
|
||||||
|
// but at least check that it's *M or *something.M.
|
||||||
|
if name, ok := ptr.X.(*ast.Ident); ok && name.Name == "M" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == "M" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// isTest tells whether name looks like a test (or benchmark, according to prefix).
|
// isTest tells whether name looks like a test (or benchmark, according to prefix).
|
||||||
// It is a Test (say) if there is a character after Test that is not a lower-case letter.
|
// It is a Test (say) if there is a character after Test that is not a lower-case letter.
|
||||||
// We don't want TesticularCancer.
|
// We don't want TesticularCancer.
|
||||||
|
@ -1093,12 +1177,12 @@ func loadTestFuncs(ptest *Package) (*testFuncs, error) {
|
||||||
Package: ptest,
|
Package: ptest,
|
||||||
}
|
}
|
||||||
for _, file := range ptest.TestGoFiles {
|
for _, file := range ptest.TestGoFiles {
|
||||||
if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.NeedTest); err != nil {
|
if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, file := range ptest.XTestGoFiles {
|
for _, file := range ptest.XTestGoFiles {
|
||||||
if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.NeedXtest); err != nil {
|
if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1121,13 +1205,16 @@ func writeTestmain(out string, t *testFuncs) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
type testFuncs struct {
|
type testFuncs struct {
|
||||||
Tests []testFunc
|
Tests []testFunc
|
||||||
Benchmarks []testFunc
|
Benchmarks []testFunc
|
||||||
Examples []testFunc
|
Examples []testFunc
|
||||||
Package *Package
|
TestMain *testFunc
|
||||||
NeedTest bool
|
Package *Package
|
||||||
NeedXtest bool
|
ImportTest bool
|
||||||
Cover []coverInfo
|
NeedTest bool
|
||||||
|
ImportXtest bool
|
||||||
|
NeedXtest bool
|
||||||
|
Cover []coverInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testFuncs) CoverMode() string {
|
func (t *testFuncs) CoverMode() string {
|
||||||
|
@ -1162,7 +1249,7 @@ type testFunc struct {
|
||||||
|
|
||||||
var testFileSet = token.NewFileSet()
|
var testFileSet = token.NewFileSet()
|
||||||
|
|
||||||
func (t *testFuncs) load(filename, pkg string, seen *bool) error {
|
func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
|
||||||
f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
|
f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return expandScanner(err)
|
return expandScanner(err)
|
||||||
|
@ -1177,17 +1264,24 @@ func (t *testFuncs) load(filename, pkg string, seen *bool) error {
|
||||||
}
|
}
|
||||||
name := n.Name.String()
|
name := n.Name.String()
|
||||||
switch {
|
switch {
|
||||||
|
case isTestMain(n):
|
||||||
|
if t.TestMain != nil {
|
||||||
|
return errors.New("multiple definitions of TestMain")
|
||||||
|
}
|
||||||
|
t.TestMain = &testFunc{pkg, name, ""}
|
||||||
|
*doImport, *seen = true, true
|
||||||
case isTest(name, "Test"):
|
case isTest(name, "Test"):
|
||||||
t.Tests = append(t.Tests, testFunc{pkg, name, ""})
|
t.Tests = append(t.Tests, testFunc{pkg, name, ""})
|
||||||
*seen = true
|
*doImport, *seen = true, true
|
||||||
case isTest(name, "Benchmark"):
|
case isTest(name, "Benchmark"):
|
||||||
t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})
|
t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})
|
||||||
*seen = true
|
*doImport, *seen = true, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ex := doc.Examples(f)
|
ex := doc.Examples(f)
|
||||||
sort.Sort(byOrder(ex))
|
sort.Sort(byOrder(ex))
|
||||||
for _, e := range ex {
|
for _, e := range ex {
|
||||||
|
*doImport = true // import test file whether executed or not
|
||||||
if e.Output == "" && !e.EmptyOutput {
|
if e.Output == "" && !e.EmptyOutput {
|
||||||
// Don't run examples with no output.
|
// Don't run examples with no output.
|
||||||
continue
|
continue
|
||||||
|
@ -1208,14 +1302,17 @@ var testmainTmpl = template.Must(template.New("main").Parse(`
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
{{if not .TestMain}}
|
||||||
|
"os"
|
||||||
|
{{end}}
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
{{if .NeedTest}}
|
{{if .ImportTest}}
|
||||||
_test {{.Package.ImportPath | printf "%q"}}
|
{{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .NeedXtest}}
|
{{if .ImportXtest}}
|
||||||
_xtest {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
|
{{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{range $i, $p := .Cover}}
|
{{range $i, $p := .Cover}}
|
||||||
_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
|
_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
|
||||||
|
@ -1302,7 +1399,12 @@ func main() {
|
||||||
CoveredPackages: {{printf "%q" .Covered}},
|
CoveredPackages: {{printf "%q" .Covered}},
|
||||||
})
|
})
|
||||||
{{end}}
|
{{end}}
|
||||||
testing.Main(matchString, tests, benchmarks, examples)
|
m := testing.MainStart(matchString, tests, benchmarks, examples)
|
||||||
|
{{with .TestMain}}
|
||||||
|
{{.Package}}.{{.Name}}(m)
|
||||||
|
{{else}}
|
||||||
|
os.Exit(m.Run())
|
||||||
|
{{end}}
|
||||||
}
|
}
|
||||||
|
|
||||||
`))
|
`))
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// Simple test for go generate.
|
||||||
|
|
||||||
|
// We include a build tag that go generate should ignore.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
//go:generate echo Success
|
||||||
|
|
||||||
|
package p
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// Test that go generate handles command aliases.
|
||||||
|
|
||||||
|
//go:generate -command run echo Now is the time
|
||||||
|
//go:generate run for all good men
|
||||||
|
|
||||||
|
package p
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// Test go generate variable substitution.
|
||||||
|
|
||||||
|
//go:generate echo $GOARCH $GOFILE $GOPACKAGE xyz$GOPACKAGE/$GOFILE/123
|
||||||
|
|
||||||
|
package p
|
|
@ -0,0 +1,3 @@
|
||||||
|
package p
|
||||||
|
|
||||||
|
import "bad"
|
|
@ -0,0 +1,3 @@
|
||||||
|
package p
|
||||||
|
|
||||||
|
import "conflict"
|
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/importcom/src/bad/bad.go
vendored
Normal file
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/importcom/src/bad/bad.go
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package bad // import
|
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/importcom/src/conflict/a.go
vendored
Normal file
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/importcom/src/conflict/a.go
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package conflict // import "a"
|
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/importcom/src/conflict/b.go
vendored
Normal file
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/importcom/src/conflict/b.go
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package conflict /* import "b" */
|
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/importcom/src/works/x/x.go
vendored
Normal file
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/importcom/src/works/x/x.go
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package x // import "works/x"
|
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/importcom/src/works/x/x1.go
vendored
Normal file
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/importcom/src/works/x/x1.go
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package x // important! not an import comment
|
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/importcom/src/wrongplace/x.go
vendored
Normal file
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/importcom/src/wrongplace/x.go
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package x // import "my/x"
|
|
@ -0,0 +1,3 @@
|
||||||
|
package p
|
||||||
|
|
||||||
|
import _ "works/x"
|
|
@ -0,0 +1,3 @@
|
||||||
|
package p
|
||||||
|
|
||||||
|
import "wrongplace"
|
11
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/norunexample/example_test.go
vendored
Normal file
11
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/norunexample/example_test.go
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package pkg_test
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
os.Stdout.Write([]byte("File with non-runnable example was built.\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Example_test() {
|
||||||
|
// This test will not be run, it has no "Output:" comment.
|
||||||
|
}
|
10
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/norunexample/test_test.go
vendored
Normal file
10
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/norunexample/test_test.go
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package pkg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuilt(t *testing.T) {
|
||||||
|
os.Stdout.Write([]byte("A normal test was executed.\n"))
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
package badc
|
5
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/src/badtest/badexec/x_test.go
vendored
Normal file
5
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/src/badtest/badexec/x_test.go
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package badexec
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
panic("badexec")
|
||||||
|
}
|
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x.go
vendored
Normal file
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x.go
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package badsyntax
|
3
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x_test.go
vendored
Normal file
3
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x_test.go
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
package badsyntax
|
||||||
|
|
||||||
|
func func func func func!
|
|
@ -0,0 +1 @@
|
||||||
|
package badvar
|
5
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/src/badtest/badvar/x_test.go
vendored
Normal file
5
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/src/badtest/badvar/x_test.go
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package badvar_test
|
||||||
|
|
||||||
|
func f() {
|
||||||
|
_ = notdefined
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
package p_test
|
|
@ -0,0 +1,7 @@
|
||||||
|
package p
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func f() {
|
||||||
|
fmt.Printf("%d")
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
package p
|
||||||
|
|
||||||
|
import _ "net/http/internal"
|
|
@ -0,0 +1,3 @@
|
||||||
|
package p
|
||||||
|
|
||||||
|
import _ "./x/y/z/internal/w"
|
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go
vendored
Normal file
1
llgo/third_party/gofrontend/libgo/go/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package w
|
|
@ -65,9 +65,9 @@ type testFlagSpec struct {
|
||||||
var testFlagDefn = []*testFlagSpec{
|
var testFlagDefn = []*testFlagSpec{
|
||||||
// local.
|
// local.
|
||||||
{name: "c", boolVar: &testC},
|
{name: "c", boolVar: &testC},
|
||||||
{name: "file", multiOK: true},
|
|
||||||
{name: "cover", boolVar: &testCover},
|
{name: "cover", boolVar: &testCover},
|
||||||
{name: "coverpkg"},
|
{name: "coverpkg"},
|
||||||
|
{name: "o"},
|
||||||
|
|
||||||
// build flags.
|
// build flags.
|
||||||
{name: "a", boolVar: &buildA},
|
{name: "a", boolVar: &buildA},
|
||||||
|
@ -153,6 +153,9 @@ func testFlags(args []string) (packageNames, passToTest []string) {
|
||||||
// bool flags.
|
// bool flags.
|
||||||
case "a", "c", "i", "n", "x", "v", "race", "cover", "work":
|
case "a", "c", "i", "n", "x", "v", "race", "cover", "work":
|
||||||
setBoolFlag(f.boolVar, value)
|
setBoolFlag(f.boolVar, value)
|
||||||
|
case "o":
|
||||||
|
testO = value
|
||||||
|
testNeedBinary = true
|
||||||
case "p":
|
case "p":
|
||||||
setIntFlag(&buildP, value)
|
setIntFlag(&buildP, value)
|
||||||
case "exec":
|
case "exec":
|
||||||
|
@ -184,8 +187,6 @@ func testFlags(args []string) (packageNames, passToTest []string) {
|
||||||
buildContext.BuildTags = strings.Fields(value)
|
buildContext.BuildTags = strings.Fields(value)
|
||||||
case "compiler":
|
case "compiler":
|
||||||
buildCompiler{}.Set(value)
|
buildCompiler{}.Set(value)
|
||||||
case "file":
|
|
||||||
testFiles = append(testFiles, value)
|
|
||||||
case "bench":
|
case "bench":
|
||||||
// record that we saw the flag; don't care about the value
|
// record that we saw the flag; don't care about the value
|
||||||
testBench = true
|
testBench = true
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// This file contains extra hooks for testing the go command.
|
||||||
|
// It is compiled into the Go binary only when building the
|
||||||
|
// test copy; it does not get compiled into the standard go
|
||||||
|
// command, so these testing hooks are not present in the
|
||||||
|
// go command that everyone uses.
|
||||||
|
|
||||||
|
// +build testgo
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if v := os.Getenv("TESTGO_IS_GO_RELEASE"); v != "" {
|
||||||
|
isGoRelease = v == "1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,13 +47,13 @@ const toolWindowsExtension = ".exe"
|
||||||
|
|
||||||
func tool(toolName string) string {
|
func tool(toolName string) string {
|
||||||
toolPath := filepath.Join(toolDir, toolName)
|
toolPath := filepath.Join(toolDir, toolName)
|
||||||
if toolIsWindows && toolName != "pprof" {
|
if toolIsWindows {
|
||||||
toolPath += toolWindowsExtension
|
toolPath += toolWindowsExtension
|
||||||
}
|
}
|
||||||
// Give a nice message if there is no tool with that name.
|
// Give a nice message if there is no tool with that name.
|
||||||
if _, err := os.Stat(toolPath); err != nil {
|
if _, err := os.Stat(toolPath); err != nil {
|
||||||
if isInGoToolsRepo(toolName) {
|
if isInGoToolsRepo(toolName) {
|
||||||
fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get code.google.com/p/go.tools/cmd/%s\n", toolName, toolName)
|
fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get golang.org/x/tools/cmd/%s\n", toolName, toolName)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
|
fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
|
||||||
}
|
}
|
||||||
|
@ -91,16 +91,6 @@ func runTool(cmd *Command, args []string) {
|
||||||
if toolPath == "" {
|
if toolPath == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if toolIsWindows && toolName == "pprof" {
|
|
||||||
args = append([]string{"perl", toolPath}, args[1:]...)
|
|
||||||
var err error
|
|
||||||
toolPath, err = exec.LookPath("perl")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "go tool: perl not found\n")
|
|
||||||
setExitStatus(3)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if toolN {
|
if toolN {
|
||||||
fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " "))
|
fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " "))
|
||||||
return
|
return
|
||||||
|
|
|
@ -33,6 +33,9 @@ type vcsCmd struct {
|
||||||
|
|
||||||
scheme []string
|
scheme []string
|
||||||
pingCmd string
|
pingCmd string
|
||||||
|
|
||||||
|
remoteRepo func(v *vcsCmd, rootDir string) (remoteRepo string, err error)
|
||||||
|
resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A tagCmd describes a command to list available tags
|
// A tagCmd describes a command to list available tags
|
||||||
|
@ -81,8 +84,17 @@ var vcsHg = &vcsCmd{
|
||||||
tagSyncCmd: "update -r {tag}",
|
tagSyncCmd: "update -r {tag}",
|
||||||
tagSyncDefault: "update default",
|
tagSyncDefault: "update default",
|
||||||
|
|
||||||
scheme: []string{"https", "http", "ssh"},
|
scheme: []string{"https", "http", "ssh"},
|
||||||
pingCmd: "identify {scheme}://{repo}",
|
pingCmd: "identify {scheme}://{repo}",
|
||||||
|
remoteRepo: hgRemoteRepo,
|
||||||
|
}
|
||||||
|
|
||||||
|
func hgRemoteRepo(vcsHg *vcsCmd, rootDir string) (remoteRepo string, err error) {
|
||||||
|
out, err := vcsHg.runOutput(rootDir, "paths default")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(out)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// vcsGit describes how to use Git.
|
// vcsGit describes how to use Git.
|
||||||
|
@ -104,8 +116,38 @@ var vcsGit = &vcsCmd{
|
||||||
tagSyncCmd: "checkout {tag}",
|
tagSyncCmd: "checkout {tag}",
|
||||||
tagSyncDefault: "checkout master",
|
tagSyncDefault: "checkout master",
|
||||||
|
|
||||||
scheme: []string{"git", "https", "http", "git+ssh"},
|
scheme: []string{"git", "https", "http", "git+ssh"},
|
||||||
pingCmd: "ls-remote {scheme}://{repo}",
|
pingCmd: "ls-remote {scheme}://{repo}",
|
||||||
|
remoteRepo: gitRemoteRepo,
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitRemoteRepo(vcsGit *vcsCmd, rootDir string) (remoteRepo string, err error) {
|
||||||
|
outb, err := vcsGit.runOutput(rootDir, "remote -v")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out := string(outb)
|
||||||
|
|
||||||
|
// Expect:
|
||||||
|
// origin https://github.com/rsc/pdf (fetch)
|
||||||
|
// origin https://github.com/rsc/pdf (push)
|
||||||
|
// use first line only.
|
||||||
|
|
||||||
|
if !strings.HasPrefix(out, "origin\t") {
|
||||||
|
return "", fmt.Errorf("unable to parse output of git remote -v")
|
||||||
|
}
|
||||||
|
out = strings.TrimPrefix(out, "origin\t")
|
||||||
|
i := strings.Index(out, "\n")
|
||||||
|
if i < 0 {
|
||||||
|
return "", fmt.Errorf("unable to parse output of git remote -v")
|
||||||
|
}
|
||||||
|
out = out[:i]
|
||||||
|
i = strings.LastIndex(out, " ")
|
||||||
|
if i < 0 {
|
||||||
|
return "", fmt.Errorf("unable to parse output of git remote -v")
|
||||||
|
}
|
||||||
|
out = out[:i]
|
||||||
|
return strings.TrimSpace(string(out)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// vcsBzr describes how to use Bazaar.
|
// vcsBzr describes how to use Bazaar.
|
||||||
|
@ -123,8 +165,51 @@ var vcsBzr = &vcsCmd{
|
||||||
tagSyncCmd: "update -r {tag}",
|
tagSyncCmd: "update -r {tag}",
|
||||||
tagSyncDefault: "update -r revno:-1",
|
tagSyncDefault: "update -r revno:-1",
|
||||||
|
|
||||||
scheme: []string{"https", "http", "bzr", "bzr+ssh"},
|
scheme: []string{"https", "http", "bzr", "bzr+ssh"},
|
||||||
pingCmd: "info {scheme}://{repo}",
|
pingCmd: "info {scheme}://{repo}",
|
||||||
|
remoteRepo: bzrRemoteRepo,
|
||||||
|
resolveRepo: bzrResolveRepo,
|
||||||
|
}
|
||||||
|
|
||||||
|
func bzrRemoteRepo(vcsBzr *vcsCmd, rootDir string) (remoteRepo string, err error) {
|
||||||
|
outb, err := vcsBzr.runOutput(rootDir, "config parent_location")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(outb)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) {
|
||||||
|
outb, err := vcsBzr.runOutput(rootDir, "info "+remoteRepo)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out := string(outb)
|
||||||
|
|
||||||
|
// Expect:
|
||||||
|
// ...
|
||||||
|
// (branch root|repository branch): <URL>
|
||||||
|
// ...
|
||||||
|
|
||||||
|
found := false
|
||||||
|
for _, prefix := range []string{"\n branch root: ", "\n repository branch: "} {
|
||||||
|
i := strings.Index(out, prefix)
|
||||||
|
if i >= 0 {
|
||||||
|
out = out[i+len(prefix):]
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return "", fmt.Errorf("unable to parse output of bzr info")
|
||||||
|
}
|
||||||
|
|
||||||
|
i := strings.Index(out, "\n")
|
||||||
|
if i < 0 {
|
||||||
|
return "", fmt.Errorf("unable to parse output of bzr info")
|
||||||
|
}
|
||||||
|
out = out[:i]
|
||||||
|
return strings.TrimSpace(string(out)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// vcsSvn describes how to use Subversion.
|
// vcsSvn describes how to use Subversion.
|
||||||
|
@ -138,8 +223,34 @@ var vcsSvn = &vcsCmd{
|
||||||
// There is no tag command in subversion.
|
// There is no tag command in subversion.
|
||||||
// The branch information is all in the path names.
|
// The branch information is all in the path names.
|
||||||
|
|
||||||
scheme: []string{"https", "http", "svn", "svn+ssh"},
|
scheme: []string{"https", "http", "svn", "svn+ssh"},
|
||||||
pingCmd: "info {scheme}://{repo}",
|
pingCmd: "info {scheme}://{repo}",
|
||||||
|
remoteRepo: svnRemoteRepo,
|
||||||
|
}
|
||||||
|
|
||||||
|
func svnRemoteRepo(vcsSvn *vcsCmd, rootDir string) (remoteRepo string, err error) {
|
||||||
|
outb, err := vcsSvn.runOutput(rootDir, "info")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out := string(outb)
|
||||||
|
|
||||||
|
// Expect:
|
||||||
|
// ...
|
||||||
|
// Repository Root: <URL>
|
||||||
|
// ...
|
||||||
|
|
||||||
|
i := strings.Index(out, "\nRepository Root: ")
|
||||||
|
if i < 0 {
|
||||||
|
return "", fmt.Errorf("unable to parse output of svn info")
|
||||||
|
}
|
||||||
|
out = out[i+len("\nRepository Root: "):]
|
||||||
|
i = strings.Index(out, "\n")
|
||||||
|
if i < 0 {
|
||||||
|
return "", fmt.Errorf("unable to parse output of svn info")
|
||||||
|
}
|
||||||
|
out = out[:i]
|
||||||
|
return strings.TrimSpace(string(out)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *vcsCmd) String() string {
|
func (v *vcsCmd) String() string {
|
||||||
|
@ -361,7 +472,14 @@ var httpPrefixRE = regexp.MustCompile(`^https?:`)
|
||||||
func repoRootForImportPath(importPath string) (*repoRoot, error) {
|
func repoRootForImportPath(importPath string) (*repoRoot, error) {
|
||||||
rr, err := repoRootForImportPathStatic(importPath, "")
|
rr, err := repoRootForImportPathStatic(importPath, "")
|
||||||
if err == errUnknownSite {
|
if err == errUnknownSite {
|
||||||
rr, err = repoRootForImportDynamic(importPath)
|
// If there are wildcards, look up the thing before the wildcard,
|
||||||
|
// hoping it applies to the wildcarded parts too.
|
||||||
|
// This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH.
|
||||||
|
lookup := strings.TrimSuffix(importPath, "/...")
|
||||||
|
if i := strings.Index(lookup, "/.../"); i >= 0 {
|
||||||
|
lookup = lookup[:i]
|
||||||
|
}
|
||||||
|
rr, err = repoRootForImportDynamic(lookup)
|
||||||
|
|
||||||
// repoRootForImportDynamic returns error detail
|
// repoRootForImportDynamic returns error detail
|
||||||
// that is irrelevant if the user didn't intend to use a
|
// that is irrelevant if the user didn't intend to use a
|
||||||
|
@ -465,11 +583,11 @@ func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) {
|
||||||
func repoRootForImportDynamic(importPath string) (*repoRoot, error) {
|
func repoRootForImportDynamic(importPath string) (*repoRoot, error) {
|
||||||
slash := strings.Index(importPath, "/")
|
slash := strings.Index(importPath, "/")
|
||||||
if slash < 0 {
|
if slash < 0 {
|
||||||
return nil, errors.New("import path doesn't contain a slash")
|
return nil, errors.New("import path does not contain a slash")
|
||||||
}
|
}
|
||||||
host := importPath[:slash]
|
host := importPath[:slash]
|
||||||
if !strings.Contains(host, ".") {
|
if !strings.Contains(host, ".") {
|
||||||
return nil, errors.New("import path doesn't contain a hostname")
|
return nil, errors.New("import path does not begin with hostname")
|
||||||
}
|
}
|
||||||
urlStr, body, err := httpsOrHTTP(importPath)
|
urlStr, body, err := httpsOrHTTP(importPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -613,6 +731,15 @@ var vcsPaths = []*vcsPath{
|
||||||
check: launchpadVCS,
|
check: launchpadVCS,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// IBM DevOps Services (JazzHub)
|
||||||
|
{
|
||||||
|
prefix: "hub.jazz.net/git",
|
||||||
|
re: `^(?P<root>hub.jazz.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
|
||||||
|
vcs: "git",
|
||||||
|
repo: "https://{root}",
|
||||||
|
check: noVCSSuffix,
|
||||||
|
},
|
||||||
|
|
||||||
// General syntax for any server.
|
// General syntax for any server.
|
||||||
{
|
{
|
||||||
re: `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,
|
re: `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
// Copyright 2014 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 (
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath.
|
||||||
|
// TODO(cmang): Add tests for SVN and BZR.
|
||||||
|
func TestRepoRootForImportPath(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping test to avoid external network")
|
||||||
|
}
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "nacl", "android":
|
||||||
|
t.Skipf("no networking available on %s", runtime.GOOS)
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
path string
|
||||||
|
want *repoRoot
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"code.google.com/p/go",
|
||||||
|
&repoRoot{
|
||||||
|
vcs: vcsHg,
|
||||||
|
repo: "https://code.google.com/p/go",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/*{
|
||||||
|
"code.google.com/r/go",
|
||||||
|
&repoRoot{
|
||||||
|
vcs: vcsHg,
|
||||||
|
repo: "https://code.google.com/r/go",
|
||||||
|
},
|
||||||
|
},*/
|
||||||
|
{
|
||||||
|
"github.com/golang/groupcache",
|
||||||
|
&repoRoot{
|
||||||
|
vcs: vcsGit,
|
||||||
|
repo: "https://github.com/golang/groupcache",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// IBM DevOps Services tests
|
||||||
|
{
|
||||||
|
"hub.jazz.net/git/user1/pkgname",
|
||||||
|
&repoRoot{
|
||||||
|
vcs: vcsGit,
|
||||||
|
repo: "https://hub.jazz.net/git/user1/pkgname",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hub.jazz.net/git/user1/pkgname/submodule/submodule/submodule",
|
||||||
|
&repoRoot{
|
||||||
|
vcs: vcsGit,
|
||||||
|
repo: "https://hub.jazz.net/git/user1/pkgname",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hub.jazz.net",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hub2.jazz.net",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hub.jazz.net/someotherprefix",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hub.jazz.net/someotherprefix/user1/pkgname",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
// Spaces are not valid in user names or package names
|
||||||
|
{
|
||||||
|
"hub.jazz.net/git/User 1/pkgname",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hub.jazz.net/git/user1/pkg name",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
// Dots are not valid in user names
|
||||||
|
{
|
||||||
|
"hub.jazz.net/git/user.1/pkgname",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hub.jazz.net/git/user/pkg.name",
|
||||||
|
&repoRoot{
|
||||||
|
vcs: vcsGit,
|
||||||
|
repo: "https://hub.jazz.net/git/user/pkg.name",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// User names cannot have uppercase letters
|
||||||
|
{
|
||||||
|
"hub.jazz.net/git/USER/pkgname",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
got, err := repoRootForImportPath(test.path)
|
||||||
|
want := test.want
|
||||||
|
|
||||||
|
if want == nil {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("RepoRootForImport(%q): Error expected but not received", test.path)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("RepoRootForImport(%q): %v", test.path, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if got.vcs.name != want.vcs.name || got.repo != want.repo {
|
||||||
|
t.Errorf("RepoRootForImport(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.vcs, got.repo, want.vcs, want.repo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import "path/filepath"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
addBuildFlagsNX(cmdVet)
|
addBuildFlagsNX(cmdVet)
|
||||||
}
|
}
|
||||||
|
@ -15,7 +17,7 @@ var cmdVet = &Command{
|
||||||
Long: `
|
Long: `
|
||||||
Vet runs the Go vet command on the packages named by the import paths.
|
Vet runs the Go vet command on the packages named by the import paths.
|
||||||
|
|
||||||
For more about vet, see 'godoc code.google.com/p/go.tools/cmd/vet'.
|
For more about vet, see 'godoc golang.org/x/tools/cmd/vet'.
|
||||||
For more about specifying packages, see 'go help packages'.
|
For more about specifying packages, see 'go help packages'.
|
||||||
|
|
||||||
To run the vet tool with specific options, run 'go tool vet'.
|
To run the vet tool with specific options, run 'go tool vet'.
|
||||||
|
@ -28,10 +30,21 @@ See also: go fmt, go fix.
|
||||||
}
|
}
|
||||||
|
|
||||||
func runVet(cmd *Command, args []string) {
|
func runVet(cmd *Command, args []string) {
|
||||||
for _, pkg := range packages(args) {
|
for _, p := range packages(args) {
|
||||||
// Use pkg.gofiles instead of pkg.Dir so that
|
// Vet expects to be given a set of files all from the same package.
|
||||||
// the command only applies to this package,
|
// Run once for package p and once for package p_test.
|
||||||
// not to packages in subdirectories.
|
if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 {
|
||||||
run(tool("vet"), relPaths(stringList(pkg.gofiles, pkg.sfiles)))
|
runVetFiles(p, stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.SFiles))
|
||||||
|
}
|
||||||
|
if len(p.XTestGoFiles) > 0 {
|
||||||
|
runVetFiles(p, stringList(p.XTestGoFiles))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runVetFiles(p *Package, files []string) {
|
||||||
|
for i := range files {
|
||||||
|
files[i] = filepath.Join(p.Dir, files[i])
|
||||||
|
}
|
||||||
|
run(tool("vet"), relPaths(files))
|
||||||
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ To remove the parentheses:
|
||||||
|
|
||||||
To convert the package tree from explicit slice upper bounds to implicit ones:
|
To convert the package tree from explicit slice upper bounds to implicit ones:
|
||||||
|
|
||||||
gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src/pkg
|
gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src
|
||||||
|
|
||||||
The simplify command
|
The simplify command
|
||||||
|
|
||||||
|
|
|
@ -87,13 +87,13 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
file, adjust, err := parse(fileSet, filename, src, stdin)
|
file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if rewrite != nil {
|
if rewrite != nil {
|
||||||
if adjust == nil {
|
if sourceAdj == nil {
|
||||||
file = rewrite(file)
|
file = rewrite(file)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(os.Stderr, "warning: rewrite ignored for incomplete programs\n")
|
fmt.Fprintf(os.Stderr, "warning: rewrite ignored for incomplete programs\n")
|
||||||
|
@ -106,15 +106,10 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
|
||||||
simplify(file)
|
simplify(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
|
||||||
err = (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(&buf, fileSet, file)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
res := buf.Bytes()
|
|
||||||
if adjust != nil {
|
|
||||||
res = adjust(src, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bytes.Equal(src, res) {
|
if !bytes.Equal(src, res) {
|
||||||
// formatting has changed
|
// formatting has changed
|
||||||
|
@ -122,7 +117,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
|
||||||
fmt.Fprintln(out, filename)
|
fmt.Fprintln(out, filename)
|
||||||
}
|
}
|
||||||
if *write {
|
if *write {
|
||||||
err = ioutil.WriteFile(filename, res, 0)
|
err = ioutil.WriteFile(filename, res, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -186,6 +181,11 @@ func gofmtMain() {
|
||||||
initRewrite()
|
initRewrite()
|
||||||
|
|
||||||
if flag.NArg() == 0 {
|
if flag.NArg() == 0 {
|
||||||
|
if *write {
|
||||||
|
fmt.Fprintln(os.Stderr, "error: cannot use -w with standard input")
|
||||||
|
exitCode = 2
|
||||||
|
return
|
||||||
|
}
|
||||||
if err := processFile("<standard input>", os.Stdin, os.Stdout, true); err != nil {
|
if err := processFile("<standard input>", os.Stdin, os.Stdout, true); err != nil {
|
||||||
report(err)
|
report(err)
|
||||||
}
|
}
|
||||||
|
@ -235,19 +235,29 @@ func diff(b1, b2 []byte) (data []byte, err error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse parses src, which was read from filename,
|
// ----------------------------------------------------------------------------
|
||||||
// as a Go source file or statement list.
|
// Support functions
|
||||||
func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.File, func(orig, src []byte) []byte, error) {
|
//
|
||||||
|
// The functions parse, format, and isSpace below are identical to the
|
||||||
|
// respective functions in src/go/format/format.go - keep them in sync!
|
||||||
|
//
|
||||||
|
// TODO(gri) Factor out this functionality, eventually.
|
||||||
|
|
||||||
|
// parse parses src, which was read from the named file,
|
||||||
|
// as a Go source file, declaration, or statement list.
|
||||||
|
func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
|
||||||
|
file *ast.File,
|
||||||
|
sourceAdj func(src []byte, indent int) []byte,
|
||||||
|
indentAdj int,
|
||||||
|
err error,
|
||||||
|
) {
|
||||||
// Try as whole source file.
|
// Try as whole source file.
|
||||||
file, err := parser.ParseFile(fset, filename, src, parserMode)
|
file, err = parser.ParseFile(fset, filename, src, parserMode)
|
||||||
if err == nil {
|
// If there's no error, return. If the error is that the source file didn't begin with a
|
||||||
return file, nil, nil
|
// package line and source fragments are ok, fall through to
|
||||||
}
|
|
||||||
// If the error is that the source file didn't begin with a
|
|
||||||
// package line and this is standard input, fall through to
|
|
||||||
// try as a source fragment. Stop and return on any other error.
|
// try as a source fragment. Stop and return on any other error.
|
||||||
if !stdin || !strings.Contains(err.Error(), "expected 'package'") {
|
if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
|
||||||
return nil, nil, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a declaration list, make it a source file
|
// If this is a declaration list, make it a source file
|
||||||
|
@ -257,19 +267,19 @@ func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.F
|
||||||
psrc := append([]byte("package p;"), src...)
|
psrc := append([]byte("package p;"), src...)
|
||||||
file, err = parser.ParseFile(fset, filename, psrc, parserMode)
|
file, err = parser.ParseFile(fset, filename, psrc, parserMode)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
adjust := func(orig, src []byte) []byte {
|
sourceAdj = func(src []byte, indent int) []byte {
|
||||||
// Remove the package clause.
|
// Remove the package clause.
|
||||||
// Gofmt has turned the ; into a \n.
|
// Gofmt has turned the ; into a \n.
|
||||||
src = src[len("package p\n"):]
|
src = src[indent+len("package p\n"):]
|
||||||
return matchSpace(orig, src)
|
return bytes.TrimSpace(src)
|
||||||
}
|
}
|
||||||
return file, adjust, nil
|
return
|
||||||
}
|
}
|
||||||
// If the error is that the source file didn't begin with a
|
// If the error is that the source file didn't begin with a
|
||||||
// declaration, fall through to try as a statement list.
|
// declaration, fall through to try as a statement list.
|
||||||
// Stop and return on any other error.
|
// Stop and return on any other error.
|
||||||
if !strings.Contains(err.Error(), "expected declaration") {
|
if !strings.Contains(err.Error(), "expected declaration") {
|
||||||
return nil, nil, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a statement list, make it a source file
|
// If this is a statement list, make it a source file
|
||||||
|
@ -277,68 +287,101 @@ func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.F
|
||||||
// into a function body. This handles expressions too.
|
// into a function body. This handles expressions too.
|
||||||
// Insert using a ;, not a newline, so that the line numbers
|
// Insert using a ;, not a newline, so that the line numbers
|
||||||
// in fsrc match the ones in src.
|
// in fsrc match the ones in src.
|
||||||
fsrc := append(append([]byte("package p; func _() {"), src...), '}')
|
fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '}')
|
||||||
file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
|
file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
adjust := func(orig, src []byte) []byte {
|
sourceAdj = func(src []byte, indent int) []byte {
|
||||||
|
// Cap adjusted indent to zero.
|
||||||
|
if indent < 0 {
|
||||||
|
indent = 0
|
||||||
|
}
|
||||||
// Remove the wrapping.
|
// Remove the wrapping.
|
||||||
// Gofmt has turned the ; into a \n\n.
|
// Gofmt has turned the ; into a \n\n.
|
||||||
src = src[len("package p\n\nfunc _() {"):]
|
// There will be two non-blank lines with indent, hence 2*indent.
|
||||||
src = src[:len(src)-len("}\n")]
|
src = src[2*indent+len("package p\n\nfunc _() {"):]
|
||||||
// Gofmt has also indented the function body one level.
|
src = src[:len(src)-(indent+len("\n}\n"))]
|
||||||
// Remove that indent.
|
return bytes.TrimSpace(src)
|
||||||
src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1)
|
|
||||||
return matchSpace(orig, src)
|
|
||||||
}
|
}
|
||||||
return file, adjust, nil
|
// Gofmt has also indented the function body one level.
|
||||||
|
// Adjust that with indentAdj.
|
||||||
|
indentAdj = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Failed, and out of options.
|
// Succeeded, or out of options.
|
||||||
return nil, nil, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func cutSpace(b []byte) (before, middle, after []byte) {
|
// format formats the given package file originally obtained from src
|
||||||
i := 0
|
// and adjusts the result based on the original source via sourceAdj
|
||||||
for i < len(b) && (b[i] == ' ' || b[i] == '\t' || b[i] == '\n') {
|
// and indentAdj.
|
||||||
i++
|
func format(
|
||||||
|
fset *token.FileSet,
|
||||||
|
file *ast.File,
|
||||||
|
sourceAdj func(src []byte, indent int) []byte,
|
||||||
|
indentAdj int,
|
||||||
|
src []byte,
|
||||||
|
cfg printer.Config,
|
||||||
|
) ([]byte, error) {
|
||||||
|
if sourceAdj == nil {
|
||||||
|
// Complete source file.
|
||||||
|
var buf bytes.Buffer
|
||||||
|
err := cfg.Fprint(&buf, fset, file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
j := len(b)
|
|
||||||
for j > 0 && (b[j-1] == ' ' || b[j-1] == '\t' || b[j-1] == '\n') {
|
// Partial source file.
|
||||||
j--
|
// Determine and prepend leading space.
|
||||||
|
i, j := 0, 0
|
||||||
|
for j < len(src) && isSpace(src[j]) {
|
||||||
|
if src[j] == '\n' {
|
||||||
|
i = j + 1 // byte offset of last line in leading space
|
||||||
|
}
|
||||||
|
j++
|
||||||
}
|
}
|
||||||
if i <= j {
|
var res []byte
|
||||||
return b[:i], b[i:j], b[j:]
|
res = append(res, src[:i]...)
|
||||||
|
|
||||||
|
// Determine and prepend indentation of first code line.
|
||||||
|
// Spaces are ignored unless there are no tabs,
|
||||||
|
// in which case spaces count as one tab.
|
||||||
|
indent := 0
|
||||||
|
hasSpace := false
|
||||||
|
for _, b := range src[i:j] {
|
||||||
|
switch b {
|
||||||
|
case ' ':
|
||||||
|
hasSpace = true
|
||||||
|
case '\t':
|
||||||
|
indent++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil, nil, b[j:]
|
if indent == 0 && hasSpace {
|
||||||
|
indent = 1
|
||||||
|
}
|
||||||
|
for i := 0; i < indent; i++ {
|
||||||
|
res = append(res, '\t')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the source.
|
||||||
|
// Write it without any leading and trailing space.
|
||||||
|
cfg.Indent = indent + indentAdj
|
||||||
|
var buf bytes.Buffer
|
||||||
|
err := cfg.Fprint(&buf, fset, file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...)
|
||||||
|
|
||||||
|
// Determine and append trailing space.
|
||||||
|
i = len(src)
|
||||||
|
for i > 0 && isSpace(src[i-1]) {
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
return append(res, src[i:]...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchSpace reformats src to use the same space context as orig.
|
func isSpace(b byte) bool {
|
||||||
// 1) If orig begins with blank lines, matchSpace inserts them at the beginning of src.
|
return b == ' ' || b == '\t' || b == '\n' || b == '\r'
|
||||||
// 2) matchSpace copies the indentation of the first non-blank line in orig
|
|
||||||
// to every non-blank line in src.
|
|
||||||
// 3) matchSpace copies the trailing space from orig and uses it in place
|
|
||||||
// of src's trailing space.
|
|
||||||
func matchSpace(orig []byte, src []byte) []byte {
|
|
||||||
before, _, after := cutSpace(orig)
|
|
||||||
i := bytes.LastIndex(before, []byte{'\n'})
|
|
||||||
before, indent := before[:i+1], before[i+1:]
|
|
||||||
|
|
||||||
_, src, _ = cutSpace(src)
|
|
||||||
|
|
||||||
var b bytes.Buffer
|
|
||||||
b.Write(before)
|
|
||||||
for len(src) > 0 {
|
|
||||||
line := src
|
|
||||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
|
||||||
line, src = line[:i+1], line[i+1:]
|
|
||||||
} else {
|
|
||||||
src = nil
|
|
||||||
}
|
|
||||||
if len(line) > 0 && line[0] != '\n' { // not blank
|
|
||||||
b.Write(indent)
|
|
||||||
}
|
|
||||||
b.Write(line)
|
|
||||||
}
|
|
||||||
b.Write(after)
|
|
||||||
return b.Bytes()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,18 +6,60 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"flag"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"text/scanner"
|
||||||
)
|
)
|
||||||
|
|
||||||
func runTest(t *testing.T, in, out, flags string) {
|
var update = flag.Bool("update", false, "update .golden files")
|
||||||
|
|
||||||
|
// gofmtFlags looks for a comment of the form
|
||||||
|
//
|
||||||
|
// //gofmt flags
|
||||||
|
//
|
||||||
|
// within the first maxLines lines of the given file,
|
||||||
|
// and returns the flags string, if any. Otherwise it
|
||||||
|
// returns the empty string.
|
||||||
|
func gofmtFlags(filename string, maxLines int) string {
|
||||||
|
f, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return "" // ignore errors - they will be found later
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// initialize scanner
|
||||||
|
var s scanner.Scanner
|
||||||
|
s.Init(f)
|
||||||
|
s.Error = func(*scanner.Scanner, string) {} // ignore errors
|
||||||
|
s.Mode = scanner.GoTokens &^ scanner.SkipComments // want comments
|
||||||
|
|
||||||
|
// look for //gofmt comment
|
||||||
|
for s.Line <= maxLines {
|
||||||
|
switch s.Scan() {
|
||||||
|
case scanner.Comment:
|
||||||
|
const prefix = "//gofmt "
|
||||||
|
if t := s.TokenText(); strings.HasPrefix(t, prefix) {
|
||||||
|
return strings.TrimSpace(t[len(prefix):])
|
||||||
|
}
|
||||||
|
case scanner.EOF:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTest(t *testing.T, in, out string) {
|
||||||
// process flags
|
// process flags
|
||||||
*simplifyAST = false
|
*simplifyAST = false
|
||||||
*rewriteRule = ""
|
*rewriteRule = ""
|
||||||
stdin := false
|
stdin := false
|
||||||
for _, flag := range strings.Split(flags, " ") {
|
for _, flag := range strings.Split(gofmtFlags(in, 20), " ") {
|
||||||
elts := strings.SplitN(flag, "=", 2)
|
elts := strings.SplitN(flag, "=", 2)
|
||||||
name := elts[0]
|
name := elts[0]
|
||||||
value := ""
|
value := ""
|
||||||
|
@ -56,6 +98,17 @@ func runTest(t *testing.T, in, out, flags string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if got := buf.Bytes(); !bytes.Equal(got, expected) {
|
if got := buf.Bytes(); !bytes.Equal(got, expected) {
|
||||||
|
if *update {
|
||||||
|
if in != out {
|
||||||
|
if err := ioutil.WriteFile(out, got, 0666); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// in == out: don't accidentally destroy input
|
||||||
|
t.Errorf("WARNING: -update did not rewrite input file %s", in)
|
||||||
|
}
|
||||||
|
|
||||||
t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in)
|
t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in)
|
||||||
d, err := diff(expected, got)
|
d, err := diff(expected, got)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -67,51 +120,37 @@ func runTest(t *testing.T, in, out, flags string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tests = []struct {
|
// TestRewrite processes testdata/*.input files and compares them to the
|
||||||
in, flags string
|
// corresponding testdata/*.golden files. The gofmt flags used to process
|
||||||
}{
|
// a file must be provided via a comment of the form
|
||||||
{"gofmt.go", ""},
|
//
|
||||||
{"gofmt_test.go", ""},
|
// //gofmt flags
|
||||||
{"testdata/composites.input", "-s"},
|
//
|
||||||
{"testdata/slices1.input", "-s"},
|
// in the processed file within the first 20 lines, if any.
|
||||||
{"testdata/slices2.input", "-s"},
|
|
||||||
{"testdata/old.input", ""},
|
|
||||||
{"testdata/rewrite1.input", "-r=Foo->Bar"},
|
|
||||||
{"testdata/rewrite2.input", "-r=int->bool"},
|
|
||||||
{"testdata/rewrite3.input", "-r=x->x"},
|
|
||||||
{"testdata/rewrite4.input", "-r=(x)->x"},
|
|
||||||
{"testdata/rewrite5.input", "-r=x+x->2*x"},
|
|
||||||
{"testdata/rewrite6.input", "-r=fun(x)->Fun(x)"},
|
|
||||||
{"testdata/rewrite7.input", "-r=fun(x...)->Fun(x)"},
|
|
||||||
{"testdata/rewrite8.input", "-r=interface{}->int"},
|
|
||||||
{"testdata/stdin*.input", "-stdin"},
|
|
||||||
{"testdata/comments.input", ""},
|
|
||||||
{"testdata/import.input", ""},
|
|
||||||
{"testdata/crlf.input", ""}, // test case for issue 3961; see also TestCRLF
|
|
||||||
{"testdata/typeswitch.input", ""}, // test case for issue 4470
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRewrite(t *testing.T) {
|
func TestRewrite(t *testing.T) {
|
||||||
for _, test := range tests {
|
// determine input files
|
||||||
match, err := filepath.Glob(test.in)
|
match, err := filepath.Glob("testdata/*.input")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Fatal(err)
|
||||||
continue
|
}
|
||||||
|
|
||||||
|
// add larger examples
|
||||||
|
match = append(match, "gofmt.go", "gofmt_test.go")
|
||||||
|
|
||||||
|
for _, in := range match {
|
||||||
|
out := in // for files where input and output are identical
|
||||||
|
if strings.HasSuffix(in, ".input") {
|
||||||
|
out = in[:len(in)-len(".input")] + ".golden"
|
||||||
}
|
}
|
||||||
for _, in := range match {
|
runTest(t, in, out)
|
||||||
out := in
|
if in != out {
|
||||||
if strings.HasSuffix(in, ".input") {
|
// Check idempotence.
|
||||||
out = in[:len(in)-len(".input")] + ".golden"
|
runTest(t, out, out)
|
||||||
}
|
|
||||||
runTest(t, in, out, test.flags)
|
|
||||||
if in != out {
|
|
||||||
// Check idempotence.
|
|
||||||
runTest(t, out, out, test.flags)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test case for issue 3961.
|
||||||
func TestCRLF(t *testing.T) {
|
func TestCRLF(t *testing.T) {
|
||||||
const input = "testdata/crlf.input" // must contain CR/LF's
|
const input = "testdata/crlf.input" // must contain CR/LF's
|
||||||
const golden = "testdata/crlf.golden" // must not contain any CR's
|
const golden = "testdata/crlf.golden" // must not contain any CR's
|
||||||
|
|
|
@ -32,7 +32,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error {
|
func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error {
|
||||||
f, _, err := parse(fset, filename, src.Bytes(), false)
|
f, _, _, err := parse(fset, filename, src.Bytes(), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
|
||||||
|
|
||||||
// exclude files w/ syntax errors (typically test cases)
|
// exclude files w/ syntax errors (typically test cases)
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
if _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil {
|
if _, _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil {
|
||||||
if *verbose {
|
if *verbose {
|
||||||
fmt.Fprintf(os.Stderr, "ignoring %s\n", err)
|
fmt.Fprintf(os.Stderr, "ignoring %s\n", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,9 +226,6 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
if p.NumField() != v.NumField() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i := 0; i < p.NumField(); i++ {
|
for i := 0; i < p.NumField(); i++ {
|
||||||
if !match(m, p.Field(i), v.Field(i)) {
|
if !match(m, p.Field(i), v.Field(i)) {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -68,9 +68,10 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor {
|
||||||
// a slice expression of the form: s[a:len(s)]
|
// a slice expression of the form: s[a:len(s)]
|
||||||
// can be simplified to: s[a:]
|
// can be simplified to: s[a:]
|
||||||
// if s is "simple enough" (for now we only accept identifiers)
|
// if s is "simple enough" (for now we only accept identifiers)
|
||||||
if s.hasDotImport {
|
if n.Max != nil || s.hasDotImport {
|
||||||
// if dot imports are present, we cannot be certain that an
|
// - 3-index slices always require the 2nd and 3rd index
|
||||||
// unresolved "len" identifier refers to the predefined len()
|
// - if dot imports are present, we cannot be certain that an
|
||||||
|
// unresolved "len" identifier refers to the predefined len()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil {
|
if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil {
|
||||||
|
@ -96,16 +97,26 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor {
|
||||||
// x, y := b[:n], b[n:]
|
// x, y := b[:n], b[n:]
|
||||||
|
|
||||||
case *ast.RangeStmt:
|
case *ast.RangeStmt:
|
||||||
// a range of the form: for x, _ = range v {...}
|
// - a range of the form: for x, _ = range v {...}
|
||||||
// can be simplified to: for x = range v {...}
|
// can be simplified to: for x = range v {...}
|
||||||
if ident, _ := n.Value.(*ast.Ident); ident != nil && ident.Name == "_" {
|
// - a range of the form: for _ = range v {...}
|
||||||
|
// can be simplified to: for range v {...}
|
||||||
|
if isBlank(n.Value) {
|
||||||
n.Value = nil
|
n.Value = nil
|
||||||
}
|
}
|
||||||
|
if isBlank(n.Key) && n.Value == nil {
|
||||||
|
n.Key = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isBlank(x ast.Expr) bool {
|
||||||
|
ident, ok := x.(*ast.Ident)
|
||||||
|
return ok && ident.Name == "_"
|
||||||
|
}
|
||||||
|
|
||||||
func simplify(f *ast.File) {
|
func simplify(f *ast.File) {
|
||||||
var s simplifier
|
var s simplifier
|
||||||
|
|
||||||
|
@ -117,5 +128,34 @@ func simplify(f *ast.File) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove empty declarations such as "const ()", etc
|
||||||
|
removeEmptyDeclGroups(f)
|
||||||
|
|
||||||
ast.Walk(&s, f)
|
ast.Walk(&s, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func removeEmptyDeclGroups(f *ast.File) {
|
||||||
|
i := 0
|
||||||
|
for _, d := range f.Decls {
|
||||||
|
if g, ok := d.(*ast.GenDecl); !ok || !isEmpty(f, g) {
|
||||||
|
f.Decls[i] = d
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.Decls = f.Decls[:i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func isEmpty(f *ast.File, g *ast.GenDecl) bool {
|
||||||
|
if g.Doc != nil || g.Specs != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range f.Comments {
|
||||||
|
// if there is a comment in the declaration, it is not considered empty
|
||||||
|
if g.Pos() <= c.Pos() && c.End() <= g.End() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -s
|
||||||
|
|
||||||
package P
|
package P
|
||||||
|
|
||||||
type T struct {
|
type T struct {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -s
|
||||||
|
|
||||||
package P
|
package P
|
||||||
|
|
||||||
type T struct {
|
type T struct {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
Source containing CR/LF line endings.
|
Source containing CR/LF line endings.
|
||||||
The gofmt'ed output must only have LF
|
The gofmt'ed output must only have LF
|
||||||
line endings.
|
line endings.
|
||||||
|
Test case for issue 3961.
|
||||||
*/
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
Source containing CR/LF line endings.
|
Source containing CR/LF line endings.
|
||||||
The gofmt'ed output must only have LF
|
The gofmt'ed output must only have LF
|
||||||
line endings.
|
line endings.
|
||||||
|
Test case for issue 3961.
|
||||||
*/
|
*/
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=Foo->Bar
|
||||||
|
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=Foo->Bar
|
||||||
|
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=int->bool
|
||||||
|
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=int->bool
|
||||||
|
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=x->x
|
||||||
|
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=x->x
|
||||||
|
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=(x)->x
|
||||||
|
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=(x)->x
|
||||||
|
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=x+x->2*x
|
||||||
|
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=x+x->2*x
|
||||||
|
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=fun(x)->Fun(x)
|
||||||
|
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=fun(x)->Fun(x)
|
||||||
|
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=fun(x...)->Fun(x)
|
||||||
|
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=fun(x...)->Fun(x)
|
||||||
|
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=interface{}->int
|
||||||
|
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -r=interface{}->int
|
||||||
|
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -s
|
||||||
|
|
||||||
// Test cases for slice expression simplification.
|
// Test cases for slice expression simplification.
|
||||||
package p
|
package p
|
||||||
|
|
||||||
|
@ -15,6 +17,7 @@ var (
|
||||||
_ = a[3:(len(a))]
|
_ = a[3:(len(a))]
|
||||||
_ = a[len(a) : len(a)-1]
|
_ = a[len(a) : len(a)-1]
|
||||||
_ = a[0:len(b)]
|
_ = a[0:len(b)]
|
||||||
|
_ = a[2:len(a):len(a)]
|
||||||
|
|
||||||
_ = a[:]
|
_ = a[:]
|
||||||
_ = a[:10]
|
_ = a[:10]
|
||||||
|
@ -22,6 +25,7 @@ var (
|
||||||
_ = a[:(len(a))]
|
_ = a[:(len(a))]
|
||||||
_ = a[:len(a)-1]
|
_ = a[:len(a)-1]
|
||||||
_ = a[:len(b)]
|
_ = a[:len(b)]
|
||||||
|
_ = a[:len(a):len(a)]
|
||||||
|
|
||||||
_ = s[0:]
|
_ = s[0:]
|
||||||
_ = s[1:10]
|
_ = s[1:10]
|
||||||
|
@ -29,6 +33,7 @@ var (
|
||||||
_ = s[3:(len(s))]
|
_ = s[3:(len(s))]
|
||||||
_ = s[len(a) : len(s)-1]
|
_ = s[len(a) : len(s)-1]
|
||||||
_ = s[0:len(b)]
|
_ = s[0:len(b)]
|
||||||
|
_ = s[2:len(s):len(s)]
|
||||||
|
|
||||||
_ = s[:]
|
_ = s[:]
|
||||||
_ = s[:10]
|
_ = s[:10]
|
||||||
|
@ -36,6 +41,7 @@ var (
|
||||||
_ = s[:(len(s))]
|
_ = s[:(len(s))]
|
||||||
_ = s[:len(s)-1]
|
_ = s[:len(s)-1]
|
||||||
_ = s[:len(b)]
|
_ = s[:len(b)]
|
||||||
|
_ = s[:len(s):len(s)]
|
||||||
|
|
||||||
_ = t.s[0:]
|
_ = t.s[0:]
|
||||||
_ = t.s[1:10]
|
_ = t.s[1:10]
|
||||||
|
@ -43,6 +49,7 @@ var (
|
||||||
_ = t.s[3:(len(t.s))]
|
_ = t.s[3:(len(t.s))]
|
||||||
_ = t.s[len(a) : len(t.s)-1]
|
_ = t.s[len(a) : len(t.s)-1]
|
||||||
_ = t.s[0:len(b)]
|
_ = t.s[0:len(b)]
|
||||||
|
_ = t.s[2:len(t.s):len(t.s)]
|
||||||
|
|
||||||
_ = t.s[:]
|
_ = t.s[:]
|
||||||
_ = t.s[:10]
|
_ = t.s[:10]
|
||||||
|
@ -50,6 +57,7 @@ var (
|
||||||
_ = t.s[:(len(t.s))]
|
_ = t.s[:(len(t.s))]
|
||||||
_ = t.s[:len(t.s)-1]
|
_ = t.s[:len(t.s)-1]
|
||||||
_ = t.s[:len(b)]
|
_ = t.s[:len(b)]
|
||||||
|
_ = t.s[:len(t.s):len(t.s)]
|
||||||
)
|
)
|
||||||
|
|
||||||
func _() {
|
func _() {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -s
|
||||||
|
|
||||||
// Test cases for slice expression simplification.
|
// Test cases for slice expression simplification.
|
||||||
package p
|
package p
|
||||||
|
|
||||||
|
@ -15,6 +17,7 @@ var (
|
||||||
_ = a[3:(len(a))]
|
_ = a[3:(len(a))]
|
||||||
_ = a[len(a) : len(a)-1]
|
_ = a[len(a) : len(a)-1]
|
||||||
_ = a[0:len(b)]
|
_ = a[0:len(b)]
|
||||||
|
_ = a[2:len(a):len(a)]
|
||||||
|
|
||||||
_ = a[:]
|
_ = a[:]
|
||||||
_ = a[:10]
|
_ = a[:10]
|
||||||
|
@ -22,6 +25,7 @@ var (
|
||||||
_ = a[:(len(a))]
|
_ = a[:(len(a))]
|
||||||
_ = a[:len(a)-1]
|
_ = a[:len(a)-1]
|
||||||
_ = a[:len(b)]
|
_ = a[:len(b)]
|
||||||
|
_ = a[:len(a):len(a)]
|
||||||
|
|
||||||
_ = s[0:]
|
_ = s[0:]
|
||||||
_ = s[1:10]
|
_ = s[1:10]
|
||||||
|
@ -29,6 +33,7 @@ var (
|
||||||
_ = s[3:(len(s))]
|
_ = s[3:(len(s))]
|
||||||
_ = s[len(a) : len(s)-1]
|
_ = s[len(a) : len(s)-1]
|
||||||
_ = s[0:len(b)]
|
_ = s[0:len(b)]
|
||||||
|
_ = s[2:len(s):len(s)]
|
||||||
|
|
||||||
_ = s[:]
|
_ = s[:]
|
||||||
_ = s[:10]
|
_ = s[:10]
|
||||||
|
@ -36,6 +41,7 @@ var (
|
||||||
_ = s[:(len(s))]
|
_ = s[:(len(s))]
|
||||||
_ = s[:len(s)-1]
|
_ = s[:len(s)-1]
|
||||||
_ = s[:len(b)]
|
_ = s[:len(b)]
|
||||||
|
_ = s[:len(s):len(s)]
|
||||||
|
|
||||||
_ = t.s[0:]
|
_ = t.s[0:]
|
||||||
_ = t.s[1:10]
|
_ = t.s[1:10]
|
||||||
|
@ -43,6 +49,7 @@ var (
|
||||||
_ = t.s[3:(len(t.s))]
|
_ = t.s[3:(len(t.s))]
|
||||||
_ = t.s[len(a) : len(t.s)-1]
|
_ = t.s[len(a) : len(t.s)-1]
|
||||||
_ = t.s[0:len(b)]
|
_ = t.s[0:len(b)]
|
||||||
|
_ = t.s[2:len(t.s):len(t.s)]
|
||||||
|
|
||||||
_ = t.s[:]
|
_ = t.s[:]
|
||||||
_ = t.s[:10]
|
_ = t.s[:10]
|
||||||
|
@ -50,6 +57,7 @@ var (
|
||||||
_ = t.s[:(len(t.s))]
|
_ = t.s[:(len(t.s))]
|
||||||
_ = t.s[:len(t.s)-1]
|
_ = t.s[:len(t.s)-1]
|
||||||
_ = t.s[:len(b)]
|
_ = t.s[:len(b)]
|
||||||
|
_ = t.s[:len(t.s):len(t.s)]
|
||||||
)
|
)
|
||||||
|
|
||||||
func _() {
|
func _() {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//gofmt -s
|
||||||
|
|
||||||
// Test cases for slice expression simplification.
|
// Test cases for slice expression simplification.
|
||||||
// Because of a dot import, these slices must remain untouched.
|
// Because of a dot import, these slices must remain untouched.
|
||||||
package p
|
package p
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue