Open HertzDevil opened 7 months ago
I think your test for stdc++
in an empty file is flawed. The name of the linked executable is ./test
, not a.out
(which is probably an artifact from building something else).
An empty file has no business linking libstdc++
for no reason.
$ crystal build --prelude=empty --stdin-filename=test <<< ""
$ ldd test
linux-vdso.so.1 (0x00007fff38e2f000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f09201a9000)
/home/linuxbrew/.linuxbrew/lib/ld.so => /lib64/ld-linux-x86-64.so.2 (0x00007f09203e5000)
Nevertheless, even without the explicit stdc++
lib mention, a Crystal program linking libllvm
builds just fine:
$ bin/crystal build spec/std/llvm/llvm_spec.cr
$ ldd llvm_spec
linux-vdso.so.1 (0x00007ffc2d19e000)
libLLVM-17.so => /home/linuxbrew/.linuxbrew/lib/libLLVM-17.so (0x00007f2de2fd0000)
libpcre2-8.so.0 => /home/linuxbrew/.linuxbrew/lib/libpcre2-8.so.0 (0x00007f2de2f2d000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f2de2e39000)
libgc.so.1 => /home/linuxbrew/.linuxbrew/lib/libgc.so.1 (0x00007f2de2cec000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f2de2ce5000)
libevent-2.1.so.7 => /home/linuxbrew/.linuxbrew/lib/libevent-2.1.so.7 (0x00007f2de2c89000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f2de2c84000)
libgcc_s.so.1 => /home/linuxbrew/.linuxbrew/lib/gcc/current/libgcc_s.so.1 (0x00007f2de2c5d000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2de2a35000)
/home/linuxbrew/.linuxbrew/lib/ld.so => /lib64/ld-linux-x86-64.so.2 (0x00007f2dec1cf000)
libffi.so.8 => /home/linuxbrew/.linuxbrew/lib/../lib/libffi.so.8 (0x00007f2de2a22000)
libedit.so.0 => /home/linuxbrew/.linuxbrew/lib/../lib/libedit.so.0 (0x00007f2de29e0000)
libz3.so.4.12 => /home/linuxbrew/.linuxbrew/lib/../lib/libz3.so.4.12 (0x00007f2de1993000)
libz.so.1 => /home/linuxbrew/.linuxbrew/lib/../lib/libz.so.1 (0x00007f2de1978000)
libzstd.so.1 => /home/linuxbrew/.linuxbrew/lib/../lib/libzstd.so.1 (0x00007f2de1865000)
libncursesw.so.6 => /home/linuxbrew/.linuxbrew/lib/../lib/libncursesw.so.6 (0x00007f2de17e8000)
libstdc++.so.6 => /home/linuxbrew/.linuxbrew/lib/../lib/libstdc++.so.6 (0x00007f2de1532000)
libstdc++
is a dependency of libllvm
so I'd suspect it should be part of the lib configuration, but apparently it isn't:
$ /home/linuxbrew/.linuxbrew/bin/llvm-config --libs --system-libs --ldflags
-L/home/linuxbrew/.linuxbrew/Cellar/llvm/17.0.6_1/lib
-lLLVM-17
So it seems to be indeed automatically linked with gcc
when needed, even without an explicit lib specification.
I guess that leaves the first option open.
Replicate what Clang does to detect the GNU toolchain. Probably not worth the effort.
This might be relevant in the context of #14332, though.
If cc
is indeed GCC or Clang, then cc -print-search-dirs
gives you where to look for the compiler-specific libraries:
`#{ARGV.shift? || ENV["CC"]? || "cc"} -print-search-dirs`.each_line do |line|
libraries = line.lchop?("libraries: =") || next
libraries.split(Process::PATH_DELIMITER)
.map { |dir| File.expand_path(dir) }
.uniq!
.each { |dir| puts dir }
end
On Debian this gives the following:
/usr/lib/gcc/x86_64-linux-gnu/14/
/usr/x86_64-linux-gnu/lib/x86_64-linux-gnu/14/
/usr/x86_64-linux-gnu/lib/x86_64-linux-gnu/
/usr/x86_64-linux-gnu/lib/
/usr/lib/x86_64-linux-gnu/14/
/usr/lib/x86_64-linux-gnu/
/usr/lib/
/lib/x86_64-linux-gnu/14/
/lib/x86_64-linux-gnu/
/lib/
with clang-15
:
/usr/lib/llvm-15/lib/clang/15.0.7
/usr/lib/gcc/x86_64-linux-gnu/14
/usr/lib64
/lib/x86_64-linux-gnu
/lib64
/usr/lib/x86_64-linux-gnu
/lib
/usr/lib
and on MSYS2:
C:\msys64\ucrt64\lib\gcc\x86_64-w64-mingw32\14.2.0\
C:\msys64\ucrt64\lib\gcc\
C:\msys64\ucrt64\x86_64-w64-mingw32\lib\x86_64-w64-mingw32\14.2.0\
C:\msys64\ucrt64\x86_64-w64-mingw32\lib\
C:\msys64\ucrt64\lib\x86_64-w64-mingw32\14.2.0\
C:\msys64\ucrt64\lib\
D:\a\msys64\ucrt64\lib\x86_64-w64-mingw32\14.2.0\
D:\a\msys64\ucrt64\lib\
As mentioned in #14386, typically
libstdc++.so
doesn't exist on any standard locations on a Linux system, and instead onlylibstdc++.so.6
can be found. This meansLibLLVM
, which currently uses@[Link("stdc++")]
on non-Windows targets, will fail to link in interpreted code. The actual library without a version suffix is part of a GCC installation:Both of them are symlinks to
../../../x86_64-linux-gnu/libstdc++.so.6
, i.e./lib/x86_64-linux-gnu/libstdc++.so.6
. If GCC is the compiler for non-interpreted code, obviously it has access to its own installation prefix; if Clang is used, apparently it has an entire file dedicated to detecting GCC toolchains, in order to pick up the above directories and pass them to the underlying linker (ld
orld.lld
).I could see a few options if we want this to work:
@[Link("stdc++")]
. Compiling an empty file will automatically link in a few libraries unless we do something funny to the linker flags:Then
libstdc++.so.6
should be implicitly available from the interpreter itself. But this seems a bit fragile.$CC
to somehow emit its library search paths, then explicitly add them to our linker command in both compiled and interpreted code. This is somewhat similar to what we do for MSVC.