veandco / go-sdl2

SDL2 binding for Go
https://godoc.org/github.com/veandco/go-sdl2
BSD 3-Clause "New" or "Revised" License
2.21k stars 221 forks source link

Support for Apple Silicon? #479

Open bartgrantham opened 3 years ago

bartgrantham commented 3 years ago

In trying to install on an M1 machine I am getting a very, very long list of linker errors, ending with:

    ...
  "_SDL_free", referenced from:
      __cgo_cd82acf4e3d9_Cfunc_SDL_free in _x004.o
     (maybe you meant: __cgo_cd82acf4e3d9_Cfunc_SDL_free)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I'm not sure why its trying to build for x64_64, I'm just doing a straightforward install with:

go get -v github.com/veandco/go-sdl2/{sdl,img,mix,ttf}

as suggested in the documentation. I can see that the included static libs in .go-sdl2-libs don't include "darwin_amd64" versions, so that will also need addressing.

Let me know if I've done something wrong here, otherwise I'm looking forward to enjoying SDL2 again in the near future.

veeableful commented 3 years ago

Hi @bartgrantham, I wonder if you are using Go 1.16 which is the Go version that supports Apple ARM64? I don't have an M1 machine so I haven't made sure that it works on an Apple ARM64 machine. I will find a way to get access to an Apple ARM64 machine so I can make sure it works and update you here.

Update: I found Scaleway which seems to provide Apple ARM64 machine for rent which costs roughly $0.12 per hour so I will try that!

bartgrantham commented 3 years ago

Yes, I am running 1.16. I might look into figuring out what is going wrong later today, do you have suggestions?

veeableful commented 3 years ago

Do you have SDL2 installed? What's the the output of file /path/to/libSDL2-[version].dylib? You should be able to locate where the dylib is by running pkg-config --libs sdl2 and see the argument of the -L flag.

I searched a little and found that someone seems to fix it by running arch=arm64 brew install llvm.

bartgrantham commented 3 years ago
$ file /opt/homebrew/lib/libSDL2-2.0.0.dylib
/opt/homebrew/lib/libSDL2-2.0.0.dylib: Mach-O 64-bit dynamically linked shared library arm64

Appears to all be arm64, as expected. I installed with brew (brew install sdl2{,_image,_mixer,_ttf,_gfx} pkg-config).

arch=arm64 brew install llvm, eh? That's... pretty brute-force. I may give that a try, but I'll see if I can find something more surgical first.

bartgrantham commented 3 years ago

I am so, so, so, so sorry! I just realized I was running the amd64 version of 1.16 by accident!

It worked with the correct compiler. I hope you didn't spend much time diagnosing it. Well, now that I have it compiling, are there tests you'd like me to do?

veeableful commented 3 years ago

@bartgrantham Ooh I'm glad that it worked! I'm still waiting for Scaleway to have stock of M1 servers as apparently they ran out of stock :joy_cat:

To test it, you could try running the examples at .go-sdl2-examples/examples/render and run go run main.go and let me know if it works! It's just a bunch of random rendering (which I should probably update with nicer example...).

bartgrantham commented 3 years ago

render worked! I did have to go mod init ... in the repo root because of modules complaining. Here's my full report:

veeableful commented 3 years ago

@bartgrantham Thanks for testing it! It seems like I can finally rent an M1 machine so I will check and fix those examples some time this weekend.

veeableful commented 3 years ago

Hi @bartgrantham, about those signal: killed messages, could you elaborate more on what happened? The same happened to me but I think it's because I used the .tar.gz version of the Go toolchain and macOS doesn't trust the programs that came with it.

I managed to fix it by allowing the Go linker tool to be executed which maybe isn't needed if you're using .pkg version. I did it by going to $GOROOT/pkg/tool/darwin_amd64 for Intel or $GOROOT/pkg/tool/darwin_arm64 for M1 in the Finder app and double-click link which would be prohibited to run by macOS the first time. After that, I need to go to System Preferences -> Securiy and Privacy and allow the program to run at the bottom.

After I did the above, I could run all of the examples that had the signal: killed error message except the ones which require MP3 support which just means the SDL2_mixer used is not built with MP3 support. I put a workaround for that in the FAQ a while back but I'm not using Homebrew for the SDL2 libraries at the moment so I haven't verified it to be working still.

bartgrantham commented 3 years ago

about those signal: killed messages, could you elaborate more on what happened?

I tried a very simple go run ... in the same directory as the example. Just now I tried also doing a go build ... for drawing-text, which built without errors but still gave the signal: killed on running.

I'm using the .pkg version of the Go toolchain, so all those binaries are already trusted. At least the couple I clicked on in /usr/local/go/pkg/tool/darwin_arm64/ had no problems. BTW, 1.16: no more $GOROOT (for better or worse...)

veeableful commented 3 years ago

