Forcing Clang to statically link against an installed library

02 February 2018
Posted in: programming LLVM GCC C++ C Clang
Jon Williams

When building redistributable binary plugins, we cannot rely on the end user having installed library dependencies. In my case, I need my code to be statically linked against libusb and librtlsdr.

In the past, the venerable GCC allowed us to specify static linking by specifying a switch such as -l:rtlsdr and dynamic linking with -lrtlsdr. The modern LLVM Clang compiler is now the C/C++ compiler of choice on many platforms including in Apple’s Xcode. Its linker lacks an option to force static linking when resolving a library passed in. When both a static and dynamic version of a library exist, we must explicitly pass the path to the static library if we wish to link statically with Clang.

Static linking with full paths

c++ -o plugin.dylib object.cpp.o … /usr/local/Cellar/libusb/1.0.21/lib/libusb-1.0.a /usr/local/Cellar/librtlsdr/0.5.3/lib/librtlsdr.a

Dynamic linking (no full paths needed)

c++ -o plugin.dylib object.cpp.o … -lusb-1.0 -lrtlsdr -lusb-1.0

Getting your build system (e.g. make) to determine the exact path to a static version of a library can be trying. Fortunately many modern packages include pkg-config which will let you do things such as the following in your Makefile

PKGCONFIG= pkg-config
PACKAGES= libusb-1.0 librtlsdr

# FLAGS will be passed to both the C and C++ compiler

FLAGS += $(shell $(PKGCONFIG) --cflags $(PACKAGES))

The compiler will get the flags -I/usr/local/Cellar/librtlsdr/0.5.3/include/ -I/usr/local/Cellar/libusb/1.0.21/include/libusb-1.0 to set the include path. pkg-config also can be used to set linker flags with --libs; however, in my experience the --static option does not correctly emit static linking options. My trick for getting make to emit the correct static linking options is:

LDFLAGS +=$(shell $(PKGCONFIG) --variable=libdir libusb-1.0)/libusb-1.0.a
LDFLAGS +=$(shell $(PKGCONFIG) --variable=libdir librtlsdr)/librtlsdr.a

I’ve had varying success with passing static libraries on the command line, particularly running into problems on Linux, but it works on Windows (with some conditional code for library naming) and Mac.

If a library lacks pkg-config, you could parse the output of ld -v to enumerate search paths for find.

Validating Static Linking

Windows Linux Mac
objdump file.dll ldd file.so otool -L file.dylib