16

I'd like to link libpng found by pkg-config statically.

pkg-config --libs --static libpng

outputs

-L/usr/local/Cellar/libpng/1.6.15/lib -lpng16 -lz

I have both libpng16.a libpng16.dylib in that directory, and if I use these flags the library gets linked dynamically.

How can I tell either pkg-config or the linker (preferably in some portable-ish way) that I really want it linked statically?

I've tried adding -static before pkg-config's flags, but that makes clang's ld try and fail to link "crt0.o".

SSC
  • 1,311
  • 5
  • 18
  • 29
Kornel
  • 97,764
  • 37
  • 219
  • 309

5 Answers5

9

Try:

-L/usr/local/Cellar/libpng/1.6.15/lib -l:libpng16.a -lz

Using -l with a : character allows you to specify the filename extension.

The -l: option is documented in the GNU ld 2.24 manual:

-l namespec

--library=namespec

Add the archive or object file specified by namespec to the list of files to link. This option may be used any number of times. If namespec is of the form :filename, ld will search the library path for a file called filename, otherwise it will search the library path for a file called libnamespec.a.

On systems which support shared libraries, ld may also search for files other than libnamespec.a. Specifically, on ELF and SunOS systems, ld will search a directory for a library called libnamespec.so before searching for one called libnamespec.a. (By convention, a .so extension indicates a shared library.) Note that this behavior does not apply to :filename, which always specifies a file called filename.

Quip Yowert
  • 444
  • 2
  • 7
  • 3
    That's interesting. Is that a documented option? Linker I have (from clang?) doesn't seem to support it: "ld: library not found for -l:libpng16.a". – Kornel Dec 22 '14 at 02:54
  • @porneL, yes, it's documented. I've edited in a quote from the manual. – Quip Yowert Dec 22 '14 at 06:20
9

The pkg-config --static option relies on proper tagging in the .pc files. If providing the --static option does not return correct information necessary to link against the libpng archive, then you cannot use pkg-config for that purpose.

I suspect libpng (along with a majority of other packages) dropped support for static linking some time after libpng 1.2. They may still provide a library archive, but the libpng pkg-config file is no longer properly tagged to support a static link. You will have to manually tell ld to use the static lib.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • 2
    What does the proper tagging for static libraries look like in the pc files? These days I often see a `lib.pc` and `lib-static.pc` -- surely that's not the "right" way, is it? – Levi Morrison Apr 20 '21 at 02:53
  • @LeviMorrison in the distant past, you would have, e.g. `LIBRUBY_A=lib${RUBY_SO_NAME}-static.a` along with `LIBRUBYARG_STATIC=-l${RUBY_SO_NAME}-static` which provided tagging for a static library (2012 timeframe with ruby 1.9) – David C. Rankin Apr 20 '21 at 03:28
6

You could edit the .pc file to make it support static linking, especially if you are in a position to be compiling, patching, and installing software yourself instead of relying on some Linux distribution.

Here is an example of a .pc file that supports both dynamic and static linking. This is taken from /usr/lib/x86_64-linux-gnu/pkgconfig/xcb.pc on my Ubuntu system:

prefix=/usr
exec_prefix=${prefix}
libdir=${prefix}/lib/x86_64-linux-gnu
includedir=${prefix}/include
xcbproto_version=1.11

Name: XCB
Description: X-protocol C Binding
Version: 1.11.1
Requires.private: pthread-stubs xau >= 0.99.2 xdmcp
Libs: -L${libdir} -lxcb
Libs.private: 
Cflags: -I${includedir}

If you run pkg-config --libs xcb, it assumes you want the dynamic version and it gives you just -lxcb. The xcb.so dynamically shared object will know how to load all of its own dependencies so you don't have to specify them when linking against it.

If you run pkg-config --libs xcb --static, then the .private fields come into play, and you get -lxcb -lXau -lXdmcp.

I have not encountered many build systems that know to pass the --static argument to pkg-config. So if your .pc file is only intended to support static linking, it's probably best to not use .private fields, and just provide all the dependencies people will need unconditionally. That way people can link against the library successfully even if they don't know it's static or don't know to pass --static to pkg-config.

David Grayson
  • 84,103
  • 24
  • 152
  • 189
  • But if the dynamic variant of the lib are also on the library search path like in the question this will still result in the linkage of the dynamic libs? – undefined Jul 12 '23 at 19:13
  • No, you pass `-static` or some equivalent option to the linker to tell it to use static libraries. – David Grayson Aug 18 '23 at 12:52
  • Yeah but when the static and the dynamic libs have the same name and are both on the search path the dynamic one will be preferred. So the static lib must have a different name. – undefined Aug 24 '23 at 15:46
0

Just adding to the post by @David Garyson above I would like to add . If a particular

*.pc file is unavailable with the command pkg-config --libs

then you might need to add a variable to your PATH

Perhaps you should add the directory containing `nice.pc' to the PKG_CONFIG_PATH environment variable
Aloy A Sen
  • 764
  • 5
  • 9
0

I use this trick in my Makefile.

LIBRARIES := $(shell pkg-config --libs libpng | sed -E 's/-l([a-z0-9]*)/-l:lib\1.a/g')

It grabs output from pkg config and expands it by prefixing each item with : and the lib, and post-fixing it with an .a. The end result is just what you need

-l:libpng.a -l:libz.a
Tomaz Stih
  • 529
  • 3
  • 10