Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation on cross-compilation #279

Open
goloroden opened this issue Sep 22, 2024 · 12 comments
Open

Documentation on cross-compilation #279

goloroden opened this issue Sep 22, 2024 · 12 comments

Comments

@goloroden
Copy link

goloroden commented Sep 22, 2024

Today, I'd like to ask for a small feature request, which – I think – could be useful to more people than just me.

It's about cross-compiling Go programs which shall use DuckDB. While building a binary for the platform you're developing on is pretty simple, doing the same with cross-compilation is not.

Given that there are three major operating systems these days (macOS, Linux, Windows), and two CPU architectures (x86-64 and ARM), you end up with quite a number of combinations: You essentially have six combinations as development base, and you have six combinations you might want to build.

E.g.:

  • Build for macOS / ARM on a Linux / x86-64 machine.
  • Build for Windows / x86-64 on a macOS / arm machine.
  • And so on …

Effectively, this is 36 combinations in total.

Now here's my question: Since I find it pretty difficult to figure out how to cross-compile, would it maybe be possible to add information on this to the documentation of this module? I think that it doesn't need an example per combination, but having some general guidelines or tips would already be helpful (or even a link to a page which explains it in more detail).

What do you think of this?

PS: If someone is able to provide the commands, I'd be more than happy to work on the documentation and submit a PR. It's just that I don't know how to do it myself.

@marcboeker
Copy link
Owner

@goloroden Thanks for bringing this up. Cross-compiling is a total pain. What could make sense is an issue where we first collect all the cross-compiling combinations we have working so far. Then we can start generating a kind of matrix from it with source and destination and which toolchain to use.

Starting with macOS we could use the approach I've commented in an earlier issue you have opened.

With linux as source we could use the compile chain from the Github runners (need to figure out what the have pre-installed) and the commands from the Makefile.

From and to Windows: @taniabogatsch is currently working on a Windows build. But I have no access to Windows to test anything. And I'm still confused about Mingw32, Msys2, Cygwin...

@goloroden
Copy link
Author

goloroden commented Oct 1, 2024

Okay, I'll start collecting things here. This is my test program:

package main

