ebitengine / purego Goto Github PK
View Code? Open in Web Editor NEWLicense: Apache License 2.0
License: Apache License 2.0
https://github.com/ebitengine/purego/blob/test/example/main.go
The test bot builds the above main package like below:
go build -v ./...
And this failed at least on Linux like this:
https://github.com/ebitengine/purego/runs/8276795548
# github.com/ebitengine/purego/example
2022/09/09 18:57:24 duplicated definition of symbol _cgo_init
I think this is a minimal reproducible case of hajimehoshi/ebiten#2313: just building a main package with purego with Cgo enabled.
Do: CGO_ENABLED=0 gotip run -race ./example/main.go
and receive signal: segmentation fault
.
Go 1.20 rewrote the race detector to not require a C compiler on macOS. That's exciting! However, it break fakecgo. :(
The issue occurs in calling x_cgo_init
from x_cgo_init_trampoline
because it adds a bunch of calls to race functions. These race functions are not allowed in this Go code pretending to be C. Adding //go:norace
does work in removing the race calls in the function itself but since we are calling this function from assembly it goes through the ABI0
stub which still has the race code despite the comment. Ugh
TEXT github.com/ebitengine/purego/internal/fakecgo.x_cgo_init(SB)
0x10f2400 4881ec98000000 SUBQ $0x98, SP
0x10f2407 4889ac2490000000 MOVQ BP, 0x90(SP)
0x10f240f 488dac2490000000 LEAQ 0x90(SP), BP
0x10f2417 48898424a0000000 MOVQ AX, 0xa0(SP)
0x10f241f 48899c24a8000000 MOVQ BX, 0xa8(SP)
0x10f2427 488b842498000000 MOVQ 0x98(SP), AX
0x10f242f 4889442420 MOVQ AX, 0x20(SP)
0x10f2434 e8278ffcff CALL runtime.racefuncenter(SB)
0x10f2439 48c744241000000000 MOVQ $0x0, 0x10(SP)
0x10f2442 440f117c2428 MOVUPS X15, 0x28(SP)
0x10f2448 440f117c2438 MOVUPS X15, 0x38(SP)
0x10f244e 440f117c2448 MOVUPS X15, 0x48(SP)
0x10f2454 440f117c2458 MOVUPS X15, 0x58(SP)
0x10f245a 488b8c24a8000000 MOVQ 0xa8(SP), CX
0x10f2462 48894c2418 MOVQ CX, 0x18(SP)
0x10f2467 488d0552a51100 LEAQ github.com/ebitengine/purego/internal/fakecgo.setg_func(SB), AX
0x10f246e e84d7afcff CALL runtime.racewrite(SB)
0x10f2473 488b4c2418 MOVQ 0x18(SP), CX
0x10f2478 48890d41a51100 MOVQ CX, github.com/ebitengine/purego/internal/fakecgo.setg_func(SB)
0x10f247f 488d442428 LEAQ 0x28(SP), AX
0x10f2484 4889842480000000 MOVQ AX, 0x80(SP)
0x10f248c e86f090000 CALL github.com/ebitengine/purego/internal/fakecgo.pthread_attr_init(SB)
0x10f2491 488d4c2428 LEAQ 0x28(SP), CX
0x10f2496 48894c2478 MOVQ CX, 0x78(SP)
0x10f249b 488d5c2410 LEAQ 0x10(SP), BX
0x10f24a0 48895c2470 MOVQ BX, 0x70(SP)
0x10f24a5 488b442478 MOVQ 0x78(SP), AX
0x10f24aa e8910e0000 CALL github.com/ebitengine/purego/internal/fakecgo.pthread_attr_getstacksize(SB)
0x10f24af 488b8424a0000000 MOVQ 0xa0(SP), AX
0x10f24b7 4889842488000000 MOVQ AX, 0x88(SP)
0x10f24bf 8400 TESTB AL, 0(AX)
0x10f24c1 488d4c2410 LEAQ 0x10(SP), CX
0x10f24c6 482b4c2410 SUBQ 0x10(SP), CX
0x10f24cb 48894c2418 MOVQ CX, 0x18(SP)
0x10f24d0 e8eb79fcff CALL runtime.racewrite(SB)
0x10f24d5 488b4c2418 MOVQ 0x18(SP), CX
0x10f24da 4881c100100000 ADDQ $0x1000, CX
0x10f24e1 488b942488000000 MOVQ 0x88(SP), DX
0x10f24e9 48890a MOVQ CX, 0(DX)
0x10f24ec 488d442428 LEAQ 0x28(SP), AX
0x10f24f1 4889442468 MOVQ AX, 0x68(SP)
0x10f24f6 e8a50f0000 CALL github.com/ebitengine/purego/internal/fakecgo.pthread_attr_destroy(SB)
0x10f24fb 0f1f440000 NOPL 0(AX)(AX*1)
0x10f2500 e89b8efcff CALL runtime.racefuncexit(SB)
0x10f2505 488bac2490000000 MOVQ 0x90(SP), BP
0x10f250d 4881c498000000 ADDQ $0x98, SP
0x10f2514 c3 RET
If this was in the runtime we could just call the function as ABIInternal and save all the hassle. The only solution I can currently think of is to compile the runtime/cgo
version and then convert that to go assembly similar to c2goasm.
@hajimehoshi do you think we should petition that CALL ยทx_cgo_init<ABIInternal>(SB)
be allowed outside the runtime? Even if it means we have to be careful about calling convention. Or perhaps, it's more likely that //go:norace
should also affect the ABI0 stubs? It might be a bug none the less so that might be more likely to be approved.
Full repro here.
Given the following C function exported via a linux shared library:
unsigned long FuncKO(unsigned long input1, char* input2,
unsigned long* input2Len, unsigned long* input3,
unsigned long* input4, unsigned char* input5, unsigned long* input5Len)
{
unsigned long rv = 0;
if (input2Len)
LogToFile("/var/tmp/so_sample.log", "IN : input2Len=%ld\n", *input2Len);
if (input5Len)
LogToFile("/var/tmp/so_sample.log", "IN : input5Len=%ld\n", *input5Len);
if (input3)
*input3 = 0;
if (input4)
*input4 = 0;
if (input2Len)
*input2Len = 32;
if (input5Len)
*input5Len = 32;
if (input3)
*input3 = 1;
if (input4)
*input4 = 1;
if (input2Len)
LogToFile("/var/tmp/so_sample.log", "OUT: input2Len=%ld\n", *input2Len);
if (input5Len)
LogToFile("/var/tmp/so_sample.log", "OUT: input5Len=%ld\n", *input5Len);
return rv;
}
And given the following equivalent Golang type definition (which I hope is correct):
type FuncKO func(
input1 uint32,
input2 *byte,
input2Len *uint32,
input3 *uint32,
input4 *uint32,
input5 *byte,
input5Len *uint32,
) uint32
Calling the C function from Go using the aforementioned type definition with purego does not set input5Len
to 32 as expected, it stays 0
.
var input1 uint32
var input2Len uint32
var imput3 uint32
var imput4 uint32
var input5Len uint32
r := funcKOProc(
input1,
nil,
&input2Len,
&imput3,
&imput4,
nil,
&input5Len,
)
fmt.Printf("=== FuncKO (nil)\n")
fmt.Printf("r = %d\n", r)
fmt.Printf("input2Len = %d\n", input2Len)
fmt.Printf("imput3 = %d\n", imput3)
fmt.Printf("imput4 = %d\n", imput4)
fmt.Printf("input5Len = %d\n\n", input5Len)
Output:
=== FuncKO (nil)
r = 0
input2Len = 32
imput3 = 1
imput4 = 1
input5Len = 0
If we look at the C function logs, we find the following:
$ cat /var/tmp/so_sample.log
IN: input2Len=0
IN: input5Len=0
OUT: input2Len=4294967328
OUT: input5Len=0
Notice input2Len
being set to 4294967328
in C, but still holding 32
in Go, and input5Len
value not changing.
If we run a sample C program that loads the same shared library and calls the same function, we get the following:
r = 0
input2Len = 32
imput3 = 1
imput4 = 1
input5Len = 32
and the C function logs show:
$ cat /var/tmp/so_sample.log
IN: input2Len=0
IN: input5Len=0
OUT: input2Len=32
OUT: input5Len=32
which is the expected behavior.
I'm not sure what could be causing this ? Maybe there is a corruption somewhere ?
Now RegisterClass
is available only for structs without member variables. If a struct had member variables, memory corruption might happen (examples/objc
uses RegisterClass
for a struct with a member variable, but this is a known issue).
As @TotallyGamerJet and Hajime discussed on Ebitengine Discord, would it be possible giving up mirroring member variables in the Go world to the Objective-C world? This makes the Objective-C struct size predictable and then memory corruption would no longer happen. Unfortunately, this would be a breaking change since GetIvar
and SetIvar
no longer works for Go member variables. However, the current major version is still 0, Hajime is fine to have such a breaking change.
Currently, a struct with members can use AllocateClassPair
, AddMethod
, and AddIvar
, but this is quite painful. RegisterClass
cares all of them, which is pretty nice.
I am finding that its not possible to build static binaries with the purego linked in and CGO disabled.
Trying to use an external linker causes relocation and symbol lookup errors.
Is it possible to eliminate the linkages to libc, libpthread, libdl, etc... either through a musl CC or other techniques?
Now building internal/fakecgo
for Windows fails since internal/fakecgo
cannot be built for Windows.
$ env GOOS=windows GOARCH=amd64 go build -v ./...
github.com/ebitengine/purego/internal/fakecgo
# github.com/ebitengine/purego/internal/fakecgo
internal/fakecgo/go_util.go:29:2: undefined: _cgo_sys_thread_start
This is a little inconvenient since I cannot use ./...
for Windows. Would it be fine to add darwin
for the fakecgo
package?
Is Windows O.S. support planned ?
Running the output from a compile crashes on startup:
$ ./s2c
Segmentation fault (core dumped)
$ gdb ./s2c
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1
[...]
(gdb) r
Starting program: /home/user1/cmd/s2c/s2c
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7e2a540 in _int_malloc (av=av@entry=0x7ffff7f9fc80 <main_arena>, bytes=bytes@entry=640) at ./malloc/malloc.c:4375
4375 ./malloc/malloc.c: No such file or directory.
(gdb) where
#0 0x00007ffff7e2a540 in _int_malloc (av=av@entry=0x7ffff7f9fc80 <main_arena>, bytes=bytes@entry=640)
at ./malloc/malloc.c:4375
#1 0x00007ffff7e2aa49 in tcache_init () at ./malloc/malloc.c:3245
#2 0x00007ffff7e2b25e in tcache_init () at ./malloc/malloc.c:3241
#3 __GI___libc_malloc (bytes=64) at ./malloc/malloc.c:3306
#4 0x0000000000657942 in github.com/ebitengine/purego/internal/fakecgo.call5 ()
at e:/gopath/pkg/mod/github.com/ebitengine/[email protected]/internal/fakecgo/trampolines_linux_amd64.s:72
#5 0x000000000065744c in github.com/ebitengine/purego/internal/fakecgo.malloc (size=<optimized out>)
at e:/gopath/pkg/mod/github.com/ebitengine/[email protected]/internal/fakecgo/symbols.go:25
#6 github.com/ebitengine/purego/internal/fakecgo.x_cgo_init (g=0x7ffff7f9fce0 <main_arena+96>, setg=6650208)
at e:/gopath/pkg/mod/github.com/ebitengine/[email protected]/internal/fakecgo/go_linux_amd64.go:81
#7 0x0000000000657b8a in github.com/ebitengine/purego/internal/fakecgo.x_cgo_init (g=0x8e7340 <runtime.g0>,
setg=4612384) at <autogenerated>:1
#8 0x00000000006577bc in x_cgo_init_trampoline ()
at e:/gopath/pkg/mod/github.com/ebitengine/[email protected]/internal/fakecgo/trampolines_linux_amd64.s:29
#9 0x0000000000466d11 in runtime.rt0_go () at c:/go/src/runtime/asm_amd64.s:220
#10 0x0000000000000000 in ?? ()
Version 0.3.0 crashes as well:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7e2a540 in _int_malloc (av=av@entry=0x7ffff7f9fc80 <main_arena>, bytes=bytes@entry=640) at ./malloc/malloc.c:4375
4375 ./malloc/malloc.c: No such file or directory.
(gdb) where
#0 0x00007ffff7e2a540 in _int_malloc (av=av@entry=0x7ffff7f9fc80 <main_arena>, bytes=bytes@entry=640)
at ./malloc/malloc.c:4375
#1 0x00007ffff7e2aa49 in tcache_init () at ./malloc/malloc.c:3245
#2 0x00007ffff7e2b25e in tcache_init () at ./malloc/malloc.c:3241
#3 __GI___libc_malloc (bytes=64) at ./malloc/malloc.c:3306
#4 0x000000000065dee2 in github.com/ebitengine/purego/internal/fakecgo.call5 ()
at e:/gopath/pkg/mod/github.com/ebitengine/[email protected]/internal/fakecgo/trampolines_linux_amd64.s:72
#5 0x000000000065d9ec in github.com/ebitengine/purego/internal/fakecgo.malloc (size=<optimized out>)
at e:/gopath/pkg/mod/github.com/ebitengine/[email protected]/internal/fakecgo/symbols.go:25
#6 github.com/ebitengine/purego/internal/fakecgo.x_cgo_init (g=0x7ffff7f9fce0 <main_arena+96>, setg=6676224)
at e:/gopath/pkg/mod/github.com/ebitengine/[email protected]/internal/fakecgo/go_linux_amd64.go:81
#7 0x000000000065e12a in github.com/ebitengine/purego/internal/fakecgo.x_cgo_init (g=0x8f5dc0 <runtime.g0>,
setg=4615808) at <autogenerated>:1
#8 0x000000000065dd5c in x_cgo_init_trampoline ()
at e:/gopath/pkg/mod/github.com/ebitengine/[email protected]/internal/fakecgo/trampolines_linux_amd64.s:29
#9 0x0000000000467a71 in runtime.rt0_go () at c:/go/src/runtime/asm_amd64.s:220
#10 0x0000000000000000 in ?? ()
Go versions tested (for compile):
ฮป go version
go version go1.19.5 windows/amd64
ฮป SET GOOS=linux
ฮป go build .
or
ฮป go version
go version go1.20.1 windows/amd64
ฮป SET GOOS=linux
ฮป go build .
All crash on startup.
The source has a comment about a special case for variadic functions -
// There is a special case when the last argument of fptr is a variadic interface (or []interface}
// it will be expanded into a call to the C function as if it had the arguments in that slice.
// This means that using arg ...interface{} is like a cast to the function with the arguments inside arg.
// This is not the same as C variadic.
Does this mean they are not supported? I made my own library in C and am unable to find a way to get my function to see any of the variadic parameters.
void printSomething(int a, const char *fmt, ...)
{
va_list ap;
printf("start %d\n", a);
printf("fmt %s\n", fmt);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n");
printf("end %d\n", a);
}
Calling code:
var printSomething func(int, string, []interface{})
purego.RegisterLibFunc(&printSomething, libcraig, `printSomething`)
printSomething(5, `%s`, []interface{}{`foo`})
This prints:
start 5
fmt %s
(null)
end 5
This is on MacOS 13.5 / Intel (16" MacBook 2019). I have tried some of my ebiten applications, ebiten tests and purego tests and example. They all seem to fail here:
raff|main:purego$ go run examples/objc/main_darwin.go
SIGSEGV: segmentation violation
PC=0x7ff800864b62 m=0 sigcode=1
signal arrived during cgo execution
goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x10cbd80, 0xc0000b2000)
/usr/local/go/src/runtime/cgocall.go:157 +0x4b fp=0xc0000ab4b0 sp=0xc0000ab478 pc=0x1007b2b
github.com/ebitengine/purego.RegisterFunc.func1({0xc00009c3c0?, 0x2?, 0x2?})
/Users/rsena/go/src/github.com/ebitengine/purego/func.go:212 +0xa25 fp=0xc0000ab820 sp=0xc0000ab4b0 pc=0x10cab05
reflect.callReflect(0xc00009c1b0, 0xc0000abd88, 0xc0000abc60, 0xc0000abc68)
/usr/local/go/src/reflect/value.go:782 +0x54c fp=0xc0000abc10 sp=0xc0000ab820 pc=0x1085c0c
reflect.callReflect(0xc00009c1b0, 0xc0000abd88, 0xc0000abc60, 0xc0000abc68)
:1 +0x45 fp=0xc0000abc40 sp=0xc0000abc10 pc=0x1095a05
reflect.makeFuncStub()
/usr/local/go/src/reflect/asm_amd64.s:47 +0x6e fp=0xc0000abd88 sp=0xc0000abc40 pc=0x1091d8e
github.com/ebitengine/purego.Dlopen({0x10fb7b0?, 0x10dafe0?}, 0x11d5348?)
/Users/rsena/go/src/github.com/ebitengine/purego/dlfcn.go:37 +0x1f fp=0xc0000abdc0 sp=0xc0000abd88 pc=0x10c9b3f
github.com/ebitengine/purego/objc.init.0()
/Users/rsena/go/src/github.com/ebitengine/purego/objc/objc_runtime_darwin.go:41 +0x28 fp=0xc0000abe10 sp=0xc0000abdc0 pc=0x10ce6c8
runtime.doInit1(0x11ca600)
/usr/local/go/src/runtime/proc.go:6739 +0xd8 fp=0xc0000abf40 sp=0xc0000abe10 pc=0x10449d8
runtime.doInit(...)
/usr/local/go/src/runtime/proc.go:6706
runtime.main()
/usr/local/go/src/runtime/proc.go:249 +0x374 fp=0xc0000abfe0 sp=0xc0000abf40 pc=0x1037ab4
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:1650 +0x1 fp=0xc0000abfe8 sp=0xc0000abfe0 pc=0x1063661
According to opensource.apple.com RTLD_DEFAULT
is defined as #define RTLD_DEFAULT ((void *) -2)
. In purego I wrote const RTLD_DEFAULT = ^uintptr(1)
which is not the same binary representation.
This is a bug in version 0.1.0 and should be corrected to something like const RTLD_DEFAULT = uintptr(0x8000000000000002)
.
Secondly, I think we should remove this constant from purego 0.2.0 since it is not used in purego, Oto or Ebitengine and is darwin specific. See the Unix specification.
I would like to use this for cross-platform development, and use purego where supported, but keep code compiling on all platforms.
However most functions, like Dlopen(...)
aren't available for Windows, which is fair enough, but I would need to guard all code with build tags.
In these cases it is very nice to have stubs available, so code compiles, but just returns errors:
var ErrUnsupported = errors.New("purego not available on this platform")
func Dlopen(path string, mode int) (uintptr, error) {
return 0, ErrUnsupported
}
func Dlclose(handle uintptr) error {
return ErrUnsupported
}
func Dlsym(handle uintptr, name string) (uintptr, error) {
return 0, ErrUnsupported
}
// etc
For my projects this would mean a lot less code duplication. I don't really see any significant downside to adding stubs.
@TotallyGamerJet I plan to move this repository to ebitengine/purego as the game engine's name is now Ebitengine. Please let me know if you are ready or not.
Should we backport this commit to 1.0 since it's the only tagged version and this bug can cause issues? 382f4c6
Hello,
I got a segmentation fault on WSL running Ubuntu 22.04 LTS when compiling the example with Go 1.20.1 using the latest available version v0.2.0-alpha.1.0.20230213042757-086b819e2f9a
.
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/mo/.cache/go-build"
GOENV="/home/mo/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/mo/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/mo/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.20.1"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="0"
GOMOD="/mnt/c/Users/MrGol/Projects/expermients/Go/purego/go.mod"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build3406589635=/tmp/go-build -gno-record-gcc-switches"
package main
import (
"fmt"
"runtime"
"github.com/ebitengine/purego"
)
func getSystemLibrary() string {
switch runtime.GOOS {
case "darwin":
return "/usr/lib/libSystem.B.dylib"
case "linux":
return "libc.so.6"
default:
panic(fmt.Errorf("GOOS=%s is not supported", runtime.GOOS))
}
}
func main() {
libc := purego.Dlopen(getSystemLibrary(), purego.RTLD_NOW|purego.RTLD_GLOBAL)
if err := purego.Dlerror(); err != "" {
panic(err)
}
var puts func(string)
purego.RegisterLibFunc(&puts, libc, "puts")
puts("Calling C from Go without Cgo!")
}
Command used to compile
CGO_ENABLED=0 go build .
Output
Segmentation fault
Starting program: /mnt/c/Users/MrGol/Projects/expermients/Go/purego/xpr-purego
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7e28540 in _int_malloc (av=av@entry=0x7ffff7f9dc80 <main_arena>, bytes=bytes@entry=640) at ./malloc/malloc.c:4375
4375 ./malloc/malloc.c: No such file or directory.
https://developer.apple.com/documentation/appkit/nscursor/1524612-initwithimage
Currently, passing a struct via Send is not supported, right?
Some SSE instructions have requirements that make the fakecgo package segfault. In my case, the call to malloc
during x_cgo_init
in internal/fakecgo/go_linux_amd64.go
makes use of a movaps
instruction on 0x10(%rsp)
. But since %rsp
was not aligned on 16 bits (as the instruction requires it), the cgo initialization segfaults. Fixing the register manually using gdb does the trick but of course it messes with the stack and segfault laters.
My team and I are really fond and the project and really want it to work on linux so I will probably drop a PR if I find a fix in the following days. If you have a definitive idea on how to fix this or if you want more debug information, please let me know.
I noticed this issue when upgrading Ebiten from 2.3.8 to 2.4.0, however this was the dependency throwing the error. So I hope this is the right place to report this.
Error: # github.com/ebitengine/purego vendor/github.com/ebitengine/purego/sys_darwin_arm64.s:8: #include: open /Users/<redacted>/sdk/go1.19/pkg/include/internal/abi/abi_arm64.h: no such file or directory
Digging further I found that the folder /internal/abi/
didn't exist in my vendored copy but strings
and fakecgo
did. Which led me to this comment that mentions that there needs to be at least one .go file present in a directory in order for all the files to be included during vendoring. I made sure it wasn't a fluke by deleting the vendor folder and starting over but the results were consistent.
There is a work around, I cloned the repo and manually copied it to the vendor folder and the issue resolved (until I vendor again)
This is not an issue that should be addressed now but exists solely to list the pros and cons of dropping support for 1.15.
Pros:
go:embed
&GOOS=iOS
Cons:
I use v0.4.0-alpha.4
for windows, the openLibrary
from example is not public.
Is there a unite public library load method ?
See oto#195 for more information.
I think we should rename _IMP
to an exported one. @TotallyGamerJet what do you think?
It would be better if Dlerror()
returned errors, rather than strings as it does now. That would allow users to check errors using a nil check, rather than an empty string check, as well as allow them to return an error from purego
as an error
type from their own function. It would also provide the ability to wrap purego
errors, such as with %w
in fmt.Errorf()
, as well as with the new functions added in Go 1.20, such as errors.Join()
.
Dlerror()
could simply use errors.New()
to create a new error with the given string, but I feel it would be even better to define a custom error type that just returns a string. That way, the type information tells the caller that the error came from purego
.
This would look something like:
type Error struct {
s string
}
func (e Error) Error() string {
return e.s
}
If this seems like a good idea, I could submit a PR to implement it.
[Question] : Does it work under Windows (with DLLs)?
To get this working just add the variable and check for any other Cgo related changes in runtime/cgo.
CGO_ENABLED=0 go test ./...
? github.com/ebitengine/purego/cmd [no test files]
? github.com/ebitengine/purego/examples/libc [no test files]
? github.com/ebitengine/purego/examples/objc [no test files]
? github.com/ebitengine/purego/internal/fakecgo [no test files]
? github.com/ebitengine/purego/internal/strings [no test files]
fatal error: _cgo_pthread_key_created missing
goroutine 1 [running, locked to thread]:
runtime.throw({0x1029ad194?, 0x0?})
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/panic.go:1077 +0x40 fp=0x14000046730 sp=0x14000046700 pc=0x1028cdcd0
runtime.main()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:213 +0x3fc fp=0x140000467d0 sp=0x14000046730 pc=0x1028d067c
runtime.goexit()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/asm_arm64.s:1197 +0x4 fp=0x140000467d0 sp=0x140000467d0 pc=0x102903204
goroutine 2 [force gc (idle)]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:398 +0xc8 fp=0x14000046f90 sp=0x14000046f70 pc=0x1028d0998
runtime.goparkunlock(...)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:404
runtime.forcegchelper()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:322 +0xb8 fp=0x14000046fd0 sp=0x14000046f90 pc=0x1028d07f8
runtime.goexit()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/asm_arm64.s:1197 +0x4 fp=0x14000046fd0 sp=0x14000046fd0 pc=0x102903204
created by runtime.init.6 in goroutine 1
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:310 +0x24
goroutine 18 [GC sweep wait]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:398 +0xc8 fp=0x14000042760 sp=0x14000042740 pc=0x1028d0998
runtime.goparkunlock(...)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:404
runtime.bgsweep(0x0?)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/mgcsweep.go:280 +0xa0 fp=0x140000427b0 sp=0x14000042760 pc=0x1028bbdc0
runtime.gcenable.func1()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/mgc.go:200 +0x28 fp=0x140000427d0 sp=0x140000427b0 pc=0x1028b0888
runtime.goexit()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/asm_arm64.s:1197 +0x4 fp=0x140000427d0 sp=0x140000427d0 pc=0x102903204
created by runtime.gcenable in goroutine 1
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/mgc.go:200 +0x6c
goroutine 19 [GC scavenge wait]:
runtime.gopark(0x1400008e000?, 0x1029d8668?, 0x1?, 0x0?, 0x140000824e0?)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:398 +0xc8 fp=0x14000042f50 sp=0x14000042f30 pc=0x1028d0998
runtime.goparkunlock(...)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:404
runtime.(*scavengerState).park(0x102aecdc0)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/mgcscavenge.go:425 +0x5c fp=0x14000042f80 sp=0x14000042f50 pc=0x1028b962c
runtime.bgscavenge(0x0?)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/mgcscavenge.go:653 +0x44 fp=0x14000042fb0 sp=0x14000042f80 pc=0x1028b9b84
runtime.gcenable.func2()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/mgc.go:201 +0x28 fp=0x14000042fd0 sp=0x14000042fb0 pc=0x1028b0828
runtime.goexit()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/asm_arm64.s:1197 +0x4 fp=0x14000042fd0 sp=0x14000042fd0 pc=0x102903204
created by runtime.gcenable in goroutine 1
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/mgc.go:201 +0xac
FAIL github.com/ebitengine/purego 0.265s
fatal error: _cgo_pthread_key_created missing
goroutine 1 [running, locked to thread]:
runtime.throw({0x1029d4a08?, 0x0?})
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/panic.go:1077 +0x40 fp=0x14000046730 sp=0x14000046700 pc=0x1029057b0
runtime.main()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:213 +0x3fc fp=0x140000467d0 sp=0x14000046730 pc=0x10290815c
runtime.goexit()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/asm_arm64.s:1197 +0x4 fp=0x140000467d0 sp=0x140000467d0 pc=0x1029394d4
goroutine 2 [force gc (idle)]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:398 +0xc8 fp=0x14000046f90 sp=0x14000046f70 pc=0x102908478
runtime.goparkunlock(...)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:404
runtime.forcegchelper()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:322 +0xb8 fp=0x14000046fd0 sp=0x14000046f90 pc=0x1029082d8
runtime.goexit()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/asm_arm64.s:1197 +0x4 fp=0x14000046fd0 sp=0x14000046fd0 pc=0x1029394d4
created by runtime.init.6 in goroutine 1
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:310 +0x24
goroutine 3 [GC sweep wait]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:398 +0xc8 fp=0x14000047760 sp=0x14000047740 pc=0x102908478
runtime.goparkunlock(...)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:404
runtime.bgsweep(0x0?)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/mgcsweep.go:280 +0xa0 fp=0x140000477b0 sp=0x14000047760 pc=0x1028f38a0
runtime.gcenable.func1()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/mgc.go:200 +0x28 fp=0x140000477d0 sp=0x140000477b0 pc=0x1028e8368
runtime.goexit()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/asm_arm64.s:1197 +0x4 fp=0x140000477d0 sp=0x140000477d0 pc=0x1029394d4
created by runtime.gcenable in goroutine 1
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/mgc.go:200 +0x6c
goroutine 4 [GC scavenge wait]:
runtime.gopark(0x14000078000?, 0x1029fd770?, 0x1?, 0x0?, 0x14000003520?)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:398 +0xc8 fp=0x14000047f50 sp=0x14000047f30 pc=0x102908478
runtime.goparkunlock(...)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/proc.go:404
runtime.(*scavengerState).park(0x102b08a00)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/mgcscavenge.go:425 +0x5c fp=0x14000047f80 sp=0x14000047f50 pc=0x1028f110c
runtime.bgscavenge(0x0?)
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/mgcscavenge.go:653 +0x44 fp=0x14000047fb0 sp=0x14000047f80 pc=0x1028f1664
runtime.gcenable.func2()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/mgc.go:201 +0x28 fp=0x14000047fd0 sp=0x14000047fb0 pc=0x1028e8308
runtime.goexit()
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/asm_arm64.s:1197 +0x4 fp=0x14000047fd0 sp=0x14000047fd0 pc=0x1029394d4
created by runtime.gcenable in goroutine 1
/Users/jarrettkuklis/go/go1.21rc2/src/runtime/mgc.go:201 +0xac
FAIL github.com/ebitengine/purego/objc 0.340s
FAIL
Hello,
I noticed that in dlopen
and dlsym
in dlfcn.go
, the return value is never checked against nil. Is there a reason for this ? This blocks the use of any call to dlopen or any similar function in the static initialization of the library loaded. In the end, if the inner call fails, the dlerror value set by the inner call would make the top call fail.
Do tell me if you need more precisions or if you want me to do a PR or an MRE.
I think this is the same issue as ebitengine/oto#183
$ go1.15.15 test ./...
? github.com/ebitengine/purego [no test files]
? github.com/ebitengine/purego/internal/fakecgo [no test files]
? github.com/ebitengine/purego/internal/strings [no test files]
--- FAIL: ExampleAllocateClassPair (0.00s)
panic: runtime error: index out of range [18056875977166063944] with length 2000 [recovered]
panic: runtime error: index out of range [18056875977166063944] with length 2000
goroutine 1 [running]:
testing.(*InternalExample).processRunResult(0xc00009dd28, 0x0, 0x0, 0xd67a, 0x113f920, 0xc000018420, 0x10144d4)
/Users/hajimehoshi/sdk/go1.15.15/src/testing/example.go:89 +0x648
testing.runExample.func2(0xc0b9b04c927ab680, 0x861ae, 0x1237440, 0xc000010050, 0xc000010018, 0xc000072240, 0xc000051d28, 0xc00009dd58)
/Users/hajimehoshi/sdk/go1.15.15/src/testing/run_example.go:58 +0x10d
panic(0x113f920, 0xc000018420)
/Users/hajimehoshi/sdk/go1.15.15/src/runtime/panic.go:969 +0x1b9
github.com/ebitengine/purego.callbackWrap(0x110fb60)
/Users/hajimehoshi/purego/syscall_darwin.go:102 +0x50f
github.com/ebitengine/purego.syscall_syscall9X(0x7ff80afe3400, 0x600000004090, 0x7ff825565129, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/hajimehoshi/purego/syscall_darwin.go:20 +0x128
github.com/ebitengine/purego.SyscallN(0x7ff80afe3400, 0xc00001a1e0, 0x2, 0x2, 0x0, 0xc00001a1e0, 0x2)
/Users/hajimehoshi/purego/syscall.go:37 +0x11e
github.com/ebitengine/purego/objc.ID.Send(0x600000004090, 0x7ff825565129, 0x0, 0x0, 0x0, 0x0)
/Users/hajimehoshi/purego/objc/objc_runtime_darwin.go:52 +0xb7
github.com/ebitengine/purego/objc_test.ExampleAllocateClassPair()
/Users/hajimehoshi/purego/objc/objc_runtime_darwin_test.go:22 +0x1b3
testing.runExample(0x1152cb4, 0x18, 0x1158988, 0x11503b1, 0xd, 0x0, 0x0)
/Users/hajimehoshi/sdk/go1.15.15/src/testing/run_example.go:62 +0x209
testing.runExamples(0xc00009ded0, 0x1233f80, 0x4, 0x4, 0xc0b9b0e292792428)
/Users/hajimehoshi/sdk/go1.15.15/src/testing/example.go:44 +0x1af
testing.(*M).Run(0xc00011a000, 0x0)
/Users/hajimehoshi/sdk/go1.15.15/src/testing/testing.go:1346 +0x273
main.main()
_testmain.go:51 +0x138
FAIL github.com/ebitengine/purego/objc 0.130s
FAIL
$ go1.16.15 test ./...
? github.com/ebitengine/purego [no test files]
? github.com/ebitengine/purego/internal/fakecgo [no test files]
? github.com/ebitengine/purego/internal/strings [no test files]
--- FAIL: ExampleAllocateClassPair (0.00s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x2 pc=0x110edf4]
goroutine 1 [running]:
testing.(*InternalExample).processRunResult(0xc00010fd58, 0x0, 0x0, 0x16e10, 0x20300000000000, 0x112c280, 0x1229dc0, 0x1529200)
/Users/hajimehoshi/sdk/go1.16.15/src/testing/example.go:91 +0x69b
testing.runExample.func2(0xc0b9b06081eed3c8, 0x948ba, 0x1231ec0, 0xc000010050, 0xc000010018, 0xc000074240, 0xc00010fd58, 0xc00010fcb6, 0xc00010fd88)
/Users/hajimehoshi/sdk/go1.16.15/src/testing/run_example.go:59 +0x11c
panic(0x112c280, 0x1229dc0)
/Users/hajimehoshi/sdk/go1.16.15/src/runtime/panic.go:965 +0x1b9
github.com/ebitengine/purego.callbackWrap(0x2)
/Users/hajimehoshi/purego/syscall_darwin.go:102 +0x54
github.com/ebitengine/purego.syscall_syscall9X(0x7ff80afe3400, 0x600000008040, 0x7ff825565129, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/hajimehoshi/purego/syscall_darwin.go:20 +0x128
github.com/ebitengine/purego.SyscallN(0x7ff80afe3400, 0xc00001a1f0, 0x2, 0x2, 0x0, 0xc00001a1f0, 0x2)
/Users/hajimehoshi/purego/syscall.go:37 +0x11e
github.com/ebitengine/purego/objc.ID.Send(0x600000008040, 0x7ff825565129, 0x0, 0x0, 0x0, 0x0)
/Users/hajimehoshi/purego/objc/objc_runtime_darwin.go:52 +0xb7
github.com/ebitengine/purego/objc_test.ExampleAllocateClassPair()
/Users/hajimehoshi/purego/objc/objc_runtime_darwin_test.go:22 +0x1b3
testing.runExample(0x1152bba, 0x18, 0x11588f8, 0x115025e, 0xd, 0x0, 0x0)
/Users/hajimehoshi/sdk/go1.16.15/src/testing/run_example.go:63 +0x222
testing.runExamples(0xc00010fed0, 0x122e780, 0x4, 0x4, 0xc0b9b0f681ed4940)
/Users/hajimehoshi/sdk/go1.16.15/src/testing/example.go:44 +0x17a
testing.(*M).Run(0xc000126000, 0x0)
/Users/hajimehoshi/sdk/go1.16.15/src/testing/testing.go:1428 +0x273
main.main()
_testmain.go:51 +0x138
FAIL github.com/ebitengine/purego/objc 0.123s
FAIL
Hello,
I thought I would try using purego to interface with macOS's unified logging framework. However I've hit a snag.
The unified logger uses a set of macros like os_log_debug
that ultimately call _os_log_internal
. This is exported by libSystem.B.dylib - so far so good. However, the first argument to that function is &__dso_handle
, which is defined in C headers as
extern struct mach_header __dso_handle;
I'm not sure how to resolve this symbol. It's not exported by libSystem.B.dylib, but rather it's specific to the running executable. I don't understand this fully, but I've read that it's actually dynamically generated by the linker.
Is there a way to reference this symbol with purego, or is this not possible?
Hi team ๐ Awesome job on this! I'm looking to port a decent amount of Cocoa based Objective-C code to purego so am happy to put in some serious time for testing and contributing. I'm currently stuck with where to start. If anyone can point me to a simple example of spinning up the equivalent of this code, then I should be able to get going and provide feedback:
package main
/*
#cgo CFLAGS: -mmacosx-version-min=10.13 -x objective-c
#cgo LDFLAGS: -framework AppKit -mmacosx-version-min=10.13
#import <AppKit/AppKit.h>
void start() {
[NSApplication sharedApplication];
[NSApp run];
}
*/
import "C"
func main() {
C.start()
}
I gave it a shot but couldn't determine the right approach from the examples. Here's my initial attempt:
package main
import (
"github.com/ebitengine/purego"
"github.com/ebitengine/purego/objc"
)
var (
class_NSApplication = objc.GetClass("NSApplication")
class_NSApp = objc.GetClass("NSApp")
sel_sharedApplication = objc.RegisterName("sharedApplication")
sel_run = objc.RegisterName("run")
)
func main() {
_, err := purego.Dlopen("/System/Library/Frameworks/AppKit.framework/AppKit", purego.RTLD_LAZY|purego.RTLD_GLOBAL)
if err != nil {
panic(err)
}
objc.ID(class_NSApplication).Send(sel_sharedApplication)
objc.ID(class_NSApp).Send(sel_run)
}
Looks like the main runloop isn't executed and the application exits immediately.
Many thanks for your work on this - it's awesome!
Greetings ๐, we encoutered this error:
$ git clone https://github.com/DataDog/go-libddwaf && cd go-libddwaf
[...]
$ go test -count=2000 -run 'TestWafObject'
dyld[98255]: could not create thread local variables pthread key
SIGABRT: abort
PC=0x1a8d6d118 m=16 sigcode=0
signal arrived during cgo execution
[...]
This happens on Mac M1 and go 1.20.5 and 1.21rc3 with cgo enabled and disabled but it does not happens on linux and it happens in the latest version of purego but also on the previous one. I did not manage to reproduce it in a test (yet) but this is very likely related to something else: as you can see I put the -count=2000
for a lot dlopen calls happens so the error happens, but even from the second call to dlopen some wierd behaviours starts to happens, like calls to new
in C++ throwing std::bad_alloc
. We avoided those wierd behaviour but this error stops us from doing more dlopen calls. Could the TLS be badly setup ? Or do you think the OSX dyld is going astray ?
goroutine 365100 [syscall]:
runtime.cgocall(0x100be24c0, 0x140003733f0)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/cgocall.go:157 +0x44 fp=0x140006bb4d0 sp=0x140006bb490 pc=0x100a43714
github.com/ebitengine/purego.RegisterFunc.func1({0x1400080f0e0?, 0x2?, 0x2?})
/Users/eliott.bouhana/go/pkg/mod/github.com/ebitengine/[email protected]/func.go:212 +0x788 fp=0x140006bb850 sp=0x140006bb4d0 pc=0x100be1178
reflect.callReflect(0x1400007a330, 0x140006bbe38, 0x140006bbc98, 0x140006bbca0)
/Users/eliott.bouhana/go/go1.21rc3/src/reflect/value.go:782 +0x3f4 fp=0x140006bbc40 sp=0x140006bb850 pc=0x100b0f424
reflect.callReflect(0x1400007a330, 0x140005a4e38, 0x140005a4c98, 0x140005a4ca0)
:1 +0x28 fp=0x140006bbc70 sp=0x140006bbc40 pc=0x100b1ed78
reflect.makeFuncStub()
/Users/eliott.bouhana/go/go1.21rc3/src/reflect/asm_arm64.s:48 +0x58 fp=0x140006bbe30 sp=0x140006bbc70 pc=0x100b1ad88
github.com/ebitengine/purego.Dlopen({0x140000240f0?, 0x140001451e0?}, 0x0?)
/Users/eliott.bouhana/go/pkg/mod/github.com/ebitengine/[email protected]/dlfcn.go:37 +0x2c fp=0x140006bbe70 sp=0x140006bbe30 pc=0x100be04bc
github.com/DataDog/go-libddwaf.getLibddwaf(0x6c7829b91d?)
/Users/eliott.bouhana/dd/go-libddwaf/ctypes_test.go:29 +0x114 fp=0x140006bbf00 sp=0x140006bbe70 pc=0x100ccba94
github.com/DataDog/go-libddwaf.TestWafObject(0x0?)
/Users/eliott.bouhana/dd/go-libddwaf/ctypes_test.go:42 +0x20 fp=0x140006bbf60 sp=0x140006bbf00 pc=0x100ccbc30
testing.tRunner(0x140001451e0, 0x100def828)
/Users/eliott.bouhana/go/go1.21rc3/src/testing/testing.go:1595 +0xe8 fp=0x140006bbfb0 sp=0x140006bbf60 pc=0x100b4f528
testing.(*T).Run.func1()
/Users/eliott.bouhana/go/go1.21rc3/src/testing/testing.go:1648 +0x2c fp=0x140006bbfd0 sp=0x140006bbfb0 pc=0x100b5033c
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x140006bbfd0 sp=0x140006bbfd0 pc=0x100aacc74
created by testing.(*T).Run in goroutine 1
/Users/eliott.bouhana/go/go1.21rc3/src/testing/testing.go:1648 +0x33c
goroutine 1 [chan receive]:
runtime.gopark(0x140006bd9b8?, 0x100a4becc?, 0xe8?, 0xe2?, 0x18?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x140006bd940 sp=0x140006bd920 pc=0x100a78978
runtime.chanrecv(0x1400036ae00, 0x140006bda3f, 0x1)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/chan.go:583 +0x414 fp=0x140006bd9c0 sp=0x140006bd940 pc=0x100a45144
runtime.chanrecv1(0x1011289e0?, 0x100d88100?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/chan.go:442 +0x14 fp=0x140006bd9f0 sp=0x140006bd9c0 pc=0x100a44cf4
testing.(*T).Run(0x14000145040, {0x100cdbd3b?, 0x11a78eca6863?}, 0x100def828)
/Users/eliott.bouhana/go/go1.21rc3/src/testing/testing.go:1649 +0x350 fp=0x140006bdab0 sp=0x140006bd9f0 pc=0x100b50200
testing.runTests.func1(0x14000145040?)
/Users/eliott.bouhana/go/go1.21rc3/src/testing/testing.go:2054 +0x48 fp=0x140006bdb00 sp=0x140006bdab0 pc=0x100b52018
testing.tRunner(0x14000145040, 0x140006bdc28)
/Users/eliott.bouhana/go/go1.21rc3/src/testing/testing.go:1595 +0xe8 fp=0x140006bdb50 sp=0x140006bdb00 pc=0x100b4f528
testing.runTests(0x140000a8000?, {0x1011225c0, 0x11, 0x11}, {0x147e355b0?, 0x100a66ac0?, 0x1011290a0?})
/Users/eliott.bouhana/go/go1.21rc3/src/testing/testing.go:2052 +0x3b4 fp=0x140006bdc50 sp=0x140006bdb50 pc=0x100b51f14
testing.(*M).Run(0x140000a8000)
/Users/eliott.bouhana/go/go1.21rc3/src/testing/testing.go:1925 +0x534 fp=0x140006bdea0 sp=0x140006bdc50 pc=0x100b50bf4
main.main()
_testmain.go:81 +0x1a8 fp=0x140006bdf30 sp=0x140006bdea0 pc=0x100cd81e8
runtime.main()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:267 +0x2bc fp=0x140006bdfd0 sp=0x140006bdf30 pc=0x100a7851c
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x140006bdfd0 sp=0x140006bdfd0 pc=0x100aacc74
goroutine 2 [force gc (idle), 2 minutes]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x1400004af90 sp=0x1400004af70 pc=0x100a78978
runtime.goparkunlock(...)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:404
runtime.forcegchelper()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:322 +0xb8 fp=0x1400004afd0 sp=0x1400004af90 pc=0x100a787d8
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x1400004afd0 sp=0x1400004afd0 pc=0x100aacc74
created by runtime.init.6 in goroutine 1
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:310 +0x24
goroutine 3 [GC sweep wait]:
runtime.gopark(0x101128b01?, 0x101128be0?, 0xc?, 0x14?, 0x1?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x1400004b760 sp=0x1400004b740 pc=0x100a78978
runtime.goparkunlock(...)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:404
runtime.bgsweep(0x0?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgcsweep.go:321 +0x108 fp=0x1400004b7b0 sp=0x1400004b760 pc=0x100a63678
runtime.gcenable.func1()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:200 +0x28 fp=0x1400004b7d0 sp=0x1400004b7b0 pc=0x100a580d8
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x1400004b7d0 sp=0x1400004b7d0 pc=0x100aacc74
created by runtime.gcenable in goroutine 1
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:200 +0x6c
goroutine 4 [sleep]:
runtime.gopark(0x140000120a0?, 0x11a7f4d3c3c5?, 0x0?, 0x0?, 0x100def9d0?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x1400004bf10 sp=0x1400004bef0 pc=0x100a78978
runtime.goparkunlock(...)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:404
runtime.(*scavengerState).sleep(0x101129120, 0x410e4b3000000000)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgcscavenge.go:504 +0x128 fp=0x1400004bf80 sp=0x1400004bf10 pc=0x100a61078
runtime.bgscavenge(0x0?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgcscavenge.go:662 +0x9c fp=0x1400004bfb0 sp=0x1400004bf80 pc=0x100a6142c
runtime.gcenable.func2()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:201 +0x28 fp=0x1400004bfd0 sp=0x1400004bfb0 pc=0x100a58078
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x1400004bfd0 sp=0x1400004bfd0 pc=0x100aacc74
created by runtime.gcenable in goroutine 1
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:201 +0xac
goroutine 5 [finalizer wait]:
runtime.gopark(0x0?, 0x100def850?, 0x20?, 0x81?, 0x2000000020?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x1400004a580 sp=0x1400004a560 pc=0x100a78978
runtime.runfinq()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mfinal.go:193 +0x108 fp=0x1400004a7d0 sp=0x1400004a580 pc=0x100a571c8
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x1400004a7d0 sp=0x1400004a7d0 pc=0x100aacc74
created by runtime.createfing in goroutine 1
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mfinal.go:163 +0x80
goroutine 258 [GC worker (idle)]:
runtime.gopark(0x11a78ebbcada?, 0x1400059cf40?, 0x1a?, 0x14?, 0x0?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x140001e9f30 sp=0x140001e9f10 pc=0x100a78978
runtime.gcBgMarkWorker()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1293 +0xd8 fp=0x140001e9fd0 sp=0x140001e9f30 pc=0x100a59d28
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x140001e9fd0 sp=0x140001e9fd0 pc=0x100aacc74
created by runtime.gcBgMarkStartWorkers in goroutine 72
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1217 +0x28
goroutine 259 [GC worker (idle)]:
runtime.gopark(0x11a78ebcb31c?, 0x1?, 0xa7?, 0xed?, 0x0?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x140001def30 sp=0x140001def10 pc=0x100a78978
runtime.gcBgMarkWorker()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1293 +0xd8 fp=0x140001defd0 sp=0x140001def30 pc=0x100a59d28
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x140001defd0 sp=0x140001defd0 pc=0x100aacc74
created by runtime.gcBgMarkStartWorkers in goroutine 72
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1217 +0x28
goroutine 260 [GC worker (idle)]:
runtime.gopark(0x11a78e2039fb?, 0x1?, 0x92?, 0x28?, 0x0?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x140001dcf30 sp=0x140001dcf10 pc=0x100a78978
runtime.gcBgMarkWorker()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1293 +0xd8 fp=0x140001dcfd0 sp=0x140001dcf30 pc=0x100a59d28
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x140001dcfd0 sp=0x140001dcfd0 pc=0x100aacc74
created by runtime.gcBgMarkStartWorkers in goroutine 72
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1217 +0x28
goroutine 274 [GC worker (idle)]:
runtime.gopark(0x11a78e4a65b8?, 0x1?, 0x46?, 0x18?, 0x0?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x1400028e730 sp=0x1400028e710 pc=0x100a78978
runtime.gcBgMarkWorker()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1293 +0xd8 fp=0x1400028e7d0 sp=0x1400028e730 pc=0x100a59d28
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x1400028e7d0 sp=0x1400028e7d0 pc=0x100aacc74
created by runtime.gcBgMarkStartWorkers in goroutine 72
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1217 +0x28
goroutine 261 [GC worker (idle)]:
runtime.gopark(0x10116aca0?, 0x1?, 0x19?, 0x5e?, 0x0?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x14000287730 sp=0x14000287710 pc=0x100a78978
runtime.gcBgMarkWorker()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1293 +0xd8 fp=0x140002877d0 sp=0x14000287730 pc=0x100a59d28
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x140002877d0 sp=0x140002877d0 pc=0x100aacc74
created by runtime.gcBgMarkStartWorkers in goroutine 72
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1217 +0x28
goroutine 290 [GC worker (idle)]:
runtime.gopark(0x10116aca0?, 0x1?, 0x1b?, 0xb7?, 0x0?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x140001e2f30 sp=0x140001e2f10 pc=0x100a78978
runtime.gcBgMarkWorker()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1293 +0xd8 fp=0x140001e2fd0 sp=0x140001e2f30 pc=0x100a59d28
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x140001e2fd0 sp=0x140001e2fd0 pc=0x100aacc74
created by runtime.gcBgMarkStartWorkers in goroutine 72
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1217 +0x28
goroutine 275 [GC worker (idle)]:
runtime.gopark(0x11a78ebc2c58?, 0x3?, 0x9e?, 0x39?, 0x0?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x1400028ef30 sp=0x1400028ef10 pc=0x100a78978
runtime.gcBgMarkWorker()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1293 +0xd8 fp=0x1400028efd0 sp=0x1400028ef30 pc=0x100a59d28
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x1400028efd0 sp=0x1400028efd0 pc=0x100aacc74
created by runtime.gcBgMarkStartWorkers in goroutine 72
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1217 +0x28
goroutine 276 [GC worker (idle)]:
runtime.gopark(0x11a78e488104?, 0x3?, 0x8e?, 0xec?, 0x0?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x140001f2730 sp=0x140001f2710 pc=0x100a78978
runtime.gcBgMarkWorker()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1293 +0xd8 fp=0x140001f27d0 sp=0x140001f2730 pc=0x100a59d28
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x140001f27d0 sp=0x140001f27d0 pc=0x100aacc74
created by runtime.gcBgMarkStartWorkers in goroutine 72
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1217 +0x28
goroutine 262 [GC worker (idle)]:
runtime.gopark(0x11a78ebc2f46?, 0x3?, 0xc4?, 0x2?, 0x0?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x140001e6f30 sp=0x140001e6f10 pc=0x100a78978
runtime.gcBgMarkWorker()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1293 +0xd8 fp=0x140001e6fd0 sp=0x140001e6f30 pc=0x100a59d28
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x140001e6fd0 sp=0x140001e6fd0 pc=0x100aacc74
created by runtime.gcBgMarkStartWorkers in goroutine 72
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1217 +0x28
goroutine 291 [GC worker (idle)]:
runtime.gopark(0x11a78e4a84a4?, 0x1?, 0x3d?, 0xcd?, 0x0?)
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/proc.go:398 +0xc8 fp=0x1400029a730 sp=0x1400029a710 pc=0x100a78978
runtime.gcBgMarkWorker()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1293 +0xd8 fp=0x1400029a7d0 sp=0x1400029a730 pc=0x100a59d28
runtime.goexit()
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/asm_arm64.s:1197 +0x4 fp=0x1400029a7d0 sp=0x1400029a7d0 pc=0x100aacc74
created by runtime.gcBgMarkStartWorkers in goroutine 72
/Users/eliott.bouhana/go/go1.21rc3/src/runtime/mgc.go:1217 +0x28
r0 0x6
r1 0x9
r2 0x176cb0ab0
r3 0x14
r4 0x176cb06b0
r5 0x0
r6 0x0
r7 0x0
r8 0x20
r9 0x9
r10 0x1
r11 0xa
r12 0x0
r13 0x39
r14 0xf0000
r15 0x8000
r16 0x209
r17 0x1a8cfd35c
r18 0x0
r19 0x0
r20 0x176cb06b0
r21 0x14
r22 0x176cb0ab0
r23 0x9
r24 0x6
r25 0x2d3144558
r26 0x176cb14c0
r27 0x2d3144648
r28 0x8
r29 0x176cb0680
lr 0x1a8d78d7c
sp 0x176cb0640
pc 0x1a8d6d118
fault 0x1a8d6d118
exit status 2
FAIL github.com/DataDog/go-libddwaf 171.877s
</details>
I think we have already discussed this, but I was wondering why we have SEL as the first argument of Send
, not a string.
In most cases, uses make a SEL by objc.RegisterName
at that place, so isn't this redundant? Sorry if you have already explained the reason.
Now Go 1.15 for Arm64 iOS doesn't work as callbackWrapPicker
is missing.
We don't have to care about macOS since Go 1.15 doesn't support Arm macOS. This support started as of Go1.16.
This is nice to have and low priority.
This project seems very cool!
However it's hard to assess the relative maturity of this package; which features it has or doesn't have, what are the largest caveats or roadblocks that one might encounter.
It would be super great to have some high-level documentation about what consumers of this package can expect so that people can assess how suitable/viable this package is.
Thanks! :)
Bazel does not use the go usual build process for an increase in building speed. For this, they use their usual sandbox which makes the current working directory a random temporary directory and not the current package. This makes cross-package #include
unable to work since the included file is not at the right place at build time. Here is the error:
external/com_github_ebitengine_purego/internal/fakecgo/asm_arm64.s:7:
#include: open /var/folders/fn/j3_08pb94p9_hyz4myff84br0000gq/T/abi/abi_arm64.h: no such file or directory
compilepkg: error running subcommand external/go_sdk/pkg/tool/darwin_arm64/asm: exit status 1
The files where it fails are the following:
Purego is especially useful in Bazel environments because CGO is disabled by default. I checked on bazel side and this behaviour seems unavoidable. Do we know if cross-package usage of #include
is really something that is officially supported (in which case bazel is at fault) and not a happy coincidence ? It is only a matter of copying the files in purego/internal/abi
to purego/internal/fakecgo
and purego/
, in which case I can do the PR, or am I missing something ?
On Linux, the name of the file is needed to open it. A recent test failed on one machine as the installed library had a suffix of ".0". What is the guidance on determining filenames on Linux so that they can be opened? Many thanks ๐
It would seem that NewCallback is not implemented on Linux.
Is this already in development?
When using the the special C package there are a few functions that convert from Go types to C types and vice versa. When porting code that uses C it's annoying not having an equivalent to these functions. Especially, GoString
and CString
which convert a C string to a Go string and vice versa. Even ebitengine had to have it's own implementation and writing these over and over is begging for mistakes. Purego already uses it's own internal versions.
I purpose adding these two functions to purego with the following signatures.
// Cstring converts a Go string to a null-terminated C string.
// The C string is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
// freed, such as by calling free.
func CString(string) *byte
// GoString converts a null-terminated C string and copies it into
// a Go allocated string.
func GoString(*byte) string
I believe these are the most used functions so should be added first. If there is strong demand later for the other ones a new issue can be created.
Hi there!
I'm trying to hook into Apple's GCD method dispatch_async
to schedule callbacks on the main thread. I've gotten pretty far but the final call never returns.
The obj-c code I'm trying to replace is:
dispatch_async(dispatch_get_main_queue(), ^{
// some code
});
I discovered that dispatch_get_main_queue
is actually a macro and returns the address of _dispatch_main_q
.
The following is where I'm up to. It feels like I'm missing just one final piece:
func dispatchTest() {
libSystem, err := purego.Dlopen("libSystem.dylib", purego.RTLD_NOW|purego.RTLD_GLOBAL)
if err != nil {
panic(err)
}
dispatchMainQueue, err := purego.Dlsym(libSystem, "_dispatch_main_q")
if err != nil {
panic(err)
}
var dispatch_async func(uintptr, uintptr)
goFunc := func() {
fmt.Println("Hello from the main thread")
}
callback := purego.NewCallback(goFunc)
purego.RegisterLibFunc(&dispatch_async, libSystem, "dispatch_async")
dispatch_async(dispatchMainQueue, callback)
println("i never get here")
}
func main() {
// Since the error wasn't checked before check it before calling any code.
NSApp := NewNSSharedApplication()
go func() {
time.Sleep(1 * time.Second)
dispatchTest()
}()
NSApp.Run()
}
The NSApp code is just the same as from last ticket so left out to simplify the example.
Nothing is crashing or suggesting anything bad is happening. Am I using NewCallback
correctly? My guess is that it's to do with C vs Obj-C calling conventions...
Any help appreciated!
chip: Apple M2 Pro
macOS: 13.2.1 (22D68)
This issue tracks the implementation of fakecgo which is needed for some frameworks to function properly when CGO_ENABLED=0. It will be similar to notti/nocgo
Is there an example of how to create an NSString variable
when link the dynamic library by cgo (without purego), thread local storage work fine.
when use purego load the dynamic library, thread local storage return 0 at first visit, then return value before assign from other os thread.
confirm the problem from linux, windows, macOS. (go1.20.5)
As per the man page, dlopen(NULL)
is supposed to return the equivalent of the macro RTLD_DEFAULT
which not accessible from go code obviously and is implementation defined. This function is especially useful to run already loaded symbols like the ones loaded with the pragma go:cgo_import_dynamic
.
But since we pass a string to Dlopen, a nil value cannot be passed as parameter. How could we give access to this feature ?
The latest tag is now v0.2.0-alpha
but this is outdated. As there has not been drastic changes in the main branch, I'd like to tag v0.2.0-alpha.1
for the latest commit.
@TotallyGamerJet, what do you think?
BTW, I plan to make 0.2 branch including non-alpha v0.2.x versions when Ebitengine v2.5 is released.
I tried to extend the Metal wrapper with support for the "setFrontFacing:" method on the MTLRenderCommandEncoder class, but it consistently crashes. I've included the code and the error below. Any ideas what might be wrong?
var sel_setFrontFacing = objc.RegisterName("setFrontFacing:")
// SetFrontFacing sets the winding order of front-facing primitives. The default is clockwise.
//
// Reference: https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515499-setfrontfacing
func (rce RenderCommandEncoder) SetFrontFacing(winding Winding) {
rce.commandEncoder.Send(sel_setFrontFacing, winding)
}
// Winding defines the vertex winding rule that determines a front-facing primitive.
//
// Reference: https://developer.apple.com/documentation/metal/mtlwinding.
type Winding uint8
const (
// Primitives whose vertices are specified in clockwise order are front-facing.
WindingClockwise Winding = 0
// Primitives whose vertices are specified in counter-clockwise order are front-facing.
WindingCounterClockwise Winding = 1
)
2023-03-23 20:37:53.213 myapp[7163:25611636] -[AGXG13GFamilyRenderContext setFrontFacing:]: unrecognized selector sent to instance 0x6000024442d0
2023-03-23 20:37:53.213 myapp[7163:25611636] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[AGXG13GFamilyRenderContext setFrontFacing:]: unrecognized selector sent to instance 0x6000024442d0'
*** First throw call stack:
(
0 CoreFoundation 0x00000001b002ab08 __exceptionPreprocess + 240
1 libobjc.A.dylib 0x00000001afd75e14 objc_exception_throw + 60
2 CoreFoundation 0x00000001b00bea68 -[NSObject(NSObject) __retain_OA] + 0
3 CoreFoundation 0x00000001aff89e14 ___forwarding___ + 1764
4 CoreFoundation 0x00000001aff89670 _CF_forwarding_prep_0 + 96
5 myapp 0x00000001005c84f4 syscall9X + 100
6 myapp 0x000000010056b27c runtime.asmcgocall.abi0 + 124
)
libc++abi: terminating with uncaught exception of type NSException
SIGABRT: abort
PC=0x1afea8db8 m=0 sigcode=0
signal arrived during cgo execution
goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x1005c8490, 0x1400018b3f0)
/opt/homebrew/Cellar/go/1.19/libexec/src/runtime/cgocall.go:158 +0x54 fp=0x1400012cf20 sp=0x1400012cee0 pc=0x10050d894
github.com/ebitengine/purego.RegisterFunc.func1({0x14000189540?, 0x3?, 0x8?})
...snip.../go/pkg/mod/github.com/ebitengine/[email protected]/func.go:188 +0x2ac fp=0x1400012d240 sp=0x1400012cf20 pc=0x1005c69cc
reflect.callReflect(0x1400011c690, 0x1400012d818, 0x1400012d678, 0x1400012d680)
/opt/homebrew/Cellar/go/1.19/libexec/src/reflect/value.go:770 +0x3e4 fp=0x1400012d620 sp=0x1400012d240 pc=0x100587044
reflect.callReflect(0x1400011c690, 0x1400012d818, 0x1400012d678, 0x1400012d680)
<autogenerated>:1 +0x28 fp=0x1400012d650 sp=0x1400012d620 pc=0x10058ad48
reflect.makeFuncStub()
/opt/homebrew/Cellar/go/1.19/libexec/src/reflect/asm_arm64.s:48 +0x58 fp=0x1400012d810 sp=0x1400012d650 pc=0x10058ac58
github.com/ebitengine/purego/objc.ID.Send(...)
...snip.../go/pkg/mod/github.com/ebitengine/[email protected]/objc/objc_runtime_darwin.go:76
...snip.../metal/mtl.RenderCommandEncoder.SetFrontFacing(...)
...snip.../metal/mtl/command_encoder_render.go:119
Golang has native embed
support since golang 1.16.
import "embed"
//go:embed hello.txt
var f embed.FS
data, _ := f.ReadFile("hello.txt")
print(string(data))
Is it possible to Dlopen
a shared object within embed fs? This way we can distribute binaries more easily.
go1.15.15 run -tags=example ./examples/audio
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4176b9e]
goroutine 17 [running, locked to thread]:
github.com/ebitengine/purego.callbackWrap(0xc000070000)
/Users/hajimehoshi/go/pkg/mod/github.com/ebitengine/[email protected]/syscall_darwin.go:123 +0x17e
github.com/ebitengine/purego.callbackWrapPicker(0xc000070000, 0x4176f80)
/Users/hajimehoshi/go/pkg/mod/github.com/ebitengine/[email protected]/syscall_darwin.go:106 +0x2b
exit status 2
/CC @TotallyGamerJet Please take a look... Thanks,
https://developer.apple.com/documentation/foundation/nsnumber/1414104-doublevalue?language=objc
Some method returns a double value, but how can I get a float64 value from ID that is returned from Send?
When Go 1.20 is released add a test that includes CGO_ENABLED=0
and -race
.
See #71 for more information.
@TotallyGamerJet what do you think? Are there extra tasks for this?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.