Crystal Build error issue with libgc on Mac OS 15.5

I posted a question on StackOverflow, but figured I’d probably get more visibility here, as I see the mailings, etc.

But here’s the stackoverflow link (I can post the answer when we get it resolved from here, etc):
https://stackoverflow.com/questions/79660994/crystal-build-error-issue-with-libgc-on-mac-os-15-5

here’s my question and context:


ran an into an error, compiling or running a crystal with kemal web framework getting started app:

$ crystal build --link-flags="~/.asdf/shims/crystal/embedded/lib/libgc.a" src/early-registration-api-cr.cr
clang: error: no such file or directory: '/Users/matt.swieboda@tastytrade.com/.asdf/shims/crystal/embedded/lib/libgc.a'
Error: execution of command failed with exit status 1: cc "${@}" -o /Users/matt.swieboda@tastytrade.com/.cache/crystal/Users-matt.swieboda@tastytrade.com-.asdf-installs-crystal-1.16.3-src-ecr-process.cr/macro_run ~/.asdf/shims/crystal/embedded/lib/libgc.a -rdynamic -lgc -liconv

I’m on Mac OS 15.5 Sequoia, on a work laptop, but permissions should be decently set (via asdf they are fine. ~/.asdf/ has full permissions, as does the ~/dev/cr directory my project is in. I’m using iTerm 2, and zsh. If anyone needs more context/info, I can happily provide it.

here is a potential solution I looked up, but I think it’s for *NIX / UNIX (and from 2016): execution of command failed with code: 1: `cc -o "/root/.cache/crystal/var-app-staging-new-http.cr

something with libgc is the issue.

using asdf and where crystal outputs:

$ where crystal
/Users/matt***/.asdf/shims/crystal

also this is on a work laptop with Zscaler, and to my knowledge no other libgc is installed via my homebrew for ex, but perhaps from Xcode command line tools, etc maybe.

can anyone help? Trying to get crystal over at the company I work for (Tastytrade, USA, based in Chicago, and parent company is IG in London, UK), to speed up the backend, and other interesting use-cases.

Thanks so much, in advance! I love the crystal community a lot, and happy to help contribute more and more to it.

Is it an option to try installing Crystal via brew? Or the universal tarball: https://github.com/crystal-lang/crystal/releases/download/1.16.3/crystal-1.16.3-1-darwin-universal.tar.gz?

Otherwise may just need to wait for someone more familiar with asdf.

1 Like

Why are you passing this path explicitly as a link flag? It does not seem to exist.
What happens if you just leave that option out?

2 Likes

I see that after installing Crystal with asdf, you had a problem when you first tried to run it. You then tried to fix this by adding --link-flags with the libgc path, but that gave a new error.

Could you please tell us what the original problem was before you used --link-flags?

If we know the first error, we might find a better solution by fixing the asdf installation instead of using a workaround. I think that is what straight-shoota meant.

1 Like

it wasn’t working with that option out, i was just trying my best guess as to where libgc.a might be. I can try with asdf with no --link-flags and share the output. And then i will try brew install crystal as this is a work laptop and i don’t need asdf but it was great for crystal version management on my personal laptop in the past

@straight-shoota @kojix2 here is the output using the asdf installed crystal, with no --link-flags arg.

I’m not sure what gc lib it’s trying to find, but i checked gc --version and gcc --version just in case.

Also, small thing, but might affect something, my home directory is stupid corporate long "/Users/matt.swieboda@company.com" with @ and . symbols, maybe that messes something up too, not sure.

15:42:15 ../early-registration-api-cr (main)$ crystal build src/early-registration-api-cr.cr
ld: library 'gc' not found
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Error: execution of command failed with exit status 1: cc "${@}" -o /Users/matt.swieboda@t-redacted-e.com/.cache/crystal/Users-matt.swieboda@t-redacted-e.com-.asdf-installs-crystal-1.16.3-src-ecr-process.cr/macro_run  -rdynamic -lgc -liconv
15:42:26 ../early-registration-api-cr (main)$ gc --version
zsh: command not found: gc
15:42:29 ../early-registration-api-cr (main)$ gcc --version
Apple clang version 17.0.0 (clang-1700.0.13.5)
Target: arm64-apple-darwin24.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

I uninstalled crystal via asdf and trying with brew install crystal now, and then will also try universal tarball if that doesn’t work either

installing with brew install crystal fixed the linker gc error issue. for now i will forgo using asdf since i don’t care right now as this is a work laptop and less steps for other coworkers to do. Thanks a lot for you help and diagnosing everyone! I might create new threads for any other issues I might encounter, you all are very helpful, and your time is much appreciated!

Cheers!

1 Like

I also, for more visibility, shared the solution copy/paste to StackOverflow question here: https://stackoverflow.com/a/79669741/1183537

libgc is an external garbage collector.

A garbage collector is a tool that automatically frees memory that is no longer in use.
This means you don’t need to manually manage memory like in C.
Crystal uses libgc instead of its own garbage collection system.

On macOS, you can check which dynamic libraries an executable links to using the otool -L command:

crystal build hello.cr
otool -L ./hello

Most Crystal programs will be dynamically linked to libgc. For example:

$ otool -L hello
hello:
	/opt/homebrew/opt/bdw-gc/lib/libgc.1.dylib (compatibility version 1.0.0, current version 1.5.4)
	/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)

As you can see, the executable is linked to libgc.1.dylib from the Homebrew directory.

This can be a problem when distributing your Crystal program, because the target machine may not have libgc.dylib installed.

To avoid this, you can link against the static version of the library (libgc.a) instead. Here’s how to build it:

git clone https://github.com/ivmai/bdwgc
cd bdwgc
mkdir build
cd build
cmake -DBUILD_SHARED_LIBS=OFF ..
cmake --build .
file libgc.a

Then compile your Crystal program with static linking:

crystal build hello.cr --link-flags "-L$(pwd) $(pwd)/libgc.a -lgc"

Now, your executable won’t depend on libgc.dylib anymore:

❯ otool -L hello
hello:
	/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)
1 Like

thanks, this helps. I was already using a Makefile with otool -L stuff in it, this helps explain why I would use that. Thanks a lot for the info @kojix2 :)

1 Like