Cannot Run Sample on Arch Linux
The example has a couple of issues for me. I'm curious which compiler accepts an argument -bundle and what it means. Both GCC and Clang complain about it - on GCC its fatal. Clang just warns that its unused. With either compiler, linking fails due to ruby symbols unfound. If I add -lruby to the args, then it builds test_ruby.bundle but ruby is unable to load this file. If I rename test_ruby.bundle to test_ruby.so then I get a spectacular seg fault and stack trace.
Summary of relevant versions/info:
crystal --version
Crystal 0.23.1 (2017-09-10) LLVM 5.0.0
[] ~/play/crystal/crystal_ruby <master> ✗ gcc --version
gcc (GCC) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[] ~/play/crystal/crystal_ruby <master> ✗ clang --version
clang version 5.0.0 (tags/RELEASE_500/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
[] ~/play/crystal/crystal_ruby <master> ✗
[] ~/play/crystal/crystal_ruby <master> ✗ ruby --version
ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-linux]
[] ~/play/crystal/crystal_ruby <master> ✗ ldd test_ruby.bundle
linux-vdso.so.1 (0x00007ffcbfbf3000)
libruby.so.2.4 => /usr/lib/libruby.so.2.4 (0x00007fbaae086000)
libpcre.so.1 => /usr/lib/libpcre.so.1 (0x00007fbaade13000)
libgc.so.1 => /usr/lib/libgc.so.1 (0x00007fbaadba9000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fbaad98b000)
libevent-2.1.so.6 => /usr/lib/libevent-2.1.so.6 (0x00007fbaad735000)
librt.so.1 => /usr/lib/librt.so.1 (0x00007fbaad52d000)
libdl.so.2 => /usr/lib/libdl.so.2 (0x00007fbaad329000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007fbaad112000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fbaacd5b000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007fbaae7bd000)
libcrypt.so.1 => /usr/lib/libcrypt.so.1 (0x00007fbaacb23000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007fbaac7d7000)
libatomic_ops.so.1 => /usr/lib/libatomic_ops.so.1 (0x00007fbaac5d4000)
libcrypto.so.1.1 => /usr/lib/libcrypto.so.1.1 (0x00007fbaac154000)
Changes I had to make to Makefile to get it to even build:
diff --git a/Makefile b/Makefile
index a223fa1..332da44 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
test_ruby.bundle: sample/test_ruby.cr
- crystal sample/test_ruby.cr --link-flags "-dynamic -bundle -Wl,-undefined,dynamic_lookup" -o test_ruby.bundle
+ crystal sample/test_ruby.cr --link-flags "-dynamic -Wl,-undefined,dynamic_lookup,-lruby" -o test_ruby.bundle
irb: test_ruby.bundle
irb -rtest_ruby -I.
Results of running make irb:
make irb
irb -rtest_ruby -I.
/usr/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require':LoadError: cannot load such file -- test_ruby
irb(main):001:0>
On macOS for me:
$ man ld | grep bundle
...others
-bundle Produce a mach-o bundle that has file type MH_BUNDLE.
-dynamic The default. Implied by -dylib, -bundle, or -execute
...others
$ ld -v
@(#)PROGRAM:ld PROJECT:ld64-609
BUILD 07:59:13 Aug 25 2020
configured to support archs: armv6 armv7 armv7s arm64 arm64e arm64_32 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em
LTO support using: LLVM version 12.0.0, (clang-1200.0.32.2) (static support for 27, runtime is 27)
TAPI support using: Apple TAPI version 12.0.0 (tapi-1200.0.23)
So maybe it might not be needed 🤷🏻 For me, I found it to have the same effect as using -shared; the plus side with -shared is that it seems to work for generating .so too. So what I found to work for me (for both macOS and Ubuntu) was along these lines:
CRYSTAL = crystal
PLATFORM = $(shell uname -s)
ifeq "$(PLATFORM)" "Darwin"
TARGET = ../../lib/gls.bundle
endif
ifeq "$(PLATFORM)" "Linux"
TARGET = ../../lib/gls.so
endif
build: ./src/gloss.cr
$(CRYSTAL) build --link-flags "-shared -dynamic -Wl,-undefined,dynamic_lookup" $< -o $(TARGET) --release
Note the release flag too - it works for me on macOS without it, but when I didn't include it in Ubuntu I got the lovely:
/usr/bin/ld: /my/file/path.cr: version node not found for symbol *Slice(UInt8)@Slice(T)#initialize:read_only<Pointer(UInt8), (Int32 | UInt32 | UInt64), Bool>:Int32
/usr/bin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status
My system specs: macOS:
Catalina, 10.15.6 crystal version 0.35.1 (via homebrew) llvm:
llvm: stable 10.0.1 (bottled), HEAD [keg-only]
Next-gen compiler infrastructure
https://llvm.org/
/usr/local/Cellar/llvm/10.0.1_1 (7,029 files, 1GB)
Poured from bottle on 2020-12-17 at 13:56:53
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/llvm.rb
License: Apache-2.0
Linux:
Ubuntu 20.04.2 LTS, running with docker crystal
Crystal 0.36.1 [c3a3c1823] (2021-02-02)
LLVM: 10.0.0
Default target: x86_64-unknown-linux-gnu