mirror of
https://gcc.gnu.org/git/gcc.git
synced 2025-01-22 20:36:20 +08:00
libgo, compiler: Upgrade libgo to Go 1.4, except for runtime.
This upgrades all of libgo other than the runtime package to the Go 1.4 release. In Go 1.4 much of the runtime was rewritten into Go. Merging that code will take more time and will not change the API, so I'm putting it off for now. There are a few runtime changes anyhow, to accomodate other packages that rely on minor modifications to the runtime support. The compiler changes slightly to add a one-bit flag to each type descriptor kind that is stored directly in an interface, which for gccgo is currently only pointer types. Another one-bit flag (gcprog) is reserved because it is used by the gc compiler, but gccgo does not currently use it. There is another error check in the compiler since I ran across it during testing. gotools/: * Makefile.am (go_cmd_go_files): Sort entries. Add generate.go. * Makefile.in: Rebuild. From-SVN: r219627
This commit is contained in:
parent
6bd3f109d8
commit
f8d9fa9e80
@ -15559,7 +15559,7 @@ bool
|
||||
Numeric_constant::set_type(Type* type, bool issue_error, Location loc)
|
||||
{
|
||||
bool ret;
|
||||
if (type == NULL)
|
||||
if (type == NULL || type->is_error())
|
||||
ret = true;
|
||||
else if (type->integer_type() != NULL)
|
||||
ret = this->check_int_type(type->integer_type(), issue_error, loc);
|
||||
|
@ -1966,6 +1966,8 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
|
||||
|
||||
if (!this->has_pointer())
|
||||
runtime_type_kind |= RUNTIME_TYPE_KIND_NO_POINTERS;
|
||||
if (this->points_to() != NULL)
|
||||
runtime_type_kind |= RUNTIME_TYPE_KIND_DIRECT_IFACE;
|
||||
Struct_field_list::const_iterator p = fields->begin();
|
||||
go_assert(p->is_field_name("kind"));
|
||||
vals->push_back(Expression::make_integer_ul(runtime_type_kind, p->type(),
|
||||
|
@ -81,6 +81,8 @@ static const int RUNTIME_TYPE_KIND_STRING = 24;
|
||||
static const int RUNTIME_TYPE_KIND_STRUCT = 25;
|
||||
static const int RUNTIME_TYPE_KIND_UNSAFE_POINTER = 26;
|
||||
|
||||
static const int RUNTIME_TYPE_KIND_DIRECT_IFACE = (1 << 5);
|
||||
static const int RUNTIME_TYPE_KIND_GC_PROG = (1 << 6);
|
||||
static const int RUNTIME_TYPE_KIND_NO_POINTERS = (1 << 7);
|
||||
|
||||
// GC instruction opcodes. These must match the values in libgo/runtime/mgc0.h.
|
||||
|
@ -1,3 +1,8 @@
|
||||
2015-01-14 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* Makefile.am (go_cmd_go_files): Sort entries. Add generate.go.
|
||||
* Makefile.in: Rebuild.
|
||||
|
||||
2015-01-09 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* Makefile.am (GOCOMPILER): Set to GOC or GOC_FOR_TARGET depending
|
||||
|
@ -46,27 +46,28 @@ cmdsrcdir = $(srcdir)/../libgo/go/cmd
|
||||
go_cmd_go_files = \
|
||||
$(cmdsrcdir)/go/build.go \
|
||||
$(cmdsrcdir)/go/clean.go \
|
||||
$(cmdsrcdir)/go/main.go \
|
||||
$(cmdsrcdir)/go/signal.go \
|
||||
$(cmdsrcdir)/go/version.go \
|
||||
$(cmdsrcdir)/go/env.go \
|
||||
$(cmdsrcdir)/go/help.go \
|
||||
$(cmdsrcdir)/go/run.go \
|
||||
$(cmdsrcdir)/go/tool.go \
|
||||
$(cmdsrcdir)/go/vet.go \
|
||||
$(cmdsrcdir)/go/context.go \
|
||||
$(cmdsrcdir)/go/fix.go \
|
||||
$(cmdsrcdir)/go/get.go \
|
||||
$(cmdsrcdir)/go/http.go \
|
||||
$(cmdsrcdir)/go/signal_unix.go \
|
||||
$(cmdsrcdir)/go/vcs.go \
|
||||
$(cmdsrcdir)/go/discovery.go \
|
||||
$(cmdsrcdir)/go/env.go \
|
||||
$(cmdsrcdir)/go/fix.go \
|
||||
$(cmdsrcdir)/go/fmt.go \
|
||||
$(cmdsrcdir)/go/generate.go \
|
||||
$(cmdsrcdir)/go/get.go \
|
||||
$(cmdsrcdir)/go/go11.go \
|
||||
$(cmdsrcdir)/go/help.go \
|
||||
$(cmdsrcdir)/go/http.go \
|
||||
$(cmdsrcdir)/go/list.go \
|
||||
$(cmdsrcdir)/go/main.go \
|
||||
$(cmdsrcdir)/go/pkg.go \
|
||||
$(cmdsrcdir)/go/run.go \
|
||||
$(cmdsrcdir)/go/signal.go \
|
||||
$(cmdsrcdir)/go/signal_unix.go \
|
||||
$(cmdsrcdir)/go/test.go \
|
||||
$(cmdsrcdir)/go/testflag.go
|
||||
$(cmdsrcdir)/go/testflag.go \
|
||||
$(cmdsrcdir)/go/tool.go \
|
||||
$(cmdsrcdir)/go/vcs.go \
|
||||
$(cmdsrcdir)/go/version.go \
|
||||
$(cmdsrcdir)/go/vet.go
|
||||
|
||||
go_cmd_gofmt_files = \
|
||||
$(cmdsrcdir)/gofmt/doc.go \
|
||||
|
@ -211,27 +211,28 @@ cmdsrcdir = $(srcdir)/../libgo/go/cmd
|
||||
go_cmd_go_files = \
|
||||
$(cmdsrcdir)/go/build.go \
|
||||
$(cmdsrcdir)/go/clean.go \
|
||||
$(cmdsrcdir)/go/main.go \
|
||||
$(cmdsrcdir)/go/signal.go \
|
||||
$(cmdsrcdir)/go/version.go \
|
||||
$(cmdsrcdir)/go/env.go \
|
||||
$(cmdsrcdir)/go/help.go \
|
||||
$(cmdsrcdir)/go/run.go \
|
||||
$(cmdsrcdir)/go/tool.go \
|
||||
$(cmdsrcdir)/go/vet.go \
|
||||
$(cmdsrcdir)/go/context.go \
|
||||
$(cmdsrcdir)/go/fix.go \
|
||||
$(cmdsrcdir)/go/get.go \
|
||||
$(cmdsrcdir)/go/http.go \
|
||||
$(cmdsrcdir)/go/signal_unix.go \
|
||||
$(cmdsrcdir)/go/vcs.go \
|
||||
$(cmdsrcdir)/go/discovery.go \
|
||||
$(cmdsrcdir)/go/env.go \
|
||||
$(cmdsrcdir)/go/fix.go \
|
||||
$(cmdsrcdir)/go/fmt.go \
|
||||
$(cmdsrcdir)/go/generate.go \
|
||||
$(cmdsrcdir)/go/get.go \
|
||||
$(cmdsrcdir)/go/go11.go \
|
||||
$(cmdsrcdir)/go/help.go \
|
||||
$(cmdsrcdir)/go/http.go \
|
||||
$(cmdsrcdir)/go/list.go \
|
||||
$(cmdsrcdir)/go/main.go \
|
||||
$(cmdsrcdir)/go/pkg.go \
|
||||
$(cmdsrcdir)/go/run.go \
|
||||
$(cmdsrcdir)/go/signal.go \
|
||||
$(cmdsrcdir)/go/signal_unix.go \
|
||||
$(cmdsrcdir)/go/test.go \
|
||||
$(cmdsrcdir)/go/testflag.go
|
||||
$(cmdsrcdir)/go/testflag.go \
|
||||
$(cmdsrcdir)/go/tool.go \
|
||||
$(cmdsrcdir)/go/vcs.go \
|
||||
$(cmdsrcdir)/go/version.go \
|
||||
$(cmdsrcdir)/go/vet.go
|
||||
|
||||
go_cmd_gofmt_files = \
|
||||
$(cmdsrcdir)/gofmt/doc.go \
|
||||
|
@ -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
|
||||
@ -761,9 +762,6 @@ else
|
||||
if LIBGO_IS_DARWIN
|
||||
go_net_tcpsockopt_file = go/net/tcpsockopt_darwin.go
|
||||
else
|
||||
if LIBGO_IS_SOLARIS
|
||||
go_net_tcpsockopt_file = go/net/tcpsockopt_solaris.go
|
||||
else
|
||||
if LIBGO_IS_DRAGONFLY
|
||||
go_net_tcpsockopt_file = go/net/tcpsockopt_dragonfly.go
|
||||
else
|
||||
@ -771,7 +769,6 @@ go_net_tcpsockopt_file = go/net/tcpsockopt_unix.go
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
go_net_files = \
|
||||
go/net/cgo_unix.go \
|
||||
@ -997,7 +994,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 +1183,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 +1294,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 +1459,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 +1502,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 +1541,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 +1577,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 +1792,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 +1976,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 +1985,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 +3181,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 +3290,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 +3394,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 +3663,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 +3695,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
|
||||
@ -3774,6 +3820,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
|
||||
@ -1017,9 +1019,8 @@ go_mime_files = \
|
||||
@LIBGO_IS_LINUX_TRUE@go_net_interface_file = go/net/interface_linux.go
|
||||
@LIBGO_IS_LINUX_FALSE@go_net_cloexec_file = go/net/sys_cloexec.go
|
||||
@LIBGO_IS_LINUX_TRUE@go_net_cloexec_file = go/net/sock_cloexec.go
|
||||
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_unix.go
|
||||
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_dragonfly.go
|
||||
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_tcpsockopt_file = go/net/tcpsockopt_solaris.go
|
||||
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_OPENBSD_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_unix.go
|
||||
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_OPENBSD_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_dragonfly.go
|
||||
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_OPENBSD_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_darwin.go
|
||||
@LIBGO_IS_OPENBSD_TRUE@go_net_tcpsockopt_file = go/net/tcpsockopt_openbsd.go
|
||||
go_net_files = \
|
||||
@ -1180,7 +1181,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 +1348,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 +1472,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 +1654,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 +1706,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 +1743,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 +1782,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 +1926,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 +2045,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 +2054,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 +2186,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 = \
|
||||
@ -2279,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 \
|
||||
@ -2515,6 +2534,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@
|
||||
@ -3031,6 +3051,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
|
||||
@ -5498,6 +5525,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)
|
||||
@ -5698,6 +5734,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
|
||||
@ -5953,6 +5998,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)
|
||||
|
||||
@ -5982,6 +6030,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
|
||||
|
||||
|
2
libgo/configure
vendored
2
libgo/configure
vendored
@ -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"
|
||||
|
@ -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
|
||||
|
398
libgo/go/cmd/go/generate.go
Normal file
398
libgo/go/cmd/go/generate.go
Normal file
@ -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)
|
||||
}
|
||||
}
|
48
libgo/go/cmd/go/generate_test.go
Normal file
48
libgo/go/cmd/go/generate_test.go
Normal file
@ -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.
|
||||
|
55
libgo/go/cmd/go/go_windows_test.go
Normal file
55
libgo/go/cmd/go/go_windows_test.go
Normal file
@ -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}}
|
||||
}
|
||||
|
||||
`))
|
||||
|
13
libgo/go/cmd/go/testdata/generate/test1.go
vendored
Normal file
13
libgo/go/cmd/go/testdata/generate/test1.go
vendored
Normal file
@ -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
|
10
libgo/go/cmd/go/testdata/generate/test2.go
vendored
Normal file
10
libgo/go/cmd/go/testdata/generate/test2.go
vendored
Normal file
@ -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
|
9
libgo/go/cmd/go/testdata/generate/test3.go
vendored
Normal file
9
libgo/go/cmd/go/testdata/generate/test3.go
vendored
Normal file
@ -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
|
3
libgo/go/cmd/go/testdata/importcom/bad.go
vendored
Normal file
3
libgo/go/cmd/go/testdata/importcom/bad.go
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package p
|
||||
|
||||
import "bad"
|
3
libgo/go/cmd/go/testdata/importcom/conflict.go
vendored
Normal file
3
libgo/go/cmd/go/testdata/importcom/conflict.go
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package p
|
||||
|
||||
import "conflict"
|
1
libgo/go/cmd/go/testdata/importcom/src/bad/bad.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/importcom/src/bad/bad.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package bad // import
|
1
libgo/go/cmd/go/testdata/importcom/src/conflict/a.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/importcom/src/conflict/a.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package conflict // import "a"
|
1
libgo/go/cmd/go/testdata/importcom/src/conflict/b.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/importcom/src/conflict/b.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package conflict /* import "b" */
|
1
libgo/go/cmd/go/testdata/importcom/src/works/x/x.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/importcom/src/works/x/x.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package x // import "works/x"
|
1
libgo/go/cmd/go/testdata/importcom/src/works/x/x1.go
vendored
Normal file
1
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
libgo/go/cmd/go/testdata/importcom/src/wrongplace/x.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/importcom/src/wrongplace/x.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package x // import "my/x"
|
3
libgo/go/cmd/go/testdata/importcom/works.go
vendored
Normal file
3
libgo/go/cmd/go/testdata/importcom/works.go
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package p
|
||||
|
||||
import _ "works/x"
|
3
libgo/go/cmd/go/testdata/importcom/wrongplace.go
vendored
Normal file
3
libgo/go/cmd/go/testdata/importcom/wrongplace.go
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package p
|
||||
|
||||
import "wrongplace"
|
11
libgo/go/cmd/go/testdata/norunexample/example_test.go
vendored
Normal file
11
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
libgo/go/cmd/go/testdata/norunexample/test_test.go
vendored
Normal file
10
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"))
|
||||
}
|
1
libgo/go/cmd/go/testdata/src/badc/x.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/src/badc/x.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package badc
|
5
libgo/go/cmd/go/testdata/src/badtest/badexec/x_test.go
vendored
Normal file
5
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
libgo/go/cmd/go/testdata/src/badtest/badsyntax/x.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/src/badtest/badsyntax/x.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package badsyntax
|
3
libgo/go/cmd/go/testdata/src/badtest/badsyntax/x_test.go
vendored
Normal file
3
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!
|
1
libgo/go/cmd/go/testdata/src/badtest/badvar/x.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/src/badtest/badvar/x.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package badvar
|
5
libgo/go/cmd/go/testdata/src/badtest/badvar/x_test.go
vendored
Normal file
5
libgo/go/cmd/go/testdata/src/badtest/badvar/x_test.go
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
package badvar_test
|
||||
|
||||
func f() {
|
||||
_ = notdefined
|
||||
}
|
1
libgo/go/cmd/go/testdata/src/vetpkg/a_test.go
vendored
Normal file
1
libgo/go/cmd/go/testdata/src/vetpkg/a_test.go
vendored
Normal file
@ -0,0 +1 @@
|
||||
package p_test
|
7
libgo/go/cmd/go/testdata/src/vetpkg/b.go
vendored
Normal file
7
libgo/go/cmd/go/testdata/src/vetpkg/b.go
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
package p
|
||||
|
||||
import "fmt"
|
||||
|
||||
func f() {
|
||||
fmt.Printf("%d")
|
||||
}
|
3
libgo/go/cmd/go/testdata/testinternal/p.go
vendored
Normal file
3
libgo/go/cmd/go/testdata/testinternal/p.go
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package p
|
||||
|
||||
import _ "net/http/internal"
|
3
libgo/go/cmd/go/testdata/testinternal2/p.go
vendored
Normal file
3
libgo/go/cmd/go/testdata/testinternal2/p.go
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package p
|
||||
|
||||
import _ "./x/y/z/internal/w"
|
1
libgo/go/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go
vendored
Normal file
1
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
|
||||
|
21
libgo/go/cmd/go/testgo.go
Normal file
21
libgo/go/cmd/go/testgo.go
Normal file
@ -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_.\-]+)*$`,
|
||||
|
124
libgo/go/cmd/go/vcs_test.go
Normal file
124
libgo/go/cmd/go/vcs_test.go
Normal file
@ -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 {
|
||||
|
2
libgo/go/cmd/gofmt/testdata/composites.input
vendored
2
libgo/go/cmd/gofmt/testdata/composites.input
vendored
@ -1,3 +1,5 @@
|
||||
//gofmt -s
|
||||
|
||||
package P
|
||||
|
||||
type T struct {
|
||||
|
1
libgo/go/cmd/gofmt/testdata/crlf.golden
vendored
1
libgo/go/cmd/gofmt/testdata/crlf.golden
vendored
@ -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
libgo/go/cmd/gofmt/testdata/crlf.input
vendored
1
libgo/go/cmd/gofmt/testdata/crlf.input
vendored
@ -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
libgo/go/cmd/gofmt/testdata/rewrite1.golden
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite1.golden
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite1.input
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite1.input
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite2.golden
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite2.golden
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite2.input
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite2.input
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite3.golden
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite3.golden
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite3.input
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite3.input
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite4.golden
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite4.golden
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite4.input
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite4.input
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite5.golden
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite5.golden
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite5.input
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite5.input
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite6.golden
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite6.golden
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite6.input
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite6.input
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite7.golden
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite7.golden
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite7.input
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite7.input
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite8.golden
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite8.golden
vendored
@ -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.
|
||||
|
2
libgo/go/cmd/gofmt/testdata/rewrite8.input
vendored
2
libgo/go/cmd/gofmt/testdata/rewrite8.input
vendored
@ -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.
|
||||
|
8
libgo/go/cmd/gofmt/testdata/slices1.golden
vendored
8
libgo/go/cmd/gofmt/testdata/slices1.golden
vendored
@ -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 _() {
|
||||
|
8
libgo/go/cmd/gofmt/testdata/slices1.input
vendored
8
libgo/go/cmd/gofmt/testdata/slices1.input
vendored
@ -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 _() {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user