import (
	"database/sql"
	"fmt"

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

func main() {
	db, err := sql.Open("duckdb", "")
	if err != nil {
		panic(err)
	}
	defer db.Close()

	var value int
	row := db.QueryRow("SELECT 23 AS value")
	row.Scan(&value)
	fmt.Println(value)
}

The goal is to compile and run the binary afterwards in the appropriate environment. If the file size is around 40 MByte, it apparently includes DuckDB statically linked; and if it runs and prints 23, it seems to work.

This list can – sooner or later – maybe be merged into the official documentation, to make things easier for other people who want to do cross-compilation with DuckDB and Go. If you want to add an entry to this list, please leave a comment below, outlining on which OS/Arch you are compiling, for which OS/Arch you are compiling, what the required steps are, and whether it was verified to work.

So far, the following combinations have been reported and successfully verified to work:

✅ On Linux (ARM) for Linux (ARM)

(Verified by @goloroden)

# Compile
$ go build .

❌ On Linux (ARM) for Linux (x86)

❌ On Linux (ARM) for macOS (ARM)

❌ On Linux (ARM) for macOS (x86)

❌ On Linux (x86) for Linux (ARM)

✅ On Linux (x86) for Linux (x86)

(Verified by @goloroden)

# Compile
$ go build .

❌ On Linux (x86) for macOS (ARM)

❌ On Linux (x86) for macOS (x86)

✅ On macOS (ARM) for Linux (ARM)

(Verified by @goloroden)

# Install the cross-compiler components for Linux (ARM)
$ brew install messense/macos-cross-toolchains/aarch64-unknown-linux-gnu

# Cross-compile
$ CC="aarch64-linux-gnu-gcc" CXX="aarch64-linux-gnu-g++" CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build .

✅ On macOS (ARM) for Linux (x86)

(Verified by @goloroden)

# Install the cross-compiler components for Linux (x86)
$ brew install messense/macos-cross-toolchains/x86_64-unknown-linux-gnu

# Cross-compile
$ CC="x86_64-linux-gnu-gcc" CXX="x86_64-linux-gnu-g++" CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build .

✅ On macOS (ARM) for macOS (ARM)

(Verified by @goloroden)

# Compile
$ go build .

✅ On macOS (ARM) for macOS (x86)

(Verified by @goloroden)

# Cross-compile
$ CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build .

❌ On macOS (x86) for Linux (ARM)

❌ On macOS (x86) for Linux (x86)

❌ On macOS (x86) for macOS (ARM)

❌ On macOS (x86) for macOS (x86)

@goloroden
Copy link
Author

@marcboeker I have collected what I have so far, do you maybe have other ones you can contribute?

@yusufozturk
Copy link

I am trying to build it on windows 10:

go build -tags="no_duckdb_arrow"
# win-duckdb
C:\Program Files\Go\pkg\tool\windows_amd64\link.exe: running gcc failed: exit status 1
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/Users/Yusuf-I9/go/pkg/mod/github.com/marcboeker/[email protected]/deps/windows_amd64\libduckdb.a(ub_duckdb_main_extension.cpp.obj):ub_duckdb_main_extension.cpp:(.rdata$_ZTVN14duckdb_httplib8DataSink19data_sink_streambufE[_ZTVN14duckdb_httplib8DataSink19data_sink_streambufE]+0x38): undefined reference to `std::basic_streambuf<char, std::char_traits<char> >::seekpos(std::fpos<_Mbstatet>, std::_Ios_Openmode)'
collect2.exe: error: ld returned 1 exit status

I tried different things but it doesn't work.
I am able to build duckdb from the source. But somehow I can not build your example.

@goloroden
Copy link
Author

@yusufozturk What happens if you simply run:

$ go build .

Does this create an executable for Windows, which includes DuckDB?

@yusufozturk
Copy link

@goloroden no, same error.

I tried a lot of different things, but nothing worked for me.

@taniabogatsch I dont think #248 solves all the issues. Or maybe @JAicewizard can share a step by step process to help us :)

@goloroden
Copy link
Author

@yusufozturk Anyway: Thanks for trying it out and giving instant feedback 😊

@yusufozturk
Copy link

yusufozturk commented Oct 19, 2024

Okay somehow it works now. I can build and debug on VS Code, but only with -tags="no_duckdb_arrow". But I have no idea what fixed the problem because I tried a lot of different things.

I will try to replicate the success on a clean Windows machine and I will create a documentation for my team. I can share the same documentation here if I can make it again.

Edit: VS Code debug works perfectly. Building is also okay. Binary is generated. But binary is crashing when it tries to load DuckDB. At this line:

db, err := sql.Open("duckdb", "")

There is no error or panic. Just stops working at this line.

@JAicewizard
Copy link
Contributor

I am trying to build it on windows 10:

go build -tags="no_duckdb_arrow"
# win-duckdb
C:\Program Files\Go\pkg\tool\windows_amd64\link.exe: running gcc failed: exit status 1
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/Users/Yusuf-I9/go/pkg/mod/github.com/marcboeker/[email protected]/deps/windows_amd64\libduckdb.a(ub_duckdb_main_extension.cpp.obj):ub_duckdb_main_extension.cpp:(.rdata$_ZTVN14duckdb_httplib8DataSink19data_sink_streambufE[_ZTVN14duckdb_httplib8DataSink19data_sink_streambufE]+0x38): undefined reference to `std::basic_streambuf<char, std::char_traits<char> >::seekpos(std::fpos<_Mbstatet>, std::_Ios_Openmode)'
collect2.exe: error: ld returned 1 exit status

I tried different things but it doesn't work. I am able to build duckdb from the source. But somehow I can not build your example.

I can reproduce this on linux with mingw, I don't know how to fix it though. One possibility is that the gcc version on github CI is different from that on your (and my) machine, leading to different stdc++ being used (https://stackoverflow.com/questions/73261554/sfml-undefined-reference-to-stdbasic-streambuf). I don't know how to fix this easily, besides setting your mingw version to be the same as on github CI. You could also try running deps.windows.amd64 to create the dependencies specifically for your system and see if that works.

@taniabogatsch
Copy link
Collaborator

Edit: VS Code debug works perfectly. Building is also okay. Binary is generated. But binary is crashing when it tries to load DuckDB. At this line:
db, err := sql.Open("duckdb", "")
There is no error or panic. Just stops working at this line.

I remember having seen this before in one of the issues... 🤔

I dont think #248 solves all the issues.

I agree, the shipped Windows build currently provides a solution for one(?) workflow/mingw version? But I don't have enough experience with Windows to know how to fix this for the pre-build library...

Also, it might be worth bundling the different issues and solutions on Windows into a discussion. Similar to this issue being a collection of knowledge on cross compilation.

@JAicewizard
Copy link
Contributor

I managed to reproduce a successfull build on a semi-clean windows. basic steps:

  • install msys64
  • install ucrt mingw (pacman -S mingw264-ucrt-x86_64-gcc in a ucrt64 shell. Not sure if the shell really matters, as long as it is msys)
  • make sure this gcc is in path (c:/msys64/ucrt64/bin)

I am 99% sure that the build errors relating to std::basic_streambuf are because of some CRT version mismatches, having an older version might not work. (Arch linux is on mingw 11, which does not work, msys has version mingw 12).

@JAicewizard
Copy link
Contributor

I hope this helps anyone, I will open a PR with instructions in a minute. Also if anyone can confirm that using mingw 12 on linux allows for cross-compiling, that would be really cool. I don't feel like upgrading the arch packages myself ATM, but it shouldn't be much work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants