This commit replaces the existing ad-hoc package loader with a package
loader that uses the x/tools/go/packages package to find all
to-be-loaded packages.
This commit changes the way that packages are looked up. Instead of
working around the loader package by modifying the GOROOT variable for
specific packages, create a new GOROOT using symlinks. This GOROOT is
cached for the specified configuration (Go version, underlying GOROOT
path, TinyGo path, whether to override the syscall package).
This will also enable go module support in the future.
Windows is a bit harder to support, because it only allows the creation
of symlinks when developer mode is enabled. This is worked around by
using symlinks and if that fails, using directory junctions or hardlinks
instead. This should work in the vast majority of cases. The only case
it doesn't work, is if developer mode is disabled and TinyGo, the Go
toolchain, and the cache directory are not all on the same filesystem.
If this is a problem, it is still possible to improve the code by using
file copies instead.
As a side effect, this also makes diagnostics use a relative file path
only when the file is not in GOROOT or in TINYGOROOT.
This commit also adds a bit of version independence, in particular for
external commands. It also adds the LLVM version to the `tinygo version`
command, which might help while debugging.
Add location information (whenever possible) to failed imports. This
helps in debugging where an incorrect import came from.
For example, show the following error message:
/home/ayke/src/github.com/tinygo-org/tinygo/src/machine/machine.go:5:8: cannot find package "foobar" in any of:
/usr/local/go/src/foobar (from $GOROOT)
/home/ayke/src/foobar (from $GOPATH)
Instead of the following:
error: cannot find package "foobar" in any of:
/usr/local/go/src/foobar (from $GOROOT)
/home/ayke/src/foobar (from $GOPATH)
This allows importing (for example) both
"github.com/tinygo-org/tinygo/src/machine" and "machine" without issues.
The former is renamed to just "machine".
This is a big commit that does a few things:
* It moves CGo processing into a separate package. It never really
belonged in the loader package, and certainly not now that the
loader package may be refactored into a driver package.
* It adds support for multiple CGo files (files that import package
"C") in a single package. Previously, this led to multiple
definition errors in the Go typecheck phase because certain C
symbols were defined multiple times in all the files. Now it
generates a new fake AST that defines these, to avoid multiple
definition errors.
* It improves debug info in a few edge cases that are probably not
relevant outside of bugs in cgo itself.
Check various locations that $GOROOT may live, including the location of
the go binary. But make it possible to override this autodetection by
setting GOROOT manually as an environment variable.
Only try to convert the C symbols to their Go equivalents that are
actually referenced by the Go code with C.<somesymbol>. This avoids
having to support all possible C types, which is difficult because of
oddities like `typedef void` or `__builtin_va_list`. Especially
__builtin_va_list, which varies between targets.
Every ABI has a slightly different implementation. Ideally, we would use
something like Clang TargetInfo or extract it by compiling some C code
and checking the IR, but this is a useful workaround for now.
These types (called elaborated types in C) are used as part of linked
lists, among others.
This is part an extra feature (to be compatible with CGo C.struct_
types) and part a bugfix: linked lists would result in endless recursion
leading to a stack overflow.
Sometimes when a GC happens while processing a C fragment with libclang,
a pointer-typed integer with value 0x1 ends up on the Go stack and the
GC will trip over it. This commit changes the offending struct type to
be uintptr_t instead of void*.
See https://go-review.googlesource.com/c/go/+/66332 for a similar
change.
Unions are somewhat hard to implement in Go because they are not a
native type. But it is actually possible with some compiler magic.
This commit inserts a special "C union" field at the start of a struct
to indicate that it is a union. As such a field cannot be written
directly in Go, this is a useful to distinguish structs and unions.
This makes CGo-emitted diagnostics very similar to regular errors
emitted while parsing/typechecking a package.
It's not complete, but after introducing some errors in testdata/cgo,
this is the resulting output:
# ./testdata/cgo/
testdata/cgo/main.h:18:11: error: a parameter list without types is only allowed in a function definition
testdata/cgo/main.go:5:10: note: in file included from testdata/cgo/main.go!cgo.c:2:
testdata/cgo/main.go:6:19: error: expected identifier or '('
Previously, this was the output:
/home/ayke/src/github.com/tinygo-org/tinygo/testdata/cgo/main.h:18:11: error: a parameter list without types is only allowed in a function definition
cgo-fake.c:3:19: error: expected identifier or '('
# ./testdata/cgo/
cgo: libclang cannot parse fragment
So far, we've pretended to be js/wasm in baremetal targets to make the
stdlib happy. Unfortunately, this has various problems because
syscall/js (a dependency of many stdlib packages) thinks it can do JS
calls, and emulating them gets quite hard with all changes to the
syscall/js packages in Go 1.12.
This commit does a few things:
* It lets baremetal targets pretend to be linux/arm instead of
js/wasm.
* It lets the loader only select particular packages from the src
overlay, instead of inserting them just before GOROOT. This makes it
possible to pick which packages to overlay for a given target.
* It adds a baremetal-only syscall package that stubs out almost all
syscalls.
The magic CGo construct to turn a C array into a slice turned out to be
not portable.
Note: this is not the only problem, there is also a bug in the Go
bindings for LLVM. With that one fixed, it is possible to build TinyGo
on a Raspberry Pi (32-bit).