marcboeker / go-duckdb

go-duckdb provides a database/sql driver for the DuckDB database engine.
MIT License
739 stars 108 forks source link

macos `go run` works but unable to execute the output of `go build` #235

Open chenbobby opened 5 months ago

chenbobby commented 5 months ago

I am trying to build the example simple.go as a single static binary, and then execute it. However, my terminal seems to just hang when I attempt to run the output Mach-O executable, and I am forced to close my terminal. I cannot even Ctrl-C out of the execution attempt.

Strangely, running go run . in the examples directory will execute successfully. Also, running both go build . and CGO_ENABLED=1 go build . will execute and terminate with exit code 0. But, as described above, executing the output binary will cause my terminal to hang.

Is there some additional work I need to do to build a CGo binary that I can run on macOS? Thanks in advance for the help, and let me know if I can provide any additional information.

CPU: Apple M1 Pro 2021 OS: macOS Ventura 13.3.1 Go Version: go1.22.2 darwin/arm64 Git Hash: 8eaf1200ffa1d2ab268071c387c4161a8508bb40

marcboeker commented 5 months ago

Thanks for bringing this up. Does this strange behavior also occur with other go-duckdb based code or only with the examples/simple.go program?

make test also executes properly?

Can you try to attach to the executed binary with dlv as described here?

chenbobby commented 5 months ago

Does this strange behavior also occur with other go-duckdb based code or only with the examples/simple.go program?

This occurs with other go-duckdb based code as well. As a simple case, the following code snippet will have the same buggy behavior:

package main

import (
    "database/sql"
    "fmt"

    _ "github.com/marcboeker/go-duckdb"
)

func main() {
    fmt.Println("Start")
    _, err := sql.Open("duckdb", "")
    if err != nil {
        panic(err)
    }
    fmt.Println("End")
}

make test also executes properly?

Yes, make test executes properly and all tests are passing.


Can you try to attach to the executed binary with dlv?

Thanks for the suggestion. I haven't used dlv before.

I tried to dlv attach <pid> to a running process, but dlv just hangs without any output.

I also tried to dlv exec <my_binary> and I get the following output:

Warning: no debug info found, some functionality will be missing such as stack traces and variable evaluation.
could not launch process: could not read debug info (decoding dwarf section info at offset 0x0: too short) and could not read go symbol table (could not find rodata struct member)
chenbobby commented 5 months ago

✅ I found a workaround. go build -ldflags="-s -w" will produce a binary that I can execute.

Explanation

When I compared the output of go build -x . and go run -x ., the only significant difference was that go run included the linker flags -s -w. When I explicitly added -ldflags="-s -w" to my go build command, I was able to successfully execute the output binary.

Apparently, those linker flags will:

-s    disable symbol table
-w    disable DWARF generation

However, I'm not sure why this solved my problem though. 😅

In any case, feel free to close this issue.