Hmm I wonder what happened.. I tried switching my set up to use .pkg version of Go and Homebrew versions of SDL2 packages (previously I compiled them myself alongside their dependencies) and they seem to build and run still.

I noticed all the examples that involve SDL2_ttf, SDL2_mix, or SDL2_image seem to crash on your set up while the ones that use SDL2 and/or SDL2_gfx don't crash. Would you happen to have a clue of what the reason could be? Could they come from different sources somehow or were they built differently?

bartgrantham commented 3 years ago

So strange! You are also using Big Sur, Go 1.16, and Apple Silicon?

Would you happen to have a clue of what the reason could be? Could they come from different sources somehow or were they built differently?

They were all installed with brew install sdl2{,_image,_mixer,_ttf,_gfx} pkg-config, all were from "bottles". Just double-checked that the libs are are arm64 and not amd64. ;)

Are these examples based on SDL C examples? I'm wondering if I should turn my eye toward SDL. I've assumed that homebrew published a proper and tested SDL for Apple Silicon, but maybe not?

veeableful commented 3 years ago

@bartgrantham Yup, now I'm using Big Sur, Go 1.16, and Apple Silicon. I think The Homebrew packages should be fine since I could run the examples with them..

I wonder if it helps to force build from scratch. For example, does the same thing still happen when you run go run -a drawing-text.go in the drawing-text example? When did you install the Homebrew packages? Is there a chance that the Homebrew packages are not up-to-date?

If those are not the issues, I wonder if you could run go mod init drawing-text in the drawing-text directory and run go build. After that, try to run the program with ./drawing-text. If that doesn't work, try codesign -s - ./drawing-text and then run it. I think this issue might be related to https://github.com/golang/go/issues/42684 but I'm not sure since it should be fixed in the latest Go release..

bartgrantham commented 3 years ago

I just did a brew upgrade sdl2{,_image,_mixer,_ttf,_gfx} pkg-config to make sure I had the most recent packages, everything was already up to date.

I wonder if it helps to force build from scratch.

Just tried go run -a drawing-text.go in drawing-text: still killed

If those are not the issues, I wonder if you could run go mod init drawing-text in the drawing-text directory and run go build.

Tried this, still killed.

codesign -s - ./drawing-text

Tried this, still killed.

:(

I did go build -x to see what how it was resolving libraries, nothing seemed out of place. Same with go build -v. I'll see if I can dig into this a bit more later. If it works for you it's surely something on my system gone wrong.

bartgrantham commented 3 years ago

Stepping through the program with delve works. (!) Even just doing dlv debug drawing-text followed with "c" immediately works (ie. no setting breakpoints, etc).

delve kicked up a security dialog about permissions, I thought it was another XCode annoyance and didn't pay close attention so I can't remember exactly what it said, I wish I had. I wonder if it's something fundamentally different about how delve builds an app than go build?

veeableful commented 3 years ago

@bartgrantham It certainly sounds like macOS doesn't want the program to run for some reason. I don't have anything that isn't just another shot in the dark. I wish I could replicate your set-up...

Could you attach the executable for drawing-text here? I would like to see if I can run it.

bartgrantham commented 3 years ago

drawing-text.zip

Attached. I'm going to assume it's something on my system with Big Sur's permissions system, but if you could give it a try it would be helpful to have confirmation of this. Thank you!

veeableful commented 3 years ago

Thanks! I managed to run it even as a fresh new user. I downloaded and extracted the go-sdl2-examples repository and put the executable at the examples/drawing-text directory so I suppose it was able to use the Homebrew installation of the native packages.

I also wrote C version of the program here:

// drawing-text.c
#include <SDL.h>
#include <SDL_ttf.h>

static const char *fontPath = "../../assets/test.ttf";
static const int fontSize = 32;

int main()
{
    SDL_Window *window;
    TTF_Font *font;
    SDL_Surface *surface;
    SDL_Surface *text;
    SDL_Color textColor;
    SDL_Rect surfaceRect;
    SDL_Event event;
    SDL_bool running;
    int ret = 0;

    ret = TTF_Init();
    if (ret != 0) {
        goto out;
    }

    ret = SDL_Init(SDL_INIT_VIDEO);
    if (ret != 0) {
        goto out;
    }

    window = SDL_CreateWindow("Drawing text", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_SHOWN);
    if (!window) {
        ret = 1;
        goto out;
    }

    surface = SDL_GetWindowSurface(window);
    font = TTF_OpenFont(fontPath, fontSize);

    textColor = (SDL_Color) {255, 0, 0, 255};
    text = TTF_RenderUTF8_Blended(font, "Hello, World!", textColor);
    if (!text) {
        ret = 1;
        goto out;
    }

    surfaceRect = (SDL_Rect) {400 - (text->w / 2), 300 - (text->h / 2), 0, 0};
    ret = SDL_BlitSurface(text, NULL, surface, &surfaceRect);
    if (ret != 0) {
        goto out;
    }

    SDL_UpdateWindowSurface(window);

    running = SDL_TRUE;

    while (running) {
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
            case SDL_QUIT:
                running = SDL_FALSE;
                break;
            }
        }

        SDL_Delay(16);
    }
out:
    TTF_CloseFont(font);
    SDL_DestroyWindow(window);
    SDL_Quit();
    TTF_Quit();
    return ret;
}

If you put it inside the drawing-text directory, you should be able to compile it by running:

gcc `pkg-config --libs --cflags sdl2 sdl2_ttf` drawing-text.c

After that, could you try running ./a.out? If it still cannot run, then perhaps there is a problem with accessing the Homebrew installed libraries though you said that delve could run it so I'm not sure anymore 😅

P.S. I accidentally closed the issue! I have re-opened it now.

bartgrantham commented 3 years ago

Tried your C example: also SIGKILL'ed!

Ok, I think this really drives it home: something is screwy on my system. Probably with permissions but it's going to require some investigation to figure out.

Thank you SO MUCH for your help in diagnosing this. I think you can probably close this issue since it appears you now have M1 support generally. I'll come back and update the issue if I figure out what's going on.

bartgrantham commented 3 years ago

Investigating in Console.app (which I should have done from the beginning!), I can see AMFI reject the process:

CODE SIGNING: process 91537[drawing-text-go]: rejecting invalid page at address 0x101314000 from offset 0x0 in file "/opt/homebrew/Cellar/freetype/2.10.4/lib/libfreetype.6.dylib" (cs_mtime:1614669612.249934129 == mtime:1614669612.249934129) (signed:1 validated:1 tainted:1 nx:0 wpmapped:0 dirty:0 depth:0)

What's odd is that library is signed, at least adhoc:

$ codesign -d --verbose /opt/homebrew/Cellar/freetype/2.10.4/lib/libfreetype.6.dylib
Executable=/opt/homebrew/Cellar/freetype/2.10.4/lib/libfreetype.6.dylib
Identifier=libfreetype.6
Format=Mach-O thin (arm64)
CodeDirectory v=20400 size=4966 flags=0x2(adhoc) hashes=150+2 location=embedded
Signature=adhoc
Info.plist=not bound
TeamIdentifier=not set
Sealed Resources=none
Internal requirements count=0 size=12

Still digging...

bartgrantham commented 3 years ago

brew uninstalled anything that had to do with SDL, then reinstalled with brew install. So it all seems to work for me now. I have no idea why uninstalling and reinstalling made a difference, AFAICT it was all the same versions and they were installed with the exact same method.

Oh well. I guess the old joke about the computer scientist, "how about we get out of the car and get back in and see if it starts?", holds true.

Here's my updated report:

Thank you do much for all the help!! I'll leave this open as a reminder to include *_darwin_arm64.a in .go-sdl2-libs next time you update the static libraries, but feel free to close it.

veeableful commented 3 years ago

Thank you too for trying all my attempts to solve it and helping me narrow down the issue! I'm really glad that you found the root of the problem and fixed it. Certainly, I will keep this issue open as well and update you here when I manage to build and put the static library in the repo for macOS M1 😃

veeableful commented 3 years ago

Just to let you know that I managed (I think) to build darwin/arm64 static library for SDL2 which is on the v0.5.0-alpha.1 tag now and tested the static compilation on darwin/amd64, darwin/arm64 and linux/amd64 machine!

However, I'm encountering stumbling blocks with the other SDL2_* libraries so I'm still working that out..

depili commented 2 years ago

in theory the following should work for cross compiling to M1:

#!/bin/bash
export GOOS=darwin
export GOARCH=arm64
export CGO_CFLAGS="-isysroot $(xcrun --sdk macosx11.1 --show-sdk-path) -arch arm64 -I/usr/local/include"
export CGO_LDFLAGS="-isysroot $(xcrun --sdk macosx11.1 --show-sdk-path) -arch arm64 -L/usr/local/lib"
export CGO_ENABLED=1
go build -tags static -ldflags "-s -w" fooo

But still haven't managed to get anything to compile, using catalina as the development machine for now.

depili commented 1 year ago

Are the commands for compiling the static libraries available somewhere?

depili commented 1 year ago

Replying for myself: https://github.com/veandco/sdl2-static-library-build-scripts

I'm in a process of getting my hands on a arm mac, and once it arrives I intend on having a go at getting the static libs made for arm.

depili commented 1 year ago

Linking to the dynamic libraries provided by homebrew on a m1pro mac seems to work. Had to do a single monkeypatch due to sdl2_ttf version mismatch. Still need to figure out the static libs

depili commented 1 year ago

And silly me, the monkeypatch I did was only necesserry becase I didn't update go-sdl2.