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/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/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/go11.go
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/help.go
|
||||
|
|
|
@ -1600,6 +1600,7 @@ const (
|
|||
gccgoRuntimeTypeKindSTRING = 24
|
||||
gccgoRuntimeTypeKindSTRUCT = 25
|
||||
gccgoRuntimeTypeKindUNSAFE_POINTER = 26
|
||||
gccgoRuntimeTypeKindDIRECT_IFACE = (1 << 5)
|
||||
gccgoRuntimeTypeKindNO_POINTERS = (1 << 7)
|
||||
)
|
||||
|
||||
|
@ -1669,7 +1670,7 @@ func runtimeTypeKind(t types.Type) (k uint8) {
|
|||
case types.String:
|
||||
k = gccgoRuntimeTypeKindSTRING
|
||||
case types.UnsafePointer:
|
||||
k = gccgoRuntimeTypeKindUNSAFE_POINTER
|
||||
k = gccgoRuntimeTypeKindUNSAFE_POINTER | gccgoRuntimeTypeKindDIRECT_IFACE
|
||||
default:
|
||||
panic("unrecognized builtin type")
|
||||
}
|
||||
|
@ -1680,7 +1681,7 @@ func runtimeTypeKind(t types.Type) (k uint8) {
|
|||
case *types.Struct:
|
||||
k = gccgoRuntimeTypeKindSTRUCT
|
||||
case *types.Pointer:
|
||||
k = gccgoRuntimeTypeKindPTR
|
||||
k = gccgoRuntimeTypeKindPTR | gccgoRuntimeTypeKindDIRECT_IFACE
|
||||
case *types.Signature:
|
||||
k = gccgoRuntimeTypeKindFUNC
|
||||
case *types.Interface:
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
package irgen
|
||||
|
||||
const (
|
||||
goVersion = "go1.3"
|
||||
goVersion = "go1.4"
|
||||
)
|
||||
|
||||
// GoVersion returns the version of Go that we are targeting.
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
|
||||
index 526b656..31c206e 100644
|
||||
--- a/libgo/Makefile.am
|
||||
+++ b/libgo/Makefile.am
|
||||
@@ -3688,7 +3688,6 @@ TEST_PACKAGES = \
|
||||
diff -r a6e10414311a libgo/Makefile.am
|
||||
--- a/libgo/Makefile.am Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/Makefile.am Fri Apr 03 15:07:47 2015 -0700
|
||||
@@ -3738,7 +3738,6 @@
|
||||
os/check \
|
||||
path/check \
|
||||
reflect/check \
|
||||
|
@ -10,7 +9,7 @@ index 526b656..31c206e 100644
|
|||
runtime/check \
|
||||
sort/check \
|
||||
strconv/check \
|
||||
@@ -3787,7 +3786,6 @@ TEST_PACKAGES = \
|
||||
@@ -3838,7 +3837,6 @@
|
||||
os/user/check \
|
||||
path/filepath/check \
|
||||
regexp/syntax/check \
|
||||
|
@ -18,11 +17,10 @@ index 526b656..31c206e 100644
|
|||
sync/atomic/check \
|
||||
text/scanner/check \
|
||||
text/tabwriter/check \
|
||||
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
|
||||
index 2254478..d2482d1 100644
|
||||
--- a/libgo/Makefile.in
|
||||
+++ b/libgo/Makefile.in
|
||||
@@ -2193,7 +2193,6 @@ TEST_PACKAGES = \
|
||||
diff -r a6e10414311a libgo/Makefile.in
|
||||
--- a/libgo/Makefile.in Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/Makefile.in Fri Apr 03 15:07:47 2015 -0700
|
||||
@@ -2212,7 +2212,6 @@
|
||||
os/check \
|
||||
path/check \
|
||||
reflect/check \
|
||||
|
@ -30,7 +28,7 @@ index 2254478..d2482d1 100644
|
|||
runtime/check \
|
||||
sort/check \
|
||||
strconv/check \
|
||||
@@ -2292,7 +2291,6 @@ TEST_PACKAGES = \
|
||||
@@ -2312,7 +2311,6 @@
|
||||
os/user/check \
|
||||
path/filepath/check \
|
||||
regexp/syntax/check \
|
||||
|
@ -38,3 +36,26 @@ index 2254478..d2482d1 100644
|
|||
sync/atomic/check \
|
||||
text/scanner/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
|
||||
--- a/libgo/runtime/chan.goc Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/chan.goc Fri Feb 13 12:12:23 2015 -0800
|
||||
diff -r a6e10414311a libgo/runtime/chan.goc
|
||||
--- a/libgo/runtime/chan.goc Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/chan.goc Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -111,7 +111,7 @@
|
||||
mysg.releasetime = -1;
|
||||
}
|
||||
|
@ -207,9 +207,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/chan.goc
|
|||
}
|
||||
|
||||
void
|
||||
diff -r 0fde0b6a7eb2 libgo/runtime/chan.h
|
||||
--- a/libgo/runtime/chan.h Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/chan.h Fri Feb 13 12:12:23 2015 -0800
|
||||
diff -r a6e10414311a libgo/runtime/chan.h
|
||||
--- a/libgo/runtime/chan.h Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/chan.h Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -39,7 +39,7 @@
|
||||
uintgo recvx; // receive index
|
||||
WaitQ recvq; // list of recv waiters
|
||||
|
@ -219,9 +219,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/chan.h
|
|||
};
|
||||
|
||||
// Buffer follows Hchan immediately in memory.
|
||||
diff -r 0fde0b6a7eb2 libgo/runtime/heapdump.c
|
||||
--- a/libgo/runtime/heapdump.c Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/heapdump.c Fri Feb 13 12:12:23 2015 -0800
|
||||
diff -r a6e10414311a libgo/runtime/heapdump.c
|
||||
--- a/libgo/runtime/heapdump.c Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/heapdump.c Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -387,7 +387,7 @@
|
||||
if(sp->kind != KindSpecialFinalizer)
|
||||
continue;
|
||||
|
@ -240,10 +240,10 @@ diff -r 0fde0b6a7eb2 libgo/runtime/heapdump.c
|
|||
dumpint(TagAllocSample);
|
||||
dumpint((uintptr)p);
|
||||
dumpint((uintptr)spp->b);
|
||||
diff -r 0fde0b6a7eb2 libgo/runtime/malloc.goc
|
||||
--- a/libgo/runtime/malloc.goc Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/malloc.goc Fri Feb 13 12:12:23 2015 -0800
|
||||
@@ -436,9 +436,9 @@
|
||||
diff -r a6e10414311a libgo/runtime/malloc.goc
|
||||
--- a/libgo/runtime/malloc.goc Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/malloc.goc Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -437,9 +437,9 @@
|
||||
m->mcache->local_nlookup++;
|
||||
if (sizeof(void*) == 4 && m->mcache->local_nlookup >= (1<<30)) {
|
||||
// purge cache stats to prevent overflow
|
||||
|
@ -255,7 +255,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/malloc.goc
|
|||
}
|
||||
|
||||
s = runtime_MHeap_LookupMaybe(&runtime_mheap, v);
|
||||
@@ -735,7 +735,7 @@
|
||||
@@ -736,7 +736,7 @@
|
||||
|
||||
static struct
|
||||
{
|
||||
|
@ -264,7 +264,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/malloc.goc
|
|||
byte* pos;
|
||||
byte* end;
|
||||
} persistent;
|
||||
@@ -764,19 +764,19 @@
|
||||
@@ -765,19 +765,19 @@
|
||||
align = 8;
|
||||
if(size >= PersistentAllocMaxBlock)
|
||||
return runtime_SysAlloc(size, stat);
|
||||
|
@ -287,9 +287,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/malloc.goc
|
|||
if(stat != &mstats.other_sys) {
|
||||
// reaccount the allocation against provided stat
|
||||
runtime_xadd64(stat, size);
|
||||
diff -r 0fde0b6a7eb2 libgo/runtime/malloc.h
|
||||
--- a/libgo/runtime/malloc.h Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/malloc.h Fri Feb 13 12:12:23 2015 -0800
|
||||
diff -r a6e10414311a libgo/runtime/malloc.h
|
||||
--- a/libgo/runtime/malloc.h Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/malloc.h Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -390,7 +390,7 @@
|
||||
typedef struct SpecialFinalizer SpecialFinalizer;
|
||||
struct SpecialFinalizer
|
||||
|
@ -335,9 +335,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/malloc.h
|
|||
byte pad[64];
|
||||
} central[NumSizeClasses];
|
||||
|
||||
diff -r 0fde0b6a7eb2 libgo/runtime/mcache.c
|
||||
--- a/libgo/runtime/mcache.c Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/mcache.c Fri Feb 13 12:12:23 2015 -0800
|
||||
diff -r a6e10414311a libgo/runtime/mcache.c
|
||||
--- a/libgo/runtime/mcache.c Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/mcache.c Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -23,9 +23,9 @@
|
||||
MCache *c;
|
||||
int32 i;
|
||||
|
@ -410,9 +410,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mcache.c
|
|||
l->list = nil;
|
||||
l->nlist = 0;
|
||||
}
|
||||
diff -r 0fde0b6a7eb2 libgo/runtime/mcentral.c
|
||||
--- a/libgo/runtime/mcentral.c Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/mcentral.c Fri Feb 13 12:12:23 2015 -0800
|
||||
diff -r a6e10414311a libgo/runtime/mcentral.c
|
||||
--- a/libgo/runtime/mcentral.c Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/mcentral.c Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -39,14 +39,14 @@
|
||||
int32 cap, n;
|
||||
uint32 sg;
|
||||
|
@ -554,10 +554,10 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mcentral.c
|
|||
runtime_unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
|
||||
runtime_MHeap_Free(&runtime_mheap, s, 0);
|
||||
}
|
||||
diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
||||
--- a/libgo/runtime/mgc0.c Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/mgc0.c Fri Feb 13 12:12:23 2015 -0800
|
||||
@@ -224,7 +224,7 @@
|
||||
diff -r a6e10414311a libgo/runtime/mgc0.c
|
||||
--- a/libgo/runtime/mgc0.c Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/mgc0.c Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -225,7 +225,7 @@
|
||||
Note alldone;
|
||||
ParFor *markfor;
|
||||
|
||||
|
@ -566,7 +566,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
|||
byte *chunk;
|
||||
uintptr nchunk;
|
||||
} work __attribute__((aligned(8)));
|
||||
@@ -1336,7 +1336,7 @@
|
||||
@@ -1337,7 +1337,7 @@
|
||||
// retain everything it points to.
|
||||
spf = (SpecialFinalizer*)sp;
|
||||
// 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){(void*)&spf->fn, PtrSize, 0});
|
||||
enqueue1(&wbuf, (Obj){(void*)&spf->ft, PtrSize, 0});
|
||||
@@ -1377,7 +1377,7 @@
|
||||
@@ -1378,7 +1378,7 @@
|
||||
b = (Workbuf*)runtime_lfstackpop(&work.empty);
|
||||
if(b == nil) {
|
||||
// Need to allocate.
|
||||
|
@ -584,7 +584,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
|||
if(work.nchunk < sizeof *b) {
|
||||
work.nchunk = 1<<20;
|
||||
work.chunk = runtime_SysAlloc(work.nchunk, &mstats.gc_sys);
|
||||
@@ -1387,7 +1387,7 @@
|
||||
@@ -1388,7 +1388,7 @@
|
||||
b = (Workbuf*)work.chunk;
|
||||
work.chunk += sizeof *b;
|
||||
work.nchunk -= sizeof *b;
|
||||
|
@ -593,7 +593,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
|||
}
|
||||
b->nobj = 0;
|
||||
return b;
|
||||
@@ -1801,7 +1801,7 @@
|
||||
@@ -1802,7 +1802,7 @@
|
||||
c->local_nsmallfree[cl] += nfree;
|
||||
c->local_cachealloc -= nfree * size;
|
||||
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
|
||||
}
|
||||
return res;
|
||||
@@ -2146,10 +2146,10 @@
|
||||
@@ -2147,10 +2147,10 @@
|
||||
return;
|
||||
|
||||
if(gcpercent == GcpercentUnknown) { // first time through
|
||||
|
@ -615,7 +615,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
|||
}
|
||||
if(gcpercent < 0)
|
||||
return;
|
||||
@@ -2420,7 +2420,7 @@
|
||||
@@ -2423,7 +2423,7 @@
|
||||
|
||||
// Pass back: pauses, last gc (absolute time), number of gc, total pause ns.
|
||||
p = (uint64*)pauses->array;
|
||||
|
@ -624,7 +624,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
|||
n = mstats.numgc;
|
||||
if(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+1] = mstats.numgc;
|
||||
p[n+2] = mstats.pause_total_ns;
|
||||
|
@ -633,7 +633,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
|||
pauses->__count = n+3;
|
||||
}
|
||||
|
||||
@@ -2443,14 +2443,14 @@
|
||||
@@ -2446,14 +2446,14 @@
|
||||
runtime_setgcpercent(int32 in) {
|
||||
int32 out;
|
||||
|
||||
|
@ -650,9 +650,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mgc0.c
|
|||
return out;
|
||||
}
|
||||
|
||||
diff -r 0fde0b6a7eb2 libgo/runtime/mheap.c
|
||||
--- a/libgo/runtime/mheap.c Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/mheap.c Fri Feb 13 12:12:23 2015 -0800
|
||||
diff -r a6e10414311a libgo/runtime/mheap.c
|
||||
--- a/libgo/runtime/mheap.c Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/mheap.c Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -70,7 +70,7 @@
|
||||
runtime_MSpanList_Init(&h->freelarge);
|
||||
runtime_MSpanList_Init(&h->busylarge);
|
||||
|
@ -837,9 +837,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/mheap.c
|
|||
+ runtime_unlock(&h->lock);
|
||||
}
|
||||
}
|
||||
diff -r 0fde0b6a7eb2 libgo/runtime/netpoll.goc
|
||||
--- a/libgo/runtime/netpoll.goc Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/netpoll.goc Fri Feb 13 12:12:23 2015 -0800
|
||||
diff -r a6e10414311a libgo/runtime/netpoll.goc
|
||||
--- a/libgo/runtime/netpoll.goc Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/netpoll.goc Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -53,7 +53,7 @@
|
||||
// pollReset, pollWait, pollWaitCanceled and runtime_netpollready (IO rediness notification)
|
||||
// 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;
|
||||
}
|
||||
pd->seq++; // invalidate current timers
|
||||
@@ -223,7 +223,7 @@
|
||||
@@ -226,7 +226,7 @@
|
||||
rg = netpollunblock(pd, 'r', false);
|
||||
if(pd->wd < 0)
|
||||
wg = netpollunblock(pd, 'w', false);
|
||||
|
@ -910,7 +910,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/netpoll.goc
|
|||
if(rg)
|
||||
runtime_ready(rg);
|
||||
if(wg)
|
||||
@@ -233,7 +233,7 @@
|
||||
@@ -236,7 +236,7 @@
|
||||
func runtime_pollUnblock(pd *PollDesc) {
|
||||
G *rg, *wg;
|
||||
|
||||
|
@ -919,7 +919,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/netpoll.goc
|
|||
if(pd->closing)
|
||||
runtime_throw("runtime_pollUnblock: already closing");
|
||||
pd->closing = true;
|
||||
@@ -249,7 +249,7 @@
|
||||
@@ -252,7 +252,7 @@
|
||||
runtime_deltimer(&pd->wt);
|
||||
pd->wt.fv = nil;
|
||||
}
|
||||
|
@ -928,7 +928,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/netpoll.goc
|
|||
if(rg)
|
||||
runtime_ready(rg);
|
||||
if(wg)
|
||||
@@ -277,13 +277,13 @@
|
||||
@@ -280,13 +280,13 @@
|
||||
void
|
||||
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
|
||||
@@ -401,10 +401,10 @@
|
||||
// If it's stale, ignore the timer event.
|
||||
seq = (uintptr)arg.type;
|
||||
@@ -399,12 +399,12 @@
|
||||
|
||||
pd = (PollDesc*)arg.data;
|
||||
rg = wg = nil;
|
||||
- runtime_lock(pd);
|
||||
+ 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) {
|
||||
// The descriptor was reused or timers were reset.
|
||||
- runtime_unlock(pd);
|
||||
|
@ -983,9 +985,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/netpoll.goc
|
|||
+ runtime_unlock(&pollcache.lock);
|
||||
return pd;
|
||||
}
|
||||
diff -r 0fde0b6a7eb2 libgo/runtime/proc.c
|
||||
--- a/libgo/runtime/proc.c Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/proc.c Fri Feb 13 12:12:23 2015 -0800
|
||||
diff -r a6e10414311a libgo/runtime/proc.c
|
||||
--- a/libgo/runtime/proc.c Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/proc.c Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -302,7 +302,7 @@
|
||||
|
||||
typedef struct Sched Sched;
|
||||
|
@ -1500,9 +1502,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/proc.c
|
|||
return out;
|
||||
}
|
||||
|
||||
diff -r 0fde0b6a7eb2 libgo/runtime/runtime.h
|
||||
--- a/libgo/runtime/runtime.h Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/runtime.h Fri Feb 13 12:12:23 2015 -0800
|
||||
diff -r a6e10414311a libgo/runtime/runtime.h
|
||||
--- a/libgo/runtime/runtime.h Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/runtime.h Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -286,7 +286,7 @@
|
||||
|
||||
struct P
|
||||
|
@ -1521,9 +1523,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/runtime.h
|
|||
G *timerproc;
|
||||
bool sleeping;
|
||||
bool rescheduling;
|
||||
diff -r 0fde0b6a7eb2 libgo/runtime/sema.goc
|
||||
--- a/libgo/runtime/sema.goc Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/sema.goc Fri Feb 13 12:12:23 2015 -0800
|
||||
diff -r a6e10414311a libgo/runtime/sema.goc
|
||||
--- a/libgo/runtime/sema.goc Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/sema.goc Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -35,7 +35,7 @@
|
||||
typedef struct SemaRoot SemaRoot;
|
||||
struct SemaRoot
|
||||
|
@ -1652,9 +1654,9 @@ diff -r 0fde0b6a7eb2 libgo/runtime/sema.goc
|
|||
- runtime_unlock(s);
|
||||
+ runtime_unlock(&s->lock);
|
||||
}
|
||||
diff -r 0fde0b6a7eb2 libgo/runtime/sigqueue.goc
|
||||
--- a/libgo/runtime/sigqueue.goc Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/sigqueue.goc Fri Feb 13 12:12:23 2015 -0800
|
||||
diff -r a6e10414311a libgo/runtime/sigqueue.goc
|
||||
--- a/libgo/runtime/sigqueue.goc Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/sigqueue.goc Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "defs.h"
|
||||
|
||||
|
@ -1693,13 +1695,13 @@ diff -r 0fde0b6a7eb2 libgo/runtime/sigqueue.goc
|
|||
return;
|
||||
}
|
||||
|
||||
diff -r 0fde0b6a7eb2 libgo/runtime/time.goc
|
||||
--- a/libgo/runtime/time.goc Fri Jan 09 17:00:26 2015 -0800
|
||||
+++ b/libgo/runtime/time.goc Fri Feb 13 12:12:23 2015 -0800
|
||||
@@ -91,17 +91,17 @@
|
||||
t.period = 0;
|
||||
diff -r a6e10414311a libgo/runtime/time.goc
|
||||
--- a/libgo/runtime/time.goc Fri Jan 16 07:57:02 2015 -0800
|
||||
+++ b/libgo/runtime/time.goc Fri Feb 13 16:36:07 2015 -0800
|
||||
@@ -92,17 +92,17 @@
|
||||
t.fv = &readyv;
|
||||
t.arg.__object = g;
|
||||
t.seq = 0;
|
||||
- runtime_lock(&timers);
|
||||
+ runtime_lock(&timers.lock);
|
||||
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
|
||||
@@ -166,14 +166,14 @@
|
||||
@@ -167,14 +167,14 @@
|
||||
i = t->i;
|
||||
gi = i;
|
||||
|
||||
|
@ -1735,7 +1737,7 @@ diff -r 0fde0b6a7eb2 libgo/runtime/time.goc
|
|||
return false;
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
@@ -190,7 +190,7 @@
|
||||
}
|
||||
if(debug)
|
||||
dumptimers("deltimer");
|
||||
|
@ -1744,8 +1746,8 @@ diff -r 0fde0b6a7eb2 libgo/runtime/time.goc
|
|||
return true;
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
Eface arg;
|
||||
@@ -209,7 +209,7 @@
|
||||
uintptr seq;
|
||||
|
||||
for(;;) {
|
||||
- runtime_lock(&timers);
|
||||
|
@ -1753,16 +1755,16 @@ diff -r 0fde0b6a7eb2 libgo/runtime/time.goc
|
|||
timers.sleeping = false;
|
||||
now = runtime_nanotime();
|
||||
for(;;) {
|
||||
@@ -233,7 +233,7 @@
|
||||
fv = t->fv;
|
||||
@@ -236,7 +236,7 @@
|
||||
f = (void*)t->fv->fn;
|
||||
arg = t->arg;
|
||||
seq = t->seq;
|
||||
- runtime_unlock(&timers);
|
||||
+ runtime_unlock(&timers.lock);
|
||||
__go_set_closure(fv);
|
||||
f(now, arg);
|
||||
f(arg, seq);
|
||||
|
||||
@@ -244,20 +244,20 @@
|
||||
@@ -247,20 +247,20 @@
|
||||
arg.__object = nil;
|
||||
USED(&arg);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
f44017549ff9
|
||||
14854533dcc7
|
||||
|
||||
The first line of this file holds the Mercurial revision number of the
|
||||
last merge done from the master library sources.
|
||||
|
|
|
@ -495,6 +495,7 @@ runtime_files = \
|
|||
runtime/go-unsafe-new.c \
|
||||
runtime/go-unsafe-newarray.c \
|
||||
runtime/go-unsafe-pointer.c \
|
||||
runtime/go-unsetenv.c \
|
||||
runtime/go-unwind.c \
|
||||
runtime/go-varargs.c \
|
||||
runtime/env_posix.c \
|
||||
|
@ -695,7 +696,7 @@ go_net_sockoptip_file = go/net/sockoptip_linux.go go/net/sockoptip_posix.go
|
|||
else
|
||||
if LIBGO_IS_SOLARIS
|
||||
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_sockoptip_file = go/net/sockoptip_stub.go
|
||||
else
|
||||
|
@ -997,7 +998,6 @@ go_runtime_files = \
|
|||
go/runtime/extern.go \
|
||||
go/runtime/mem.go \
|
||||
go/runtime/softfloat64.go \
|
||||
go/runtime/type.go \
|
||||
version.go
|
||||
|
||||
version.go: s-version; @true
|
||||
|
@ -1187,10 +1187,19 @@ go_crypto_md5_files = \
|
|||
go/crypto/md5/md5.go \
|
||||
go/crypto/md5/md5block.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/rand.go \
|
||||
go/crypto/rand/rand_unix.go \
|
||||
$(crypto_rand_file) \
|
||||
go/crypto/rand/util.go
|
||||
|
||||
go_crypto_rc4_files = \
|
||||
go/crypto/rc4/rc4.go \
|
||||
go/crypto/rc4/rc4_ref.go
|
||||
|
@ -1289,9 +1298,11 @@ go_encoding_csv_files = \
|
|||
go_encoding_gob_files = \
|
||||
go/encoding/gob/decode.go \
|
||||
go/encoding/gob/decoder.go \
|
||||
go/encoding/gob/dec_helpers.go \
|
||||
go/encoding/gob/doc.go \
|
||||
go/encoding/gob/encode.go \
|
||||
go/encoding/gob/encoder.go \
|
||||
go/encoding/gob/enc_helpers.go \
|
||||
go/encoding/gob/error.go \
|
||||
go/encoding/gob/type.go
|
||||
go_encoding_hex_files = \
|
||||
|
@ -1452,7 +1463,6 @@ go_mime_multipart_files = \
|
|||
go/mime/multipart/writer.go
|
||||
|
||||
go_net_http_files = \
|
||||
go/net/http/chunked.go \
|
||||
go/net/http/client.go \
|
||||
go/net/http/cookie.go \
|
||||
go/net/http/filetransport.go \
|
||||
|
@ -1496,12 +1506,12 @@ go_net_http_httptest_files = \
|
|||
go_net_http_pprof_files = \
|
||||
go/net/http/pprof/pprof.go
|
||||
go_net_http_httputil_files = \
|
||||
go/net/http/httputil/chunked.go \
|
||||
go/net/http/httputil/dump.go \
|
||||
go/net/http/httputil/httputil.go \
|
||||
go/net/http/httputil/persist.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/regexp.go
|
||||
|
@ -1535,7 +1545,8 @@ go_path_filepath_files = \
|
|||
go/path/filepath/match.go \
|
||||
go/path/filepath/path.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/compile.go \
|
||||
|
@ -1570,7 +1581,8 @@ go_text_template_parse_files = \
|
|||
go/text/template/parse/parse.go
|
||||
|
||||
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/atomic.c
|
||||
|
||||
|
@ -1784,10 +1796,21 @@ go_syscall_c_files = \
|
|||
|
||||
go_syscall_test_files = \
|
||||
$(syscall_creds_test_file) \
|
||||
go/syscall/export_test.go \
|
||||
go/syscall/mmap_unix_test.go \
|
||||
go/syscall/syscall_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
|
||||
s-libcalls: libcalls-list go/syscall/mksyscall.awk $(go_base_syscall_files)
|
||||
rm -f libcalls.go.tmp
|
||||
|
@ -1957,6 +1980,7 @@ libgo_go_objs = \
|
|||
net/http/fcgi.lo \
|
||||
net/http/httptest.lo \
|
||||
net/http/httputil.lo \
|
||||
net/http/internal.lo \
|
||||
net/http/pprof.lo \
|
||||
image/color.lo \
|
||||
image/color/palette.lo \
|
||||
|
@ -1965,6 +1989,7 @@ libgo_go_objs = \
|
|||
image/jpeg.lo \
|
||||
image/png.lo \
|
||||
index/suffixarray.lo \
|
||||
internal/syscall.lo \
|
||||
io/ioutil.lo \
|
||||
log/syslog.lo \
|
||||
log/syslog/syslog_c.lo \
|
||||
|
@ -3160,6 +3185,15 @@ net/http/httputil/check: $(check_deps)
|
|||
@$(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
|
||||
net/http/pprof.lo.dep: $(go_net_http_pprof_files)
|
||||
$(BUILDDEPS)
|
||||
|
@ -3260,7 +3294,8 @@ runtime/pprof/check: $(CHECK_DEPS)
|
|||
.PHONY: runtime/pprof/check
|
||||
# At least for now, we need -static-libgo for this test, because
|
||||
# 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
|
||||
sync/atomic.lo.dep: $(go_sync_atomic_files)
|
||||
|
@ -3363,6 +3398,15 @@ syscall/check: $(CHECK_DEPS)
|
|||
@$(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.
|
||||
BUILDGOX = \
|
||||
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
|
||||
$(BUILDGOX)
|
||||
|
||||
net/http/internal.gox: net/http/internal.lo
|
||||
$(BUILDGOX)
|
||||
|
||||
net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
|
||||
$(BUILDGOX)
|
||||
|
||||
|
@ -3652,6 +3699,9 @@ runtime/pprof.gox: runtime/pprof.lo
|
|||
sync/atomic.gox: sync/atomic.lo
|
||||
$(BUILDGOX)
|
||||
|
||||
internal/syscall.gox: internal/syscall.lo
|
||||
$(BUILDGOX)
|
||||
|
||||
text/scanner.gox: text/scanner.lo
|
||||
$(BUILDGOX)
|
||||
text/tabwriter.gox: text/tabwriter.lo
|
||||
|
@ -3773,6 +3823,7 @@ TEST_PACKAGES = \
|
|||
net/http/fcgi/check \
|
||||
net/http/httptest/check \
|
||||
net/http/httputil/check \
|
||||
net/http/internal/check \
|
||||
net/mail/check \
|
||||
net/rpc/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 \
|
||||
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/httputil.lo net/http/pprof.lo image/color.lo \
|
||||
image/color/palette.lo image/draw.lo image/gif.lo \
|
||||
image/jpeg.lo image/png.lo index/suffixarray.lo io/ioutil.lo \
|
||||
log/syslog.lo log/syslog/syslog_c.lo math/big.lo math/cmplx.lo \
|
||||
math/rand.lo mime/multipart.lo net/http.lo net/mail.lo \
|
||||
net/rpc.lo net/smtp.lo net/textproto.lo net/url.lo \
|
||||
old/regexp.lo old/template.lo os/exec.lo $(am__DEPENDENCIES_1) \
|
||||
os/signal.lo os/user.lo path/filepath.lo regexp/syntax.lo \
|
||||
net/http/httputil.lo net/http/internal.lo net/http/pprof.lo \
|
||||
image/color.lo image/color/palette.lo image/draw.lo \
|
||||
image/gif.lo image/jpeg.lo image/png.lo index/suffixarray.lo \
|
||||
internal/syscall.lo io/ioutil.lo log/syslog.lo \
|
||||
log/syslog/syslog_c.lo math/big.lo math/cmplx.lo math/rand.lo \
|
||||
mime/multipart.lo net/http.lo net/mail.lo net/rpc.lo \
|
||||
net/smtp.lo net/textproto.lo net/url.lo old/regexp.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 \
|
||||
sync/atomic.lo sync/atomic_c.lo text/scanner.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-float.lo go-type-identity.lo go-type-interface.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-varargs.lo env_posix.lo heapdump.lo $(am__objects_1) \
|
||||
mcache.lo mcentral.lo $(am__objects_2) mfixalloc.lo mgc0.lo \
|
||||
mheap.lo msize.lo $(am__objects_3) panic.lo parfor.lo print.lo \
|
||||
proc.lo runtime.lo signal_unix.lo thread.lo yield.lo \
|
||||
$(am__objects_4) chan.lo cpuprof.lo go-iface.lo lfstack.lo \
|
||||
malloc.lo map.lo mprof.lo netpoll.lo rdebug.lo reflect.lo \
|
||||
runtime1.lo sema.lo sigqueue.lo string.lo time.lo \
|
||||
$(am__objects_5)
|
||||
go-unsafe-newarray.lo go-unsafe-pointer.lo go-unsetenv.lo \
|
||||
go-unwind.lo go-varargs.lo env_posix.lo heapdump.lo \
|
||||
$(am__objects_1) mcache.lo mcentral.lo $(am__objects_2) \
|
||||
mfixalloc.lo mgc0.lo mheap.lo msize.lo $(am__objects_3) \
|
||||
panic.lo parfor.lo print.lo proc.lo runtime.lo signal_unix.lo \
|
||||
thread.lo yield.lo $(am__objects_4) chan.lo cpuprof.lo \
|
||||
go-iface.lo lfstack.lo malloc.lo map.lo mprof.lo netpoll.lo \
|
||||
rdebug.lo reflect.lo runtime1.lo sema.lo sigqueue.lo string.lo \
|
||||
time.lo $(am__objects_5)
|
||||
am_libgo_llgo_la_OBJECTS = $(am__objects_6)
|
||||
libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS)
|
||||
libgo_llgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
|
@ -838,6 +839,7 @@ runtime_files = \
|
|||
runtime/go-unsafe-new.c \
|
||||
runtime/go-unsafe-newarray.c \
|
||||
runtime/go-unsafe-pointer.c \
|
||||
runtime/go-unsetenv.c \
|
||||
runtime/go-unwind.c \
|
||||
runtime/go-varargs.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_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_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_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
|
||||
|
@ -1180,7 +1182,6 @@ go_runtime_files = \
|
|||
go/runtime/extern.go \
|
||||
go/runtime/mem.go \
|
||||
go/runtime/softfloat64.go \
|
||||
go/runtime/type.go \
|
||||
version.go
|
||||
|
||||
go_sort_files = \
|
||||
|
@ -1348,9 +1349,12 @@ go_crypto_md5_files = \
|
|||
go/crypto/md5/md5block.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/rand.go \
|
||||
go/crypto/rand/rand_unix.go \
|
||||
$(crypto_rand_file) \
|
||||
go/crypto/rand/util.go
|
||||
|
||||
go_crypto_rc4_files = \
|
||||
|
@ -1469,9 +1473,11 @@ go_encoding_csv_files = \
|
|||
go_encoding_gob_files = \
|
||||
go/encoding/gob/decode.go \
|
||||
go/encoding/gob/decoder.go \
|
||||
go/encoding/gob/dec_helpers.go \
|
||||
go/encoding/gob/doc.go \
|
||||
go/encoding/gob/encode.go \
|
||||
go/encoding/gob/encoder.go \
|
||||
go/encoding/gob/enc_helpers.go \
|
||||
go/encoding/gob/error.go \
|
||||
go/encoding/gob/type.go
|
||||
|
||||
|
@ -1649,7 +1655,6 @@ go_mime_multipart_files = \
|
|||
go/mime/multipart/writer.go
|
||||
|
||||
go_net_http_files = \
|
||||
go/net/http/chunked.go \
|
||||
go/net/http/client.go \
|
||||
go/net/http/cookie.go \
|
||||
go/net/http/filetransport.go \
|
||||
|
@ -1702,12 +1707,14 @@ go_net_http_pprof_files = \
|
|||
go/net/http/pprof/pprof.go
|
||||
|
||||
go_net_http_httputil_files = \
|
||||
go/net/http/httputil/chunked.go \
|
||||
go/net/http/httputil/dump.go \
|
||||
go/net/http/httputil/httputil.go \
|
||||
go/net/http/httputil/persist.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/regexp.go
|
||||
|
||||
|
@ -1737,7 +1744,8 @@ go_path_filepath_files = \
|
|||
go/path/filepath/match.go \
|
||||
go/path/filepath/path.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/compile.go \
|
||||
|
@ -1775,7 +1783,8 @@ go_text_template_parse_files = \
|
|||
go/text/template/parse/parse.go
|
||||
|
||||
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/atomic.c
|
||||
|
@ -1918,10 +1927,17 @@ go_syscall_c_files = \
|
|||
|
||||
go_syscall_test_files = \
|
||||
$(syscall_creds_test_file) \
|
||||
go/syscall/export_test.go \
|
||||
go/syscall/mmap_unix_test.go \
|
||||
go/syscall/syscall_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 =
|
||||
|
||||
# os_lib_inotify_lo = os/inotify.lo
|
||||
|
@ -2030,6 +2046,7 @@ libgo_go_objs = \
|
|||
net/http/fcgi.lo \
|
||||
net/http/httptest.lo \
|
||||
net/http/httputil.lo \
|
||||
net/http/internal.lo \
|
||||
net/http/pprof.lo \
|
||||
image/color.lo \
|
||||
image/color/palette.lo \
|
||||
|
@ -2038,6 +2055,7 @@ libgo_go_objs = \
|
|||
image/jpeg.lo \
|
||||
image/png.lo \
|
||||
index/suffixarray.lo \
|
||||
internal/syscall.lo \
|
||||
io/ioutil.lo \
|
||||
log/syslog.lo \
|
||||
log/syslog/syslog_c.lo \
|
||||
|
@ -2169,7 +2187,8 @@ CHECK_DEPS = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
|
|||
$(toolexeclibgounicode_DATA) $(am__append_1) $(am__append_2)
|
||||
# At least for now, we need -static-libgo for this test, because
|
||||
# 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.
|
||||
BUILDGOX = \
|
||||
|
@ -2278,6 +2297,7 @@ TEST_PACKAGES = \
|
|||
net/http/fcgi/check \
|
||||
net/http/httptest/check \
|
||||
net/http/httputil/check \
|
||||
net/http/internal/check \
|
||||
net/mail/check \
|
||||
net/rpc/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-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-unsetenv.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)/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@
|
||||
@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
|
||||
@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
|
||||
|
@ -5496,6 +5524,15 @@ net/http/httputil/check: $(check_deps)
|
|||
@$(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
|
||||
net/http/pprof.lo.dep: $(go_net_http_pprof_files)
|
||||
$(BUILDDEPS)
|
||||
|
@ -5696,6 +5733,15 @@ syscall/check: $(CHECK_DEPS)
|
|||
@$(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
|
||||
$(BUILDGOX)
|
||||
bytes.gox: bytes.lo
|
||||
|
@ -5951,6 +5997,9 @@ net/http/httputil.gox: net/http/httputil.lo
|
|||
net/http/pprof.gox: net/http/pprof.lo
|
||||
$(BUILDGOX)
|
||||
|
||||
net/http/internal.gox: net/http/internal.lo
|
||||
$(BUILDGOX)
|
||||
|
||||
net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
|
||||
$(BUILDGOX)
|
||||
|
||||
|
@ -5980,6 +6029,9 @@ runtime/pprof.gox: runtime/pprof.lo
|
|||
sync/atomic.gox: sync/atomic.lo
|
||||
$(BUILDGOX)
|
||||
|
||||
internal/syscall.gox: internal/syscall.lo
|
||||
$(BUILDGOX)
|
||||
|
||||
text/scanner.gox: text/scanner.lo
|
||||
$(BUILDGOX)
|
||||
text/tabwriter.gox: text/tabwriter.lo
|
||||
|
|
|
@ -319,6 +319,9 @@
|
|||
/* Define to 1 if you have the `unlinkat' function. */
|
||||
#undef HAVE_UNLINKAT
|
||||
|
||||
/* Define to 1 if you have the `unsetenv' function. */
|
||||
#undef HAVE_UNSETENV
|
||||
|
||||
/* Define to 1 if you have the `unshare' function. */
|
||||
#undef HAVE_UNSHARE
|
||||
|
||||
|
|
|
@ -2511,7 +2511,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
|||
ac_config_headers="$ac_config_headers config.h"
|
||||
|
||||
|
||||
libtool_VERSION=6:0:0
|
||||
libtool_VERSION=7:0:0
|
||||
|
||||
|
||||
# Default to --enable-multilib
|
||||
|
@ -14805,7 +14805,7 @@ else
|
|||
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 :
|
||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
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_HEADER(config.h)
|
||||
|
||||
libtool_VERSION=6:0:0
|
||||
libtool_VERSION=7:0:0
|
||||
AC_SUBST(libtool_VERSION)
|
||||
|
||||
AM_ENABLE_MULTILIB(, ..)
|
||||
|
@ -551,7 +551,7 @@ fi
|
|||
|
||||
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_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),
|
||||
// and then it can be treated as an io.Reader to access the file's data.
|
||||
type Reader struct {
|
||||
r io.Reader
|
||||
err error
|
||||
pad int64 // amount of padding (ignored) after current file entry
|
||||
curr numBytesReader // reader for current file entry
|
||||
r io.Reader
|
||||
err error
|
||||
pad int64 // amount of padding (ignored) after 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
|
||||
|
@ -426,7 +427,9 @@ func (tr *Reader) verifyChecksum(header []byte) bool {
|
|||
}
|
||||
|
||||
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 {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -37,8 +37,10 @@ type Writer struct {
|
|||
nb int64 // number of unwritten bytes for current file entry
|
||||
pad int64 // amount of padding to write after current file entry
|
||||
closed bool
|
||||
usedBinary bool // whether the binary numeric field extension was used
|
||||
preferPax bool // use pax header instead of binary numeric header
|
||||
usedBinary bool // whether the binary numeric field extension was used
|
||||
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.
|
||||
|
@ -160,7 +162,18 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
|
|||
// subsecond time resolution, but for now let's just capture
|
||||
// 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)
|
||||
|
||||
// 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")
|
||||
}
|
||||
}
|
||||
|
||||
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:]
|
||||
}
|
||||
// Should have consumed the whole header.
|
||||
if len(b) != 0 {
|
||||
return ErrFormat
|
||||
// But popular zip & JAR creation tools are broken and
|
||||
// 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
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
@ -508,3 +509,25 @@ func returnRecursiveZip() (r io.ReaderAt, size int64) {
|
|||
b := rZipBytes()
|
||||
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)}}
|
||||
}
|
||||
|
||||
// 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.
|
||||
// It does not (and can not) close the underlying writer.
|
||||
func (w *Writer) Close() error {
|
||||
|
|
|
@ -6,6 +6,7 @@ package zip
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"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) {
|
||||
header := &FileHeader{
|
||||
Name: wt.Name,
|
||||
|
|
|
@ -30,8 +30,8 @@ var (
|
|||
// Reader implements buffering for an io.Reader object.
|
||||
type Reader struct {
|
||||
buf []byte
|
||||
rd io.Reader
|
||||
r, w int
|
||||
rd io.Reader // reader provided by the client
|
||||
r, w int // buf read and write positions
|
||||
err error
|
||||
lastByte int
|
||||
lastRuneSize int
|
||||
|
@ -131,18 +131,17 @@ func (b *Reader) Peek(n int) ([]byte, error) {
|
|||
for b.w-b.r < n && b.err == nil {
|
||||
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
|
||||
if m < n {
|
||||
if avail := b.w - b.r; avail < n {
|
||||
// not enough data in buffer
|
||||
n = avail
|
||||
err = b.readErr()
|
||||
if err == nil {
|
||||
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.
|
||||
|
@ -173,15 +172,13 @@ func (b *Reader) Read(p []byte) (n int, err error) {
|
|||
return n, b.readErr()
|
||||
}
|
||||
b.fill() // buffer is empty
|
||||
if b.w == b.r {
|
||||
if b.r == b.w {
|
||||
return 0, b.readErr()
|
||||
}
|
||||
}
|
||||
|
||||
if n > b.w-b.r {
|
||||
n = b.w - b.r
|
||||
}
|
||||
copy(p[0:n], b.buf[b.r:])
|
||||
// copy as much as we can
|
||||
n = copy(p, b.buf[b.r:b.w])
|
||||
b.r += n
|
||||
b.lastByte = int(b.buf[b.r-1])
|
||||
b.lastRuneSize = -1
|
||||
|
@ -288,7 +285,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
|
|||
}
|
||||
|
||||
// Buffer full?
|
||||
if n := b.Buffered(); n >= len(b.buf) {
|
||||
if b.Buffered() >= len(b.buf) {
|
||||
b.r = b.w
|
||||
line = b.buf
|
||||
err = ErrBufferFull
|
||||
|
@ -301,6 +298,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
|
|||
// Handle last byte, if any.
|
||||
if i := len(line) - 1; i >= 0 {
|
||||
b.lastByte = int(line[i])
|
||||
b.lastRuneSize = -1
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -458,11 +456,13 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
|
|||
return n, b.readErr()
|
||||
}
|
||||
|
||||
var errNegativeWrite = errors.New("bufio: writer returned negative count from Write")
|
||||
|
||||
// writeBuf writes the Reader's buffer to the writer.
|
||||
func (b *Reader) writeBuf(w io.Writer) (int64, error) {
|
||||
n, err := w.Write(b.buf[b.r:b.w])
|
||||
if n < b.r-b.w {
|
||||
panic(errors.New("bufio: writer did not write all data"))
|
||||
if n < 0 {
|
||||
panic(errNegativeWrite)
|
||||
}
|
||||
b.r += n
|
||||
return int64(n), err
|
||||
|
|
|
@ -31,9 +31,6 @@ func newRot13Reader(r io.Reader) *rot13Reader {
|
|||
|
||||
func (r13 *rot13Reader) Read(p []byte) (int, error) {
|
||||
n, err := r13.r.Read(p)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
c := p[i] | 0x20 // lowercase byte
|
||||
if 'a' <= c && c <= 'm' {
|
||||
|
@ -42,7 +39,7 @@ func (r13 *rot13Reader) Read(p []byte) (int, error) {
|
|||
p[i] -= 13
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Call ReadByte to accumulate the text of a file
|
||||
|
@ -438,7 +435,7 @@ func TestUnreadRuneError(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error("unexpected error on ReadRune (2):", err)
|
||||
}
|
||||
for _ = range buf {
|
||||
for range buf {
|
||||
_, err = r.ReadByte()
|
||||
if err != nil {
|
||||
t.Error("unexpected error on ReadByte (2):", err)
|
||||
|
@ -463,6 +460,18 @@ func TestUnreadRuneError(t *testing.T) {
|
|||
if r.UnreadRune() == nil {
|
||||
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) {
|
||||
|
|
|
@ -36,6 +36,7 @@ type Scanner struct {
|
|||
start int // First non-processed byte in buf.
|
||||
end int // End of data in buf.
|
||||
err error // Sticky error.
|
||||
empties int // Count of successive empty tokens.
|
||||
}
|
||||
|
||||
// SplitFunc is the signature of the split function used to tokenize the
|
||||
|
@ -64,8 +65,9 @@ var (
|
|||
)
|
||||
|
||||
const (
|
||||
// Maximum size used to buffer a token. The actual maximum token size
|
||||
// may be smaller as the buffer may need to include, for instance, a newline.
|
||||
// MaxScanTokenSize is the maximum size used to buffer a token.
|
||||
// The actual maximum token size may be smaller as the buffer
|
||||
// may need to include, for instance, a newline.
|
||||
MaxScanTokenSize = 64 * 1024
|
||||
)
|
||||
|
||||
|
@ -107,11 +109,15 @@ func (s *Scanner) Text() string {
|
|||
// After Scan returns false, the Err method will return any error that
|
||||
// occurred during scanning, except that if it was io.EOF, Err
|
||||
// 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 {
|
||||
// Loop until we have a token.
|
||||
for {
|
||||
// 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)
|
||||
if err != nil {
|
||||
s.setErr(err)
|
||||
|
@ -122,6 +128,15 @@ func (s *Scanner) Scan() bool {
|
|||
}
|
||||
s.token = token
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -169,6 +184,7 @@ func (s *Scanner) Scan() bool {
|
|||
break
|
||||
}
|
||||
if n > 0 {
|
||||
s.empties = 0
|
||||
break
|
||||
}
|
||||
loop++
|
||||
|
@ -326,9 +342,6 @@ func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
|||
break
|
||||
}
|
||||
}
|
||||
if atEOF && len(data) == 0 {
|
||||
return 0, nil, nil
|
||||
}
|
||||
// Scan until space, marking end of word.
|
||||
for width, i := 0, start; i < len(data); i += width {
|
||||
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
|
||||
}
|
||||
// Request more data.
|
||||
return 0, nil, nil
|
||||
return start, nil, nil
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ import (
|
|||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const smallMaxTokenSize = 256 // Much smaller for more efficient testing.
|
||||
|
||||
// Test white space table matches the Unicode definition.
|
||||
func TestSpace(t *testing.T) {
|
||||
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.
|
||||
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.
|
||||
tmp := new(bytes.Buffer)
|
||||
buf := new(bytes.Buffer)
|
||||
|
@ -404,3 +405,120 @@ func TestBadReader(t *testing.T) {
|
|||
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
|
||||
// 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.
|
||||
// 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 {
|
||||
n := 0
|
||||
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.
|
||||
func Repeat(b []byte, count int) []byte {
|
||||
nb := make([]byte, len(b)*count)
|
||||
bp := 0
|
||||
for i := 0; i < count; i++ {
|
||||
bp += copy(nb[bp:], b)
|
||||
bp := copy(nb, b)
|
||||
for bp < len(nb) {
|
||||
copy(nb[bp:], nb[:bp])
|
||||
bp *= 2
|
||||
}
|
||||
return nb
|
||||
}
|
||||
|
@ -604,6 +607,9 @@ func Runes(s []byte) []rune {
|
|||
|
||||
// Replace returns a copy of the slice s with the first n
|
||||
// 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.
|
||||
func Replace(s, old, new []byte, n int) []byte {
|
||||
m := 0
|
||||
|
|
|
@ -1232,3 +1232,9 @@ func BenchmarkTrimSpace(b *testing.B) {
|
|||
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:
|
||||
|
||||
// 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:
|
||||
if len(n.Names) == 0 && context == "field" {
|
||||
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 {
|
||||
f.walk(&n.High, "expr", visit)
|
||||
}
|
||||
if n.Max != nil {
|
||||
f.walk(&n.Max, "expr", visit)
|
||||
}
|
||||
case *ast.TypeAssertExpr:
|
||||
f.walk(&n.X, "expr", 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.
|
||||
C compilers are aware of this calling convention and adjust
|
||||
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
|
||||
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,
|
||||
// like #defines or 'struct foo', before bothering with gcc.
|
||||
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
|
||||
// and we can translate it as a constant value, do so.
|
||||
if n.Define != "" {
|
||||
|
@ -331,6 +332,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
const (
|
||||
notType = 1 << iota
|
||||
notConst
|
||||
notDeclared
|
||||
)
|
||||
for _, line := range strings.Split(stderr, "\n") {
|
||||
if !strings.Contains(line, ": error:") {
|
||||
|
@ -365,7 +367,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
completed = true
|
||||
|
||||
case "not-declared":
|
||||
error_(token.NoPos, "%s", strings.TrimSpace(line[c2+1:]))
|
||||
sniff[i] |= notDeclared
|
||||
case "not-type":
|
||||
sniff[i] |= notType
|
||||
case "not-const":
|
||||
|
@ -374,12 +376,12 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
}
|
||||
|
||||
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 {
|
||||
switch sniff[i] {
|
||||
case 0:
|
||||
default:
|
||||
error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
|
||||
case notType:
|
||||
n.Kind = "const"
|
||||
|
@ -390,6 +392,14 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
}
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
|
@ -649,7 +659,13 @@ func (p *Package) rewriteRef(f *File) {
|
|||
f.Name[fpName] = 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" {
|
||||
// Okay - might be new(T)
|
||||
expr = r.Name.Type.Go
|
||||
|
@ -928,9 +944,8 @@ type typeConv struct {
|
|||
|
||||
// Map from types to incomplete pointers to those types.
|
||||
ptrs map[dwarf.Type][]*Type
|
||||
|
||||
// Fields to be processed by godefsField after completing pointers.
|
||||
todoFlds [][]*ast.Field
|
||||
// Keys of ptrs in insertion order (deterministic worklist)
|
||||
ptrKeys []dwarf.Type
|
||||
|
||||
// Predeclared types.
|
||||
bool ast.Expr
|
||||
|
@ -940,9 +955,9 @@ type typeConv struct {
|
|||
float32, float64 ast.Expr
|
||||
complex64, complex128 ast.Expr
|
||||
void ast.Expr
|
||||
unsafePointer ast.Expr
|
||||
string ast.Expr
|
||||
goVoid ast.Expr // _Ctype_void, denotes C's void
|
||||
goVoidPtr ast.Expr // unsafe.Pointer or *byte
|
||||
|
||||
ptrSize int64
|
||||
intSize int64
|
||||
|
@ -972,10 +987,17 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
|
|||
c.float64 = c.Ident("float64")
|
||||
c.complex64 = c.Ident("complex64")
|
||||
c.complex128 = c.Ident("complex128")
|
||||
c.unsafePointer = c.Ident("unsafe.Pointer")
|
||||
c.void = c.Ident("void")
|
||||
c.string = c.Ident("string")
|
||||
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
|
||||
|
@ -1037,29 +1059,22 @@ func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
|
|||
}
|
||||
|
||||
// FinishType completes any outstanding type mapping work.
|
||||
// In particular, it resolves incomplete pointer types and also runs
|
||||
// godefsFields on any new struct types.
|
||||
// In particular, it resolves incomplete pointer types.
|
||||
func (c *typeConv) FinishType(pos token.Pos) {
|
||||
// Completing one pointer type might produce more to complete.
|
||||
// Keep looping until they're all done.
|
||||
for len(c.ptrs) > 0 {
|
||||
for dtype := range c.ptrs {
|
||||
// Note Type might invalidate c.ptrs[dtype].
|
||||
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)
|
||||
}
|
||||
}
|
||||
for len(c.ptrKeys) > 0 {
|
||||
dtype := c.ptrKeys[0]
|
||||
c.ptrKeys = c.ptrKeys[1:]
|
||||
|
||||
// Now that pointer types are completed, we can invoke godefsFields
|
||||
// to rewrite struct definitions.
|
||||
for _, fld := range c.todoFlds {
|
||||
godefsFields(fld)
|
||||
// Note Type might invalidate c.ptrs[dtype].
|
||||
t := c.Type(dtype, pos)
|
||||
for _, ptr := range c.ptrs[dtype] {
|
||||
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
|
||||
|
@ -1072,12 +1087,6 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
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.Size = dtype.Size() // note: wrong for array of pointers, corrected below
|
||||
t.Align = -1
|
||||
|
@ -1101,12 +1110,20 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
t.Go = c.Opaque(t.Size)
|
||||
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)
|
||||
t.Align = sub.Align
|
||||
t.Go = &ast.ArrayType{
|
||||
Len: c.intExpr(dt.Count),
|
||||
Len: c.intExpr(count),
|
||||
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)
|
||||
|
||||
case *dwarf.BoolType:
|
||||
|
@ -1207,11 +1224,15 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
}
|
||||
|
||||
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
|
||||
|
||||
// Translate void* as unsafe.Pointer
|
||||
if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
|
||||
t.Go = c.unsafePointer
|
||||
t.Go = c.goVoidPtr
|
||||
t.C.Set("void*")
|
||||
break
|
||||
}
|
||||
|
@ -1219,6 +1240,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
// Placeholder initialization; completed in FinishType.
|
||||
t.Go = &ast.StarExpr{}
|
||||
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)
|
||||
|
||||
case *dwarf.QualType:
|
||||
|
@ -1379,34 +1403,24 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
}
|
||||
}
|
||||
|
||||
if t.Size <= 0 {
|
||||
// Clang does not record the size of a pointer in its DWARF entry,
|
||||
// so if dtype is an array, the call to dtype.Size at the top of the function
|
||||
// computed the size as the array length * 0 = 0.
|
||||
// The type switch called Type (this function) recursively on the pointer
|
||||
// entry, and the code near the top of the function updated the size to
|
||||
// be correct, so calling dtype.Size again will produce the correct value.
|
||||
t.Size = dtype.Size()
|
||||
if t.Size < 0 {
|
||||
// Unsized types are [0]byte, unless they're typedefs of other types
|
||||
// or structs with tags.
|
||||
// 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.Size < 0 {
|
||||
// Unsized types are [0]byte, unless they're typedefs of other types
|
||||
// or structs with tags.
|
||||
// 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
|
||||
}
|
||||
if t.C.Empty() {
|
||||
t.C.Set("void")
|
||||
}
|
||||
return t
|
||||
t.Go = c.Opaque(0)
|
||||
default:
|
||||
t.Go = c.Opaque(0)
|
||||
}
|
||||
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.
|
||||
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
|
||||
buf.WriteString("struct {")
|
||||
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)
|
||||
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
|
||||
size := t.Size
|
||||
talign := t.Align
|
||||
|
@ -1598,17 +1635,18 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
|
|||
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.
|
||||
// The goal is to make available what can be made available.
|
||||
// Otherwise one bad and unneeded field in an otherwise okay struct
|
||||
// makes the whole program not compile. Much of the time these
|
||||
// structs are in system headers that cannot be corrected.
|
||||
// Exception: In -cdefs mode, we use #pragma pack, so misaligned
|
||||
// fields should still work.
|
||||
continue
|
||||
}
|
||||
n := len(fld)
|
||||
fld = fld[0 : n+1]
|
||||
name := f.Name
|
||||
if name == "" {
|
||||
name = fmt.Sprintf("anon%d", anon)
|
||||
anon++
|
||||
|
@ -1635,7 +1673,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
|
|||
csyntax = buf.String()
|
||||
|
||||
if *godefs || *cdefs {
|
||||
c.todoFlds = append(c.todoFlds, fld)
|
||||
godefsFields(fld)
|
||||
}
|
||||
expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
|
||||
return
|
||||
|
@ -1673,19 +1711,6 @@ func godefsFields(fld []*ast.Field) {
|
|||
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")
|
||||
if *importRuntimeCgo {
|
||||
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 {
|
||||
// If we're not importing runtime/cgo, we *are* runtime/cgo,
|
||||
// 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, "package %s\n\n", p.PackageName)
|
||||
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
|
||||
if *importSyscall {
|
||||
fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
|
||||
}
|
||||
if !*gccgo && *importRuntimeCgo {
|
||||
fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n")
|
||||
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))
|
||||
for name := range typedef {
|
||||
|
@ -87,9 +86,10 @@ func (p *Package) writeDefs() {
|
|||
}
|
||||
|
||||
if *gccgo {
|
||||
fmt.Fprintf(fc, p.cPrologGccgo())
|
||||
fmt.Fprint(fc, p.cPrologGccgo())
|
||||
} else {
|
||||
fmt.Fprintf(fc, cProlog)
|
||||
fmt.Fprint(fc, cProlog)
|
||||
fmt.Fprint(fgo2, goProlog)
|
||||
}
|
||||
|
||||
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(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C)
|
||||
} 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, "\n")
|
||||
|
@ -296,10 +297,6 @@ func (p *Package) structType(n *Name) (string, int64) {
|
|||
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", 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 {
|
||||
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.
|
||||
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 {
|
||||
// Gccgo style hooks.
|
||||
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)
|
||||
fmt.Fprint(fgo2, " {\n")
|
||||
if !inProlog {
|
||||
|
@ -383,7 +379,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
|
|||
fmt.Fprint(fgo2, "}\n")
|
||||
|
||||
// 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)
|
||||
if n.AddError {
|
||||
l := d.Type.Results.List
|
||||
|
@ -394,61 +390,50 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
|
|||
|
||||
return
|
||||
}
|
||||
conf.Fprint(fgo2, fset, d)
|
||||
fmt.Fprint(fgo2, "\n")
|
||||
|
||||
if inProlog {
|
||||
fmt.Fprint(fgo2, builtinDefs[name])
|
||||
return
|
||||
}
|
||||
|
||||
var argSize int64
|
||||
_, argSize = p.structType(n)
|
||||
|
||||
// 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, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle)
|
||||
fmt.Fprintf(fc, "\n")
|
||||
fmt.Fprintf(fc, "void\n")
|
||||
if argSize == 0 {
|
||||
argSize++
|
||||
fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", cname)
|
||||
fmt.Fprintf(fc, "void %s(void*);\n", cname)
|
||||
fmt.Fprintf(fc, "#pragma dataflag NOPTR\n")
|
||||
fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname)
|
||||
|
||||
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 {
|
||||
// gcc leaves errno in first word of interface at end of p.
|
||||
// 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 */
|
||||
}
|
||||
}`)
|
||||
d.Type.Results.List[nret].Names = []*ast.Ident{ast.NewIdent("r2")}
|
||||
}
|
||||
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
|
||||
|
@ -521,7 +506,11 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
|
|||
|
||||
// Gcc wrapper unpacks the C argument struct
|
||||
// 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, "{\n")
|
||||
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
|
||||
// gcc has different packing requirements.
|
||||
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")
|
||||
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] == '*' {
|
||||
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, ");\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 {
|
||||
fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n")
|
||||
fmt.Fprintf(fgcc, "\treturn errno;\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)
|
||||
i++
|
||||
} else {
|
||||
for _ = range r.Names {
|
||||
for range r.Names {
|
||||
fn(i, r.Type)
|
||||
i++
|
||||
}
|
||||
|
@ -1143,21 +1143,17 @@ __cgo_size_assert(__cgo_long_long, 8)
|
|||
__cgo_size_assert(float, 4)
|
||||
__cgo_size_assert(double, 8)
|
||||
|
||||
extern char* _cgo_topofstack(void);
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
`
|
||||
|
||||
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. */
|
||||
#ifdef __PTRDIFF_TYPE__
|
||||
typedef __PTRDIFF_TYPE__ intgo;
|
||||
#elif defined(_LP64)
|
||||
typedef long long intgo;
|
||||
#else
|
||||
typedef int intgo;
|
||||
#endif
|
||||
typedef ptrdiff_t intgo;
|
||||
|
||||
typedef struct { char *p; intgo n; } _GoString_;
|
||||
typedef struct { char *p; intgo n; intgo c; } _GoBytes_;
|
||||
|
@ -1171,47 +1167,86 @@ void *_CMalloc(size_t);
|
|||
const cProlog = `
|
||||
#include "runtime.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
|
||||
·_Cfunc_GoString(int8 *p, String s)
|
||||
{
|
||||
s = runtime·gostring((byte*)p);
|
||||
FLUSH(&s);
|
||||
}
|
||||
const goProlog = `
|
||||
var _cgo_runtime_cgocall_errno func(unsafe.Pointer, uintptr) int32
|
||||
var _cgo_runtime_cmalloc func(uintptr) unsafe.Pointer
|
||||
`
|
||||
|
||||
void
|
||||
·_Cfunc_GoStringN(int8 *p, int32 l, String s)
|
||||
{
|
||||
s = runtime·gostringn((byte*)p, l);
|
||||
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 goStringDef = `
|
||||
var _cgo_runtime_gostring func(*_Ctype_char) string
|
||||
func _Cfunc_GoString(p *_Ctype_char) string {
|
||||
return _cgo_runtime_gostring(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 {
|
||||
return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1)
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ and test commands:
|
|||
|
||||
-a
|
||||
force rebuilding of packages that are already up-to-date.
|
||||
In Go releases, does not apply to the standard library.
|
||||
-n
|
||||
print the commands but do not run them.
|
||||
-p n
|
||||
|
@ -64,7 +65,7 @@ and test commands:
|
|||
The default is the number of CPUs available.
|
||||
-race
|
||||
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
|
||||
print the names of packages as they are compiled.
|
||||
-work
|
||||
|
@ -291,23 +292,26 @@ func runBuild(cmd *Command, args []string) {
|
|||
}
|
||||
}
|
||||
|
||||
depMode := modeBuild
|
||||
if buildI {
|
||||
depMode = modeInstall
|
||||
}
|
||||
|
||||
if *buildO != "" {
|
||||
if len(pkgs) > 1 {
|
||||
fatalf("go build: cannot use -o with multiple packages")
|
||||
} else if len(pkgs) == 0 {
|
||||
fatalf("no packages to build")
|
||||
}
|
||||
p := pkgs[0]
|
||||
p.target = "" // must build - not up to date
|
||||
a := b.action(modeInstall, modeBuild, p)
|
||||
a := b.action(modeInstall, depMode, p)
|
||||
a.target = *buildO
|
||||
b.do(a)
|
||||
return
|
||||
}
|
||||
|
||||
a := &action{}
|
||||
depMode := modeBuild
|
||||
if buildI {
|
||||
depMode = modeInstall
|
||||
}
|
||||
for _, p := range packages(args) {
|
||||
a.deps = append(a.deps, b.action(modeBuild, depMode, p))
|
||||
}
|
||||
|
@ -438,12 +442,11 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
goroot = filepath.Clean(runtime.GOROOT())
|
||||
gobin = os.Getenv("GOBIN")
|
||||
gorootBin = filepath.Join(goroot, "bin")
|
||||
gorootSrcPkg = filepath.Join(goroot, "src/pkg")
|
||||
gorootPkg = filepath.Join(goroot, "pkg")
|
||||
gorootSrc = filepath.Join(goroot, "src")
|
||||
goroot = filepath.Clean(runtime.GOROOT())
|
||||
gobin = os.Getenv("GOBIN")
|
||||
gorootBin = filepath.Join(goroot, "bin")
|
||||
gorootPkg = filepath.Join(goroot, "pkg")
|
||||
gorootSrc = filepath.Join(goroot, "src")
|
||||
)
|
||||
|
||||
func (b *builder) init() {
|
||||
|
@ -510,8 +513,13 @@ func goFilesPackage(gofiles []string) *Package {
|
|||
}
|
||||
ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
|
||||
|
||||
if !filepath.IsAbs(dir) {
|
||||
dir = filepath.Join(cwd, dir)
|
||||
var err error
|
||||
if dir == "" {
|
||||
dir = cwd
|
||||
}
|
||||
dir, err = filepath.Abs(dir)
|
||||
if err != nil {
|
||||
fatalf("%s", err)
|
||||
}
|
||||
|
||||
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...)
|
||||
cfiles = append(cfiles, a.p.CFiles...)
|
||||
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.
|
||||
if a.p.usesCgo() {
|
||||
// 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 != "" {
|
||||
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 {
|
||||
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
|
||||
// compiled with gcc.
|
||||
gccfiles := append(cfiles, sfiles...)
|
||||
cxxfiles, mfiles := a.p.CXXFiles, a.p.MFiles
|
||||
cfiles = 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 {
|
||||
return err
|
||||
}
|
||||
|
@ -893,7 +915,7 @@ func (b *builder) build(a *action) (err error) {
|
|||
}
|
||||
|
||||
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
|
||||
|
@ -1028,6 +1050,34 @@ func (b *builder) build(a *action) (err error) {
|
|||
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.
|
||||
func (b *builder) install(a *action) (err error) {
|
||||
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.
|
||||
// showOutput rewrites mentions of dir with a relative path to dir
|
||||
// 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
|
||||
//
|
||||
// $ go build
|
||||
|
@ -1275,7 +1325,7 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) {
|
|||
//
|
||||
// $ go build
|
||||
// # 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.
|
||||
|
@ -1435,6 +1485,14 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter
|
|||
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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
if p.Standard {
|
||||
switch p.ImportPath {
|
||||
case "os", "runtime/pprof", "sync", "time":
|
||||
case "bytes", "net", "os", "runtime/pprof", "sync", "time":
|
||||
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 {
|
||||
// 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)
|
||||
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 {
|
||||
|
@ -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 {
|
||||
importArgs := b.includeArgs("-L", allactions)
|
||||
cxx := false
|
||||
cxx := len(p.CXXFiles) > 0
|
||||
for _, a := range allactions {
|
||||
if a.p != nil && len(a.p.CXXFiles) > 0 {
|
||||
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 {
|
||||
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
out := p.Name + ".o"
|
||||
out := "_go_.o"
|
||||
ofile = obj + out
|
||||
gcargs := []string{"-g"}
|
||||
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, b.gccArchArgs()...)
|
||||
|
||||
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()
|
||||
cgoldflags := []string{}
|
||||
usesCgo := false
|
||||
cxx := false
|
||||
objc := false
|
||||
cxx := len(p.CXXFiles) > 0
|
||||
objc := len(p.MFiles) > 0
|
||||
|
||||
// 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.
|
||||
|
@ -1917,8 +1986,7 @@ func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) er
|
|||
if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
|
||||
defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
|
||||
}
|
||||
// TODO: Support using clang here (during gccgo build)?
|
||||
return b.run(p.Dir, p.ImportPath, nil, "gcc", "-Wall", "-g",
|
||||
return b.run(p.Dir, p.ImportPath, nil, envList("CC", defaultCC), "-Wall", "-g",
|
||||
"-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
|
||||
}
|
||||
|
||||
|
@ -1969,9 +2037,9 @@ func (b *builder) libgcc(p *Package) (string, error) {
|
|||
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.
|
||||
if strings.Contains(gccCmd[0], "clang") && !filepath.IsAbs(string(f)) {
|
||||
if !filepath.IsAbs(string(f)) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
|
@ -2109,36 +2177,16 @@ var (
|
|||
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)
|
||||
_, 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 len(mfiles) > 0 {
|
||||
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.
|
||||
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, ".dll"):
|
||||
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:
|
||||
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...)
|
||||
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")
|
||||
}
|
||||
if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
|
||||
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]
|
||||
}
|
||||
|
||||
|
@ -2321,7 +2378,23 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles
|
|||
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
|
||||
}
|
||||
|
||||
|
@ -2336,7 +2409,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles
|
|||
// Run SWIG on all SWIG input files.
|
||||
// TODO: Don't build a shared library, once SWIG emits the necessary
|
||||
// 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)
|
||||
cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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.
|
||||
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)
|
||||
var cflags []string
|
||||
if cxx {
|
||||
cflags = stringList(cgoCPPFLAGS, cgoCXXFLAGS)
|
||||
cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
|
||||
} else {
|
||||
cflags = stringList(cgoCPPFLAGS, cgoCFLAGS)
|
||||
cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS)
|
||||
}
|
||||
|
||||
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,
|
||||
"-outdir", obj,
|
||||
}
|
||||
|
||||
for _, f := range cflags {
|
||||
if len(f) > 3 && f[:2] == "-I" {
|
||||
args = append(args, f)
|
||||
}
|
||||
}
|
||||
|
||||
if gccgo {
|
||||
args = append(args, "-gccgo")
|
||||
if pkgpath := gccgoPkgpath(p); pkgpath != "" {
|
||||
|
@ -2575,8 +2655,8 @@ func raceInit() {
|
|||
if !buildRace {
|
||||
return
|
||||
}
|
||||
if goarch != "amd64" || goos != "linux" && 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])
|
||||
if goarch != "amd64" || goos != "linux" && goos != "freebsd" && goos != "darwin" && goos != "windows" {
|
||||
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)
|
||||
}
|
||||
buildGcflags = append(buildGcflags, "-race")
|
||||
|
|
|
@ -19,6 +19,7 @@ The commands are:
|
|||
env print Go environment information
|
||||
fix run go tool fix on packages
|
||||
fmt run gofmt on package sources
|
||||
generate generate Go files by processing source
|
||||
get download and install packages and dependencies
|
||||
install compile and install packages and dependencies
|
||||
list list packages
|
||||
|
@ -75,6 +76,7 @@ and test commands:
|
|||
|
||||
-a
|
||||
force rebuilding of packages that are already up-to-date.
|
||||
In Go releases, does not apply to the standard library.
|
||||
-n
|
||||
print the commands but do not run them.
|
||||
-p n
|
||||
|
@ -82,7 +84,7 @@ and test commands:
|
|||
The default is the number of CPUs available.
|
||||
-race
|
||||
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
|
||||
print the names of packages as they are compiled.
|
||||
-work
|
||||
|
@ -219,11 +221,110 @@ To run gofmt with specific options, run gofmt itself.
|
|||
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
|
||||
|
||||
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,
|
||||
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,
|
||||
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
|
||||
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:
|
||||
|
||||
type Package struct {
|
||||
Dir string // directory containing package sources
|
||||
ImportPath string // import path of package in dir
|
||||
Name string // package name
|
||||
Doc string // package documentation string
|
||||
Target string // install path
|
||||
Goroot bool // is this package in the Go root?
|
||||
Standard bool // is this package part of the standard Go library?
|
||||
Stale bool // would 'go install' do anything for this package?
|
||||
Root string // Go root or Go path dir containing this package
|
||||
Dir string // directory containing package sources
|
||||
ImportPath string // import path of package in dir
|
||||
ImportComment string // path in import comment on package statement
|
||||
Name string // package name
|
||||
Doc string // package documentation string
|
||||
Target string // install path
|
||||
Goroot bool // is this package in the Go root?
|
||||
Standard bool // is this package part of the standard Go library?
|
||||
Stale bool // would 'go install' do anything for this package?
|
||||
Root string // Go root or Go path dir containing this package
|
||||
|
||||
// Source files
|
||||
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
CgoFiles []string // .go sources files that import "C"
|
||||
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
CgoFiles []string // .go sources files that import "C"
|
||||
IgnoredGoFiles []string // .go sources ignored due to build constraints
|
||||
CFiles []string // .c source files
|
||||
CXXFiles []string // .cc, .cxx and .cpp source files
|
||||
MFiles []string // .m source files
|
||||
HFiles []string // .h, .hh, .hpp and .hxx source files
|
||||
SFiles []string // .s source files
|
||||
SwigFiles []string // .swig files
|
||||
SwigCXXFiles []string // .swigcxx files
|
||||
SysoFiles []string // .syso object files to add to archive
|
||||
CFiles []string // .c source files
|
||||
CXXFiles []string // .cc, .cxx and .cpp source files
|
||||
MFiles []string // .m source files
|
||||
HFiles []string // .h, .hh, .hpp and .hxx source files
|
||||
SFiles []string // .s source files
|
||||
SwigFiles []string // .swig files
|
||||
SwigCXXFiles []string // .swigcxx files
|
||||
SysoFiles []string // .syso object files to add to archive
|
||||
|
||||
// Cgo directives
|
||||
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:
|
||||
|
||||
-c Compile the test binary to pkg.test but do not run it.
|
||||
(Where pkg is the last element of the package's import path.)
|
||||
-c
|
||||
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
|
||||
Install packages that are dependencies of the test.
|
||||
Do not run the test.
|
||||
|
||||
-exec xprog
|
||||
Run the test binary using xprog. The behavior is the same as
|
||||
in 'go run'. See 'go help run' for details.
|
||||
-o file
|
||||
Compile the test binary to the named file.
|
||||
The test still runs (unless -c or -i is specified).
|
||||
|
||||
|
||||
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.
|
||||
|
@ -488,7 +602,7 @@ Usage:
|
|||
|
||||
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'.
|
||||
|
||||
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/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
|
||||
with the version control type, or the go tool can dynamically fetch
|
||||
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
|
||||
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
|
||||
|
@ -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
|
||||
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
|
||||
|
@ -844,6 +983,7 @@ control the execution of any test:
|
|||
-blockprofile block.out
|
||||
Write a goroutine blocking profile to the specified file
|
||||
when all tests are complete.
|
||||
Writes test binary as -c would.
|
||||
|
||||
-blockprofilerate n
|
||||
Control the detail provided in goroutine blocking profiles by
|
||||
|
@ -875,8 +1015,7 @@ control the execution of any test:
|
|||
Sets -cover.
|
||||
|
||||
-coverprofile cover.out
|
||||
Write a coverage profile to the specified file after all tests
|
||||
have passed.
|
||||
Write a coverage profile to the file after all tests have passed.
|
||||
Sets -cover.
|
||||
|
||||
-cpu 1,2,4
|
||||
|
@ -886,10 +1025,11 @@ control the execution of any test:
|
|||
|
||||
-cpuprofile cpu.out
|
||||
Write a CPU profile to the specified file before exiting.
|
||||
Writes test binary as -c would.
|
||||
|
||||
-memprofile mem.out
|
||||
Write a memory profile to the specified file after all tests
|
||||
have passed.
|
||||
Write a memory profile to the file after all tests have passed.
|
||||
Writes test binary as -c would.
|
||||
|
||||
-memprofilerate n
|
||||
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{
|
||||
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",
|
||||
Long: `
|
||||
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,
|
||||
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
|
||||
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 getF = cmdGet.Flag.Bool("f", false, "")
|
||||
var getT = cmdGet.Flag.Bool("t", false, "")
|
||||
var getU = cmdGet.Flag.Bool("u", false, "")
|
||||
var getFix = cmdGet.Flag.Bool("fix", false, "")
|
||||
|
@ -63,6 +69,10 @@ func init() {
|
|||
}
|
||||
|
||||
func runGet(cmd *Command, args []string) {
|
||||
if *getF && !*getU {
|
||||
fatalf("go get: cannot use -f flag without -u")
|
||||
}
|
||||
|
||||
// Phase 1. Download/update.
|
||||
var stk importStack
|
||||
for _, arg := range downloadPaths(args) {
|
||||
|
@ -151,7 +161,9 @@ func download(arg string, stk *importStack, getTestDeps bool) {
|
|||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
downloadCache[arg] = true
|
||||
|
@ -264,6 +276,25 @@ func downloadPackage(p *Package) error {
|
|||
return err
|
||||
}
|
||||
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 {
|
||||
// Analyze the import path to determine the version control system,
|
||||
// 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
|
||||
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/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
|
||||
with the version control type, or the go tool can dynamically fetch
|
||||
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
|
||||
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:
|
||||
|
||||
type Package struct {
|
||||
Dir string // directory containing package sources
|
||||
ImportPath string // import path of package in dir
|
||||
Name string // package name
|
||||
Doc string // package documentation string
|
||||
Target string // install path
|
||||
Goroot bool // is this package in the Go root?
|
||||
Standard bool // is this package part of the standard Go library?
|
||||
Stale bool // would 'go install' do anything for this package?
|
||||
Root string // Go root or Go path dir containing this package
|
||||
Dir string // directory containing package sources
|
||||
ImportPath string // import path of package in dir
|
||||
ImportComment string // path in import comment on package statement
|
||||
Name string // package name
|
||||
Doc string // package documentation string
|
||||
Target string // install path
|
||||
Goroot bool // is this package in the Go root?
|
||||
Standard bool // is this package part of the standard Go library?
|
||||
Stale bool // would 'go install' do anything for this package?
|
||||
Root string // Go root or Go path dir containing this package
|
||||
|
||||
// Source files
|
||||
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
CgoFiles []string // .go sources files that import "C"
|
||||
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
CgoFiles []string // .go sources files that import "C"
|
||||
IgnoredGoFiles []string // .go sources ignored due to build constraints
|
||||
CFiles []string // .c source files
|
||||
CXXFiles []string // .cc, .cxx and .cpp source files
|
||||
MFiles []string // .m source files
|
||||
HFiles []string // .h, .hh, .hpp and .hxx source files
|
||||
SFiles []string // .s source files
|
||||
SwigFiles []string // .swig files
|
||||
SwigCXXFiles []string // .swigcxx files
|
||||
SysoFiles []string // .syso object files to add to archive
|
||||
CFiles []string // .c source files
|
||||
CXXFiles []string // .cc, .cxx and .cpp source files
|
||||
MFiles []string // .m source files
|
||||
HFiles []string // .h, .hh, .hpp and .hxx source files
|
||||
SFiles []string // .s source files
|
||||
SwigFiles []string // .swig files
|
||||
SwigCXXFiles []string // .swigcxx files
|
||||
SysoFiles []string // .syso object files to add to archive
|
||||
|
||||
// Cgo directives
|
||||
CgoCFLAGS []string // cgo: flags for C compiler
|
||||
|
|
|
@ -79,6 +79,7 @@ var commands = []*Command{
|
|||
cmdEnv,
|
||||
cmdFix,
|
||||
cmdFmt,
|
||||
cmdGenerate,
|
||||
cmdGet,
|
||||
cmdInstall,
|
||||
cmdList,
|
||||
|
@ -536,7 +537,7 @@ func matchPackages(pattern string) []string {
|
|||
})
|
||||
|
||||
for _, src := range buildContext.SrcDirs() {
|
||||
if pattern == "std" && src != gorootSrcPkg {
|
||||
if pattern == "std" && src != gorootSrc {
|
||||
continue
|
||||
}
|
||||
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.
|
||||
//
|
||||
// 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
|
||||
// result in "././io", and match("././io") returns false.
|
||||
path = filepath.Clean(path)
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"os"
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -25,16 +26,17 @@ type Package struct {
|
|||
// 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
|
||||
// remove existing ones. Keep in sync with list.go
|
||||
Dir string `json:",omitempty"` // directory containing package sources
|
||||
ImportPath string `json:",omitempty"` // import path of package in dir
|
||||
Name string `json:",omitempty"` // package name
|
||||
Doc string `json:",omitempty"` // package documentation string
|
||||
Target string `json:",omitempty"` // install path
|
||||
Goroot bool `json:",omitempty"` // is this package found in the Go root?
|
||||
Standard bool `json:",omitempty"` // is this package part of the standard Go library?
|
||||
Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
|
||||
Root string `json:",omitempty"` // Go root or Go path dir containing this package
|
||||
ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
|
||||
Dir string `json:",omitempty"` // directory containing package sources
|
||||
ImportPath string `json:",omitempty"` // import path of package in dir
|
||||
ImportComment string `json:",omitempty"` // path in import comment on package statement
|
||||
Name string `json:",omitempty"` // package name
|
||||
Doc string `json:",omitempty"` // package documentation string
|
||||
Target string `json:",omitempty"` // install path
|
||||
Goroot bool `json:",omitempty"` // is this package found in the Go root?
|
||||
Standard bool `json:",omitempty"` // is this package part of the standard Go library?
|
||||
Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
|
||||
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
|
||||
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.ImportPath = pp.ImportPath
|
||||
p.ImportComment = pp.ImportComment
|
||||
p.Name = pp.Name
|
||||
p.Doc = pp.Doc
|
||||
p.Root = pp.Root
|
||||
|
@ -218,7 +221,7 @@ func dirToImportPath(dir string) string {
|
|||
}
|
||||
|
||||
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"
|
||||
if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
|
||||
return '_'
|
||||
|
@ -244,6 +247,9 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
|
|||
importPath = dirToImportPath(filepath.Join(srcDir, path))
|
||||
}
|
||||
if p := packageCache[importPath]; p != nil {
|
||||
if perr := disallowInternal(srcDir, p, stk); perr != p {
|
||||
return perr
|
||||
}
|
||||
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.
|
||||
// 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
|
||||
if 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)
|
||||
if p.Error != nil && len(importPos) > 0 {
|
||||
pos := importPos[0]
|
||||
|
@ -270,6 +279,10 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
|
|||
p.Error.Pos = pos.String()
|
||||
}
|
||||
|
||||
if perr := disallowInternal(srcDir, p, stk); perr != p {
|
||||
return perr
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
|
@ -298,12 +311,82 @@ func reusePackage(p *Package, stk *importStack) *Package {
|
|||
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
|
||||
|
||||
const (
|
||||
toRoot targetDir = iota // to bin dir inside package root (default)
|
||||
toTool // GOROOT/pkg/tool
|
||||
toBin // GOROOT/bin
|
||||
toRoot targetDir = iota // to bin dir inside package root (default)
|
||||
toTool // GOROOT/pkg/tool
|
||||
toBin // GOROOT/bin
|
||||
stalePath // the old import path; fail to build
|
||||
)
|
||||
|
||||
// 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/objdump": toTool,
|
||||
"cmd/pack": toTool,
|
||||
"cmd/pprof": toTool,
|
||||
"cmd/yacc": toTool,
|
||||
"code.google.com/p/go.tools/cmd/cover": toTool,
|
||||
"code.google.com/p/go.tools/cmd/godoc": toBin,
|
||||
"code.google.com/p/go.tools/cmd/vet": toTool,
|
||||
"golang.org/x/tools/cmd/cover": toTool,
|
||||
"golang.org/x/tools/cmd/godoc": toBin,
|
||||
"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.
|
||||
|
@ -380,6 +467,13 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
|
|||
}
|
||||
|
||||
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)
|
||||
full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem
|
||||
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.
|
||||
imports := make([]*Package, 0, len(p.Imports))
|
||||
deps := make(map[string]bool)
|
||||
deps := make(map[string]*Package)
|
||||
for i, path := range importPaths {
|
||||
if path == "C" {
|
||||
continue
|
||||
|
@ -505,10 +599,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
|
|||
path = p1.ImportPath
|
||||
importPaths[i] = path
|
||||
}
|
||||
deps[path] = true
|
||||
deps[path] = p1
|
||||
imports = append(imports, p1)
|
||||
for _, dep := range p1.Deps {
|
||||
deps[dep] = true
|
||||
for _, dep := range p1.deps {
|
||||
deps[dep.ImportPath] = dep
|
||||
}
|
||||
if p1.Incomplete {
|
||||
p.Incomplete = true
|
||||
|
@ -522,7 +616,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
|
|||
}
|
||||
sort.Strings(p.Deps)
|
||||
for _, dep := range p.Deps {
|
||||
p1 := packageCache[dep]
|
||||
p1 := deps[dep]
|
||||
if p1 == nil {
|
||||
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
|
||||
|
||||
// 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,
|
||||
// check for case-insensitive collisions of import paths.
|
||||
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.
|
||||
func isStale(p *Package, topRoot map[string]bool) bool {
|
||||
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
|
||||
|
@ -619,7 +729,16 @@ func isStale(p *Package, topRoot map[string]bool) bool {
|
|||
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
|
||||
}
|
||||
|
||||
|
@ -707,24 +826,13 @@ func loadPackage(arg string, stk *importStack) *Package {
|
|||
arg = sub
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(arg, "cmd/") {
|
||||
if strings.HasPrefix(arg, "cmd/") && !strings.Contains(arg[4:], "/") {
|
||||
if p := cmdCache[arg]; p != nil {
|
||||
return p
|
||||
}
|
||||
stk.push(arg)
|
||||
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.ImportPath = arg
|
||||
bp.Goroot = true
|
||||
|
|
|
@ -6,6 +6,7 @@ package main
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
|
@ -48,7 +49,7 @@ It prints a summary of the test results in the format:
|
|||
followed by detailed output for each failed package.
|
||||
|
||||
'Go test' recompiles each package along with any files with names matching
|
||||
the file pattern "*_test.go".
|
||||
the file pattern "*_test.go".
|
||||
Files whose names begin with "_" (including "_test.go") or "." are ignored.
|
||||
These additional files can contain test functions, benchmark functions, and
|
||||
example functions. See 'go help testfunc' for more.
|
||||
|
@ -65,16 +66,23 @@ non-test installation.
|
|||
|
||||
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.
|
||||
(Where pkg is the last element of the package's import path.)
|
||||
-c
|
||||
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
|
||||
Install packages that are dependencies of the test.
|
||||
Do not run the test.
|
||||
|
||||
-exec xprog
|
||||
Run the test binary using xprog. The behavior is the same as
|
||||
in 'go run'. See 'go help run' for details.
|
||||
-o file
|
||||
Compile the test binary to the named file.
|
||||
The test still runs (unless -c or -i is specified).
|
||||
|
||||
|
||||
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.
|
||||
|
@ -122,6 +130,7 @@ control the execution of any test:
|
|||
-blockprofile block.out
|
||||
Write a goroutine blocking profile to the specified file
|
||||
when all tests are complete.
|
||||
Writes test binary as -c would.
|
||||
|
||||
-blockprofilerate n
|
||||
Control the detail provided in goroutine blocking profiles by
|
||||
|
@ -153,8 +162,7 @@ control the execution of any test:
|
|||
Sets -cover.
|
||||
|
||||
-coverprofile cover.out
|
||||
Write a coverage profile to the specified file after all tests
|
||||
have passed.
|
||||
Write a coverage profile to the file after all tests have passed.
|
||||
Sets -cover.
|
||||
|
||||
-cpu 1,2,4
|
||||
|
@ -164,10 +172,11 @@ control the execution of any test:
|
|||
|
||||
-cpuprofile cpu.out
|
||||
Write a CPU profile to the specified file before exiting.
|
||||
Writes test binary as -c would.
|
||||
|
||||
-memprofile mem.out
|
||||
Write a memory profile to the specified file after all tests
|
||||
have passed.
|
||||
Write a memory profile to the file after all tests have passed.
|
||||
Writes test binary as -c would.
|
||||
|
||||
-memprofilerate n
|
||||
Enable more precise (and expensive) memory profiles by setting
|
||||
|
@ -274,10 +283,10 @@ var (
|
|||
testCoverMode string // -covermode flag
|
||||
testCoverPaths []string // -coverpkg flag
|
||||
testCoverPkgs []*Package // -coverpkg flag
|
||||
testO string // -o flag
|
||||
testProfile bool // some profiling flag
|
||||
testNeedBinary bool // profile needs to keep binary around
|
||||
testV bool // -v flag
|
||||
testFiles []string // -file flag(s) TODO: not respected
|
||||
testTimeout string // -timeout flag
|
||||
testArgs []string
|
||||
testBench bool
|
||||
|
@ -291,6 +300,7 @@ var testMainDeps = map[string]bool{
|
|||
// Dependencies for testmain.
|
||||
"testing": true,
|
||||
"regexp": true,
|
||||
"os": true,
|
||||
}
|
||||
|
||||
func runTest(cmd *Command, args []string) {
|
||||
|
@ -308,6 +318,9 @@ func runTest(cmd *Command, args []string) {
|
|||
if testC && len(pkgs) != 1 {
|
||||
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 {
|
||||
fatalf("cannot use test profile flag with multiple packages")
|
||||
}
|
||||
|
@ -524,6 +537,13 @@ func contains(x []string, s string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
var windowsBadWords = []string{
|
||||
"install",
|
||||
"patch",
|
||||
"setup",
|
||||
"update",
|
||||
}
|
||||
|
||||
func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) {
|
||||
if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
|
||||
build := b.action(modeBuild, modeBuild, p)
|
||||
|
@ -695,7 +715,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
|
|||
omitDWARF: !testC && !testNeedBinary,
|
||||
}
|
||||
|
||||
// The generated main also imports testing and regexp.
|
||||
// The generated main also imports testing, regexp, and os.
|
||||
stk.push("testmain")
|
||||
for dep := range testMainDeps {
|
||||
if dep == ptest.ImportPath {
|
||||
|
@ -734,11 +754,13 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
|
|||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if t.NeedTest || ptest.coverMode != "" {
|
||||
if len(ptest.GoFiles) > 0 {
|
||||
pmain.imports = append(pmain.imports, ptest)
|
||||
t.ImportTest = true
|
||||
}
|
||||
if t.NeedXtest {
|
||||
if pxtest != nil {
|
||||
pmain.imports = append(pmain.imports, pxtest)
|
||||
t.ImportXtest = true
|
||||
}
|
||||
|
||||
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.objpkg = filepath.Join(testDir, "main.a")
|
||||
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 {
|
||||
// -c or profiling flag: create action to copy binary to ./test.out.
|
||||
runAction = &action{
|
||||
f: (*builder).install,
|
||||
deps: []*action{pmainAction},
|
||||
p: pmain,
|
||||
target: filepath.Join(cwd, testBinary+exeSuffix),
|
||||
target := filepath.Join(cwd, testBinary+exeSuffix)
|
||||
if testO != "" {
|
||||
target = testO
|
||||
if !filepath.IsAbs(target) {
|
||||
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 {
|
||||
printAction = &action{p: p, deps: []*action{runAction}} // nop
|
||||
|
@ -808,7 +867,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
|
|||
// run test
|
||||
runAction = &action{
|
||||
f: (*builder).runTest,
|
||||
deps: []*action{pmainAction},
|
||||
deps: []*action{buildAction},
|
||||
p: p,
|
||||
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 {
|
||||
|
@ -1068,6 +1127,31 @@ func (b *builder) notest(a *action) error {
|
|||
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).
|
||||
// It is a Test (say) if there is a character after Test that is not a lower-case letter.
|
||||
// We don't want TesticularCancer.
|
||||
|
@ -1093,12 +1177,12 @@ func loadTestFuncs(ptest *Package) (*testFuncs, error) {
|
|||
Package: ptest,
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -1121,13 +1205,16 @@ func writeTestmain(out string, t *testFuncs) error {
|
|||
}
|
||||
|
||||
type testFuncs struct {
|
||||
Tests []testFunc
|
||||
Benchmarks []testFunc
|
||||
Examples []testFunc
|
||||
Package *Package
|
||||
NeedTest bool
|
||||
NeedXtest bool
|
||||
Cover []coverInfo
|
||||
Tests []testFunc
|
||||
Benchmarks []testFunc
|
||||
Examples []testFunc
|
||||
TestMain *testFunc
|
||||
Package *Package
|
||||
ImportTest bool
|
||||
NeedTest bool
|
||||
ImportXtest bool
|
||||
NeedXtest bool
|
||||
Cover []coverInfo
|
||||
}
|
||||
|
||||
func (t *testFuncs) CoverMode() string {
|
||||
|
@ -1162,7 +1249,7 @@ type testFunc struct {
|
|||
|
||||
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)
|
||||
if err != nil {
|
||||
return expandScanner(err)
|
||||
|
@ -1177,17 +1264,24 @@ func (t *testFuncs) load(filename, pkg string, seen *bool) error {
|
|||
}
|
||||
name := n.Name.String()
|
||||
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"):
|
||||
t.Tests = append(t.Tests, testFunc{pkg, name, ""})
|
||||
*seen = true
|
||||
*doImport, *seen = true, true
|
||||
case isTest(name, "Benchmark"):
|
||||
t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})
|
||||
*seen = true
|
||||
*doImport, *seen = true, true
|
||||
}
|
||||
}
|
||||
ex := doc.Examples(f)
|
||||
sort.Sort(byOrder(ex))
|
||||
for _, e := range ex {
|
||||
*doImport = true // import test file whether executed or not
|
||||
if e.Output == "" && !e.EmptyOutput {
|
||||
// Don't run examples with no output.
|
||||
continue
|
||||
|
@ -1208,14 +1302,17 @@ var testmainTmpl = template.Must(template.New("main").Parse(`
|
|||
package main
|
||||
|
||||
import (
|
||||
{{if not .TestMain}}
|
||||
"os"
|
||||
{{end}}
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
{{if .NeedTest}}
|
||||
_test {{.Package.ImportPath | printf "%q"}}
|
||||
{{if .ImportTest}}
|
||||
{{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
|
||||
{{end}}
|
||||
{{if .NeedXtest}}
|
||||
_xtest {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
|
||||
{{if .ImportXtest}}
|
||||
{{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
|
||||
{{end}}
|
||||
{{range $i, $p := .Cover}}
|
||||
_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
|
||||
|
@ -1302,7 +1399,12 @@ func main() {
|
|||
CoveredPackages: {{printf "%q" .Covered}},
|
||||
})
|
||||
{{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{
|
||||
// local.
|
||||
{name: "c", boolVar: &testC},
|
||||
{name: "file", multiOK: true},
|
||||
{name: "cover", boolVar: &testCover},
|
||||
{name: "coverpkg"},
|
||||
{name: "o"},
|
||||
|
||||
// build flags.
|
||||
{name: "a", boolVar: &buildA},
|
||||
|
@ -153,6 +153,9 @@ func testFlags(args []string) (packageNames, passToTest []string) {
|
|||
// bool flags.
|
||||
case "a", "c", "i", "n", "x", "v", "race", "cover", "work":
|
||||
setBoolFlag(f.boolVar, value)
|
||||
case "o":
|
||||
testO = value
|
||||
testNeedBinary = true
|
||||
case "p":
|
||||
setIntFlag(&buildP, value)
|
||||
case "exec":
|
||||
|
@ -184,8 +187,6 @@ func testFlags(args []string) (packageNames, passToTest []string) {
|
|||
buildContext.BuildTags = strings.Fields(value)
|
||||
case "compiler":
|
||||
buildCompiler{}.Set(value)
|
||||
case "file":
|
||||
testFiles = append(testFiles, value)
|
||||
case "bench":
|
||||
// record that we saw the flag; don't care about the value
|
||||
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 {
|
||||
toolPath := filepath.Join(toolDir, toolName)
|
||||
if toolIsWindows && toolName != "pprof" {
|
||||
if toolIsWindows {
|
||||
toolPath += toolWindowsExtension
|
||||
}
|
||||
// Give a nice message if there is no tool with that name.
|
||||
if _, err := os.Stat(toolPath); err != nil {
|
||||
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 {
|
||||
fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
|
||||
}
|
||||
|
@ -91,16 +91,6 @@ func runTool(cmd *Command, args []string) {
|
|||
if toolPath == "" {
|
||||
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 {
|
||||
fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " "))
|
||||
return
|
||||
|
|
|
@ -33,6 +33,9 @@ type vcsCmd struct {
|
|||
|
||||
scheme []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
|
||||
|
@ -81,8 +84,17 @@ var vcsHg = &vcsCmd{
|
|||
tagSyncCmd: "update -r {tag}",
|
||||
tagSyncDefault: "update default",
|
||||
|
||||
scheme: []string{"https", "http", "ssh"},
|
||||
pingCmd: "identify {scheme}://{repo}",
|
||||
scheme: []string{"https", "http", "ssh"},
|
||||
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.
|
||||
|
@ -104,8 +116,38 @@ var vcsGit = &vcsCmd{
|
|||
tagSyncCmd: "checkout {tag}",
|
||||
tagSyncDefault: "checkout master",
|
||||
|
||||
scheme: []string{"git", "https", "http", "git+ssh"},
|
||||
pingCmd: "ls-remote {scheme}://{repo}",
|
||||
scheme: []string{"git", "https", "http", "git+ssh"},
|
||||
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.
|
||||
|
@ -123,8 +165,51 @@ var vcsBzr = &vcsCmd{
|
|||
tagSyncCmd: "update -r {tag}",
|
||||
tagSyncDefault: "update -r revno:-1",
|
||||
|
||||
scheme: []string{"https", "http", "bzr", "bzr+ssh"},
|
||||
pingCmd: "info {scheme}://{repo}",
|
||||
scheme: []string{"https", "http", "bzr", "bzr+ssh"},
|
||||
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.
|
||||
|
@ -138,8 +223,34 @@ var vcsSvn = &vcsCmd{
|
|||
// There is no tag command in subversion.
|
||||
// The branch information is all in the path names.
|
||||
|
||||
scheme: []string{"https", "http", "svn", "svn+ssh"},
|
||||
pingCmd: "info {scheme}://{repo}",
|
||||
scheme: []string{"https", "http", "svn", "svn+ssh"},
|
||||
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 {
|
||||
|
@ -361,7 +472,14 @@ var httpPrefixRE = regexp.MustCompile(`^https?:`)
|
|||
func repoRootForImportPath(importPath string) (*repoRoot, error) {
|
||||
rr, err := repoRootForImportPathStatic(importPath, "")
|
||||
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
|
||||
// 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) {
|
||||
slash := strings.Index(importPath, "/")
|
||||
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]
|
||||
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)
|
||||
if err != nil {
|
||||
|
@ -613,6 +731,15 @@ var vcsPaths = []*vcsPath{
|
|||
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.
|
||||
{
|
||||
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
|
||||
|
||||
import "path/filepath"
|
||||
|
||||
func init() {
|
||||
addBuildFlagsNX(cmdVet)
|
||||
}
|
||||
|
@ -15,7 +17,7 @@ var cmdVet = &Command{
|
|||
Long: `
|
||||
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'.
|
||||
|
||||
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) {
|
||||
for _, pkg := range packages(args) {
|
||||
// Use pkg.gofiles instead of pkg.Dir so that
|
||||
// the command only applies to this package,
|
||||
// not to packages in subdirectories.
|
||||
run(tool("vet"), relPaths(stringList(pkg.gofiles, pkg.sfiles)))
|
||||
for _, p := range packages(args) {
|
||||
// Vet expects to be given a set of files all from the same package.
|
||||
// Run once for package p and once for package p_test.
|
||||
if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 {
|
||||
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:
|
||||
|
||||
gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src/pkg
|
||||
gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src
|
||||
|
||||
The simplify command
|
||||
|
||||
|
|
|
@ -87,13 +87,13 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
|
|||
return err
|
||||
}
|
||||
|
||||
file, adjust, err := parse(fileSet, filename, src, stdin)
|
||||
file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if rewrite != nil {
|
||||
if adjust == nil {
|
||||
if sourceAdj == nil {
|
||||
file = rewrite(file)
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(&buf, fileSet, file)
|
||||
res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
res := buf.Bytes()
|
||||
if adjust != nil {
|
||||
res = adjust(src, res)
|
||||
}
|
||||
|
||||
if !bytes.Equal(src, res) {
|
||||
// formatting has changed
|
||||
|
@ -122,7 +117,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
|
|||
fmt.Fprintln(out, filename)
|
||||
}
|
||||
if *write {
|
||||
err = ioutil.WriteFile(filename, res, 0)
|
||||
err = ioutil.WriteFile(filename, res, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -186,6 +181,11 @@ func gofmtMain() {
|
|||
initRewrite()
|
||||
|
||||
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 {
|
||||
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.
|
||||
func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.File, func(orig, src []byte) []byte, error) {
|
||||
// ----------------------------------------------------------------------------
|
||||
// Support functions
|
||||
//
|
||||
// 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.
|
||||
file, err := parser.ParseFile(fset, filename, src, parserMode)
|
||||
if err == nil {
|
||||
return file, nil, nil
|
||||
}
|
||||
// If the error is that the source file didn't begin with a
|
||||
// package line and this is standard input, fall through to
|
||||
file, err = parser.ParseFile(fset, filename, src, parserMode)
|
||||
// If there's no error, return. If the error is that the source file didn't begin with a
|
||||
// package line and source fragments are ok, fall through to
|
||||
// try as a source fragment. Stop and return on any other error.
|
||||
if !stdin || !strings.Contains(err.Error(), "expected 'package'") {
|
||||
return nil, nil, err
|
||||
if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
|
||||
return
|
||||
}
|
||||
|
||||
// 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...)
|
||||
file, err = parser.ParseFile(fset, filename, psrc, parserMode)
|
||||
if err == nil {
|
||||
adjust := func(orig, src []byte) []byte {
|
||||
sourceAdj = func(src []byte, indent int) []byte {
|
||||
// Remove the package clause.
|
||||
// Gofmt has turned the ; into a \n.
|
||||
src = src[len("package p\n"):]
|
||||
return matchSpace(orig, src)
|
||||
src = src[indent+len("package p\n"):]
|
||||
return bytes.TrimSpace(src)
|
||||
}
|
||||
return file, adjust, nil
|
||||
return
|
||||
}
|
||||
// If the error is that the source file didn't begin with a
|
||||
// declaration, fall through to try as a statement list.
|
||||
// Stop and return on any other error.
|
||||
if !strings.Contains(err.Error(), "expected declaration") {
|
||||
return nil, nil, err
|
||||
return
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Insert using a ;, not a newline, so that the line numbers
|
||||
// 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)
|
||||
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.
|
||||
// Gofmt has turned the ; into a \n\n.
|
||||
src = src[len("package p\n\nfunc _() {"):]
|
||||
src = src[:len(src)-len("}\n")]
|
||||
// Gofmt has also indented the function body one level.
|
||||
// Remove that indent.
|
||||
src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1)
|
||||
return matchSpace(orig, src)
|
||||
// There will be two non-blank lines with indent, hence 2*indent.
|
||||
src = src[2*indent+len("package p\n\nfunc _() {"):]
|
||||
src = src[:len(src)-(indent+len("\n}\n"))]
|
||||
return bytes.TrimSpace(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.
|
||||
return nil, nil, err
|
||||
// Succeeded, or out of options.
|
||||
return
|
||||
}
|
||||
|
||||
func cutSpace(b []byte) (before, middle, after []byte) {
|
||||
i := 0
|
||||
for i < len(b) && (b[i] == ' ' || b[i] == '\t' || b[i] == '\n') {
|
||||
i++
|
||||
// format formats the given package file originally obtained from src
|
||||
// and adjusts the result based on the original source via sourceAdj
|
||||
// and indentAdj.
|
||||
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') {
|
||||
j--
|
||||
|
||||
// Partial source file.
|
||||
// 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 {
|
||||
return b[:i], b[i:j], b[j:]
|
||||
var res []byte
|
||||
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.
|
||||
// 1) If orig begins with blank lines, matchSpace inserts them at the beginning of src.
|
||||
// 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()
|
||||
func isSpace(b byte) bool {
|
||||
return b == ' ' || b == '\t' || b == '\n' || b == '\r'
|
||||
}
|
||||
|
|
|
@ -6,18 +6,60 @@ package main
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"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
|
||||
*simplifyAST = false
|
||||
*rewriteRule = ""
|
||||
stdin := false
|
||||
for _, flag := range strings.Split(flags, " ") {
|
||||
for _, flag := range strings.Split(gofmtFlags(in, 20), " ") {
|
||||
elts := strings.SplitN(flag, "=", 2)
|
||||
name := elts[0]
|
||||
value := ""
|
||||
|
@ -56,6 +98,17 @@ func runTest(t *testing.T, in, out, flags string) {
|
|||
}
|
||||
|
||||
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)
|
||||
d, err := diff(expected, got)
|
||||
if err == nil {
|
||||
|
@ -67,51 +120,37 @@ func runTest(t *testing.T, in, out, flags string) {
|
|||
}
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
in, flags string
|
||||
}{
|
||||
{"gofmt.go", ""},
|
||||
{"gofmt_test.go", ""},
|
||||
{"testdata/composites.input", "-s"},
|
||||
{"testdata/slices1.input", "-s"},
|
||||
{"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
|
||||
}
|
||||
|
||||
// TestRewrite processes testdata/*.input files and compares them to the
|
||||
// corresponding testdata/*.golden files. The gofmt flags used to process
|
||||
// a file must be provided via a comment of the form
|
||||
//
|
||||
// //gofmt flags
|
||||
//
|
||||
// in the processed file within the first 20 lines, if any.
|
||||
func TestRewrite(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
match, err := filepath.Glob(test.in)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
// determine input files
|
||||
match, err := filepath.Glob("testdata/*.input")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
out := in
|
||||
if strings.HasSuffix(in, ".input") {
|
||||
out = in[:len(in)-len(".input")] + ".golden"
|
||||
}
|
||||
runTest(t, in, out, test.flags)
|
||||
if in != out {
|
||||
// Check idempotence.
|
||||
runTest(t, out, out, test.flags)
|
||||
}
|
||||
runTest(t, in, out)
|
||||
if in != out {
|
||||
// Check idempotence.
|
||||
runTest(t, out, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test case for issue 3961.
|
||||
func TestCRLF(t *testing.T) {
|
||||
const input = "testdata/crlf.input" // must contain CR/LF'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 {
|
||||
f, _, err := parse(fset, filename, src.Bytes(), false)
|
||||
f, _, _, err := parse(fset, filename, src.Bytes(), false)
|
||||
if err != nil {
|
||||
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)
|
||||
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 {
|
||||
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
|
||||
|
||||
case reflect.Struct:
|
||||
if p.NumField() != v.NumField() {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < p.NumField(); i++ {
|
||||
if !match(m, p.Field(i), v.Field(i)) {
|
||||
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)]
|
||||
// can be simplified to: s[a:]
|
||||
// if s is "simple enough" (for now we only accept identifiers)
|
||||
if s.hasDotImport {
|
||||
// if dot imports are present, we cannot be certain that an
|
||||
// unresolved "len" identifier refers to the predefined len()
|
||||
if n.Max != nil || s.hasDotImport {
|
||||
// - 3-index slices always require the 2nd and 3rd index
|
||||
// - if dot imports are present, we cannot be certain that an
|
||||
// unresolved "len" identifier refers to the predefined len()
|
||||
break
|
||||
}
|
||||
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:]
|
||||
|
||||
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 {...}
|
||||
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
|
||||
}
|
||||
if isBlank(n.Key) && n.Value == nil {
|
||||
n.Key = nil
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func isBlank(x ast.Expr) bool {
|
||||
ident, ok := x.(*ast.Ident)
|
||||
return ok && ident.Name == "_"
|
||||
}
|
||||
|
||||
func simplify(f *ast.File) {
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
type T struct {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -s
|
||||
|
||||
package P
|
||||
|
||||
type T struct {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Source containing CR/LF line endings.
|
||||
The gofmt'ed output must only have LF
|
||||
line endings.
|
||||
Test case for issue 3961.
|
||||
*/
|
||||
package main
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Source containing CR/LF line endings.
|
||||
The gofmt'ed output must only have LF
|
||||
line endings.
|
||||
Test case for issue 3961.
|
||||
*/
|
||||
package main
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=Foo->Bar
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=Foo->Bar
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=int->bool
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=int->bool
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=x->x
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=x->x
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=(x)->x
|
||||
|
||||
// Copyright 2012 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=(x)->x
|
||||
|
||||
// Copyright 2012 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=x+x->2*x
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=x+x->2*x
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=fun(x)->Fun(x)
|
||||
|
||||
// Copyright 2013 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=fun(x)->Fun(x)
|
||||
|
||||
// Copyright 2013 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=fun(x...)->Fun(x)
|
||||
|
||||
// Copyright 2013 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=fun(x...)->Fun(x)
|
||||
|
||||
// Copyright 2013 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=interface{}->int
|
||||
|
||||
// Copyright 2013 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -r=interface{}->int
|
||||
|
||||
// Copyright 2013 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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -s
|
||||
|
||||
// Test cases for slice expression simplification.
|
||||
package p
|
||||
|
||||
|
@ -15,6 +17,7 @@ var (
|
|||
_ = a[3:(len(a))]
|
||||
_ = a[len(a) : len(a)-1]
|
||||
_ = a[0:len(b)]
|
||||
_ = a[2:len(a):len(a)]
|
||||
|
||||
_ = a[:]
|
||||
_ = a[:10]
|
||||
|
@ -22,6 +25,7 @@ var (
|
|||
_ = a[:(len(a))]
|
||||
_ = a[:len(a)-1]
|
||||
_ = a[:len(b)]
|
||||
_ = a[:len(a):len(a)]
|
||||
|
||||
_ = s[0:]
|
||||
_ = s[1:10]
|
||||
|
@ -29,6 +33,7 @@ var (
|
|||
_ = s[3:(len(s))]
|
||||
_ = s[len(a) : len(s)-1]
|
||||
_ = s[0:len(b)]
|
||||
_ = s[2:len(s):len(s)]
|
||||
|
||||
_ = s[:]
|
||||
_ = s[:10]
|
||||
|
@ -36,6 +41,7 @@ var (
|
|||
_ = s[:(len(s))]
|
||||
_ = s[:len(s)-1]
|
||||
_ = s[:len(b)]
|
||||
_ = s[:len(s):len(s)]
|
||||
|
||||
_ = t.s[0:]
|
||||
_ = t.s[1:10]
|
||||
|
@ -43,6 +49,7 @@ var (
|
|||
_ = t.s[3:(len(t.s))]
|
||||
_ = t.s[len(a) : len(t.s)-1]
|
||||
_ = t.s[0:len(b)]
|
||||
_ = t.s[2:len(t.s):len(t.s)]
|
||||
|
||||
_ = t.s[:]
|
||||
_ = t.s[:10]
|
||||
|
@ -50,6 +57,7 @@ var (
|
|||
_ = t.s[:(len(t.s))]
|
||||
_ = t.s[:len(t.s)-1]
|
||||
_ = t.s[:len(b)]
|
||||
_ = t.s[:len(t.s):len(t.s)]
|
||||
)
|
||||
|
||||
func _() {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -s
|
||||
|
||||
// Test cases for slice expression simplification.
|
||||
package p
|
||||
|
||||
|
@ -15,6 +17,7 @@ var (
|
|||
_ = a[3:(len(a))]
|
||||
_ = a[len(a) : len(a)-1]
|
||||
_ = a[0:len(b)]
|
||||
_ = a[2:len(a):len(a)]
|
||||
|
||||
_ = a[:]
|
||||
_ = a[:10]
|
||||
|
@ -22,6 +25,7 @@ var (
|
|||
_ = a[:(len(a))]
|
||||
_ = a[:len(a)-1]
|
||||
_ = a[:len(b)]
|
||||
_ = a[:len(a):len(a)]
|
||||
|
||||
_ = s[0:]
|
||||
_ = s[1:10]
|
||||
|
@ -29,6 +33,7 @@ var (
|
|||
_ = s[3:(len(s))]
|
||||
_ = s[len(a) : len(s)-1]
|
||||
_ = s[0:len(b)]
|
||||
_ = s[2:len(s):len(s)]
|
||||
|
||||
_ = s[:]
|
||||
_ = s[:10]
|
||||
|
@ -36,6 +41,7 @@ var (
|
|||
_ = s[:(len(s))]
|
||||
_ = s[:len(s)-1]
|
||||
_ = s[:len(b)]
|
||||
_ = s[:len(s):len(s)]
|
||||
|
||||
_ = t.s[0:]
|
||||
_ = t.s[1:10]
|
||||
|
@ -43,6 +49,7 @@ var (
|
|||
_ = t.s[3:(len(t.s))]
|
||||
_ = t.s[len(a) : len(t.s)-1]
|
||||
_ = t.s[0:len(b)]
|
||||
_ = t.s[2:len(t.s):len(t.s)]
|
||||
|
||||
_ = t.s[:]
|
||||
_ = t.s[:10]
|
||||
|
@ -50,6 +57,7 @@ var (
|
|||
_ = t.s[:(len(t.s))]
|
||||
_ = t.s[:len(t.s)-1]
|
||||
_ = t.s[:len(b)]
|
||||
_ = t.s[:len(t.s):len(t.s)]
|
||||
)
|
||||
|
||||
func _() {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//gofmt -s
|
||||
|
||||
// Test cases for slice expression simplification.
|
||||
// Because of a dot import, these slices must remain untouched.
|
||||
package p
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue