TLDR I tried to read the clang llvm documentation to find a way to pass library path, I wasn't successful. Then I searched and found a solution. I am curious where I can find the documentation of my solution.
Details and why
I was trying to run ruby's bundle on my catalina and I faced this error:
ld: library not found for -lssl
I reinstalled openssl using brew install openssl
and then brew link openssl
I received the follwoing response from it:
Warning: Refusing to link macOS provided/shadowed software: openssl@1.1
If you need to have openssl@1.1 first in your PATH run:
echo 'export PATH="/usr/local/opt/openssl@1.1/bin:$PATH"' >> ~/.zshrc
For compilers to find openssl@1.1 you may need to set:
export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib"
export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include"
For pkg-config to find openssl@1.1 you may need to set:
export PKG_CONFIG_PATH="/usr/local/opt/openssl@1.1/lib/pkgconfig"
While I appreciated brew's effort to make it work non of those worked. I narrowed the linker issue to this to see what's going on:
clang -dynamic -bundle -o asdf -L/usr/local/Cellar/mysql/8.0.19/lib -lmysqlclient -lssl -lcrypt -v
Finally using LIBRARY_PATH
I made passed the enviornment variable
export LIBRARY_PATH=/usr/local/opt/openssl@1.1/lib/
You were able to make the clang
linkage:
clang -dynamic -bundle -o asdf -L/usr/local/Cellar/mysql/8.0.19/lib -lmysqlclient -lssl -lcrypt -v
succeed when it otherwise failed by setting:
export LIBRARY_PATH=/usr/local/opt/openssl@1.1/lib/
in the environment of the clang
command.
That's evidence that clang
is influenced by the LIBRARY_PATH
environment
variable in the same way as GCC compilers.
LIBRARY_PATH
is not mentioned in the ENVIRONMENT
section of man clang
,
or indeed at all, so this GCC-like behaviour can strictly be viewed as not mandatory.
It seems likely however that the omission is an oversight in the manual,
since clang
generally strives to be an unobtrusive substitute for gcc
. If
we run a Linux clang
linkage in verbose mode:
$ export LIBRARY_PATH=/wheres/wally; clang -v main.o -L. -lfoo -lbar
clang version 10.0.0-4ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/8
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/8
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/9
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9
Candidate multilib: .;@m64
Selected multilib: .;@m64
"/usr/bin/ld" -z relro --hash-style=gnu --build-id --eh-frame-hdr \
-m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o a.out \
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crt1.o \
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o \
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/crtbegin.o \
-L. -L/usr/bin/../lib/gcc/x86_64-linux-gnu/9 \
-L/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu \
-L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu \
-L/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../.. \
-L/usr/lib/llvm-10/bin/../lib -L/lib -L/usr/lib \
-L/wheres/wally \ # < There's wally!
main.o -lfoo -lbar -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc \
--as-needed -lgcc_s --no-as-needed \
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/crtend.o \
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
we observe clang
inserting the expansion of -L${LIBRARY_PATH}
into
the ld
commandline after all of the other -Ldir
options. And if we
track down LIBRARY_PATH
in the clang
source tree,
we'll see the code that makes it do so.
In the ENVIRONMENT
section of man gcc
,
LIBRARY_PATH
is documented:
LIBRARY_PATH
The value of LIBRARY_PATH is a colon-separated list of directories, much like PATH . When configured as a native compiler, GCC tries the directories thus specified when searching for special linker files, if it can't find them using GCC_EXEC_PREFIX . Linking using GCC also uses these directories when searching for ordinary libraries for the -l option (but directories specified with -L come first).
and the same appears verbatim in GCC online documentation: 3.21 Environment Variables Affecting GCC
What clang
does with LIBRARY_PATH
conforms with the sentence I've emphasised.
It's worth knowing that while using LIBRARY_PATH
for this purpose may have got
you out of a jam, it is not favoured in regular linkage practice, because it is
likely to be an invisible hand when you are studying the output of a
linkage: its effect is only revealed in verbose mode (by either gcc
or clang
). The
installer's recommendation:
export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib"
is what you'd expect. I've no insight into why it didn't work for you.