Search code examples
clinuxmakefilepkg-config

What, exactly, does 'pkg-config --exists' do?


I recently tried installing an app from source (dwb on Debian Wheezy if it makes a difference). While installing, it would choke on some dependency problem, but to me it seemed I was meeting that dependency. I wasn't the only person with this problem. Which got me poking around in the project's config.mk.

In config.mk I found several blocks that looked like this:

REQPKG=foo
ifeq ($(shell pkg-config --exists $(REQPKG) && echo 1),1)
LIBS=$(REQPKG)
else
$(error Cannot find $(REQPKG))
endif

Which seems very counter intuitive to me. I searched and searched. Read the man page, consulted google. Read everything I could about pkg-config and found nothing. The man page is particularly frustrating as it simply lists '--exists' as a flag and gives no description (I guess it's as self explanatory as --help).

I began thinking that Debian's pkg-config had a bug where it returned inverse results. But, as it turns out 'pkg-config --exists' is supposed to return 0 (i.e. False) when the requested package is present.

Why is this? Wouldn't it produce cleaner code to return True/False or 1/0 indicating the presence of the required package? You could do this:

if (shell pkg-config --exists foo)
/*do things*/
else
/*throw error*/
endif

Instead of what looks to me like:

ifeq (($(not(True) && True)),True)
/*do things*/
else [...]

What am I missing about pkg-config? Does it act this way because it's a shell utility and some strange convention regarding them?

Also, why is the documentation so sparse? Am I missing a resource that would give the info I was looking for?

PS I don't have any real experience with C, so if my example code looks weird...


Solution

  • pkg-config --exists doesn't create any output it simply returns with an exit code of 0 for success and 1 for failure.

    && in the shell runs the right-hand side when the left-hand side returns success.

    So that line is running pkg-config --exists and iff it returns true (return code of 0) it then echos a 1 as output. That 1 is then compared against the 1 in the ifeq.

    And as to why you can't do something simpler here the answer is because make (when not in target rules) doesn't deal with program return codes. Specifically $(shell) pays the return code of the shell command being run no attention at all.

    Personally, I'd probably have written that test as either:

    ifeq ($(shell pkg-config --exists $(REQPKG); echo $?),0)
    

    or something like

    REQPKG=foo
    REQPKG:=$(shell pkg-config --exists $(REQPKG) && echo '$(REQPKG)')
    ifneq ($(REQPKG),)
        LIBS=$(REQPKG)
    else
        $(error ...)
    fi