Weird behavior in glibc Makefiles, or: another example why you should never build software as root user

Thomas Schwinge thomas@schwinge.name
Thu Sep 22 11:50:00 GMT 2011


Hi!

This is about an oddity in glibc's Makefiles.  The underlying Makefile
issue is generally valid even if it was triggered on GNU/Hurd in this
case.


My first email on this topic has been eaten by the libc-alpha moderators
(and I did not exactly enjoy their boilerplate answer); perhaps this one
will make it through?  At least I would consider it on-topic for
libc-alpha.


On Tue, 20 Sep 2011 10:49:06 +0200, I wrote:
> About a year ago I have once seen this while running ``make check'' after
> having run ``make check'' before on the same build tree.  Now, on a
> different system, I have seen it with a plain ``make''.  Mind you, *not*
> ``make install''.
> 
>     [...]
>     make  subdir=nss -C nss ..=../ others
>     make[2]: Entering directory `/media/erich/home/thomas/tmp/glibc/tschwinge/Roger_Whittaker/nss'
>     /usr/bin/install -c -m 644 ../include/pthread.h /usr/include/pthread.h
>     /usr/bin/install: cannot remove `/usr/include/pthread.h': Permission denied
>     make[2]: *** [/usr/include/pthread.h] Error 1
>     make[2]: Leaving directory `/media/erich/home/thomas/tmp/glibc/tschwinge/Roger_Whittaker/nss'
>     make[1]: *** [nss/others] Error 2
>     make[1]: Leaving directory `/media/erich/home/thomas/tmp/glibc/tschwinge/Roger_Whittaker'
>     make: *** [all] Error 2
> 
> That happend after I was editing nss/nss_db/db-initgroups.c, and then
> resuming the build.
> 
> I guess nobody has ever seen this before, or has an explanation for such
> behavior?
> 
> This is on GNU/Hurd (but I can't see why that would matter), with Debian
> make 3.81-8.1.
> 
> I will try poking around in the Makefiles later on...

Which I have now done, and here follows my analysis.

In the recent case, this behavior is triggered with
[glibc]/nss/nss_files/files-init.c.  That one contains #include
<nscd/nscd.h>.

[glibc]/nscd/nscd.h contains #include <pthread.h>.  <pthread.h> is
resolved to [glibc]/include/pthread.h which is a glibc-internal wrapper
that does #include_next <pthread.h> to get the real pthread header, and
additionally ``extern void __pthread_initialize (void) __attribute__
((weak));''.  On GNU/Hurd, the #include_next <pthread.h> resolves to
/usr/include/pthread.h, as our libpthread is not yet integrated with
glibc.  So far, so good; this works.

After the first build, [glibc.build]/nss/files-init.os.d contains these
dependency rules:

    $(common-objpfx)nss/files-init.os: \
     nss_files/files-init.c ../include/libc-symbols.h \
     $(common-objpfx)config.h \
     ../sysdeps/wordsize-32/symbol-hacks.h ../nscd/nscd.h \
     ../include/pthread.h /usr/include/pthread.h \
     /usr/include/pthread/pthread.h ../include/features.h \
     [...]

That is, [glibc.build]/nss/files-init.os depends on
/usr/include/pthread.h (which is correct).

Now, [glibc]/Makerules happens to contain the following rules:

    # This implicit rule installs headers from the source directory.
    # It may be ignored in preference to rules from sysd-rules to find
    # headers in the sysdeps tree.
    $(inst_includedir)/%.h: $(objpfx)%.h $(+force)
            $(do-install)
    $(inst_includedir)/%.h: %.h $(+force)
            $(do-install)
    $(inst_includedir)/%.h: $(..)include/%.h $(+force)
            $(do-install)

These are, of course intended for header installation.  (But are not
guarded for the ``make install'' case.)

The last of these can be expanded as follows:

    /usr/include/pthread.h: $(..)include/pthread.h $(+force)
            $(do-install)

Thus, we can see what happens -- due to the *.d file containing a
files-init.os: /usr/include/pthread dependency, the build system will try
to $(do-install) from include/pthread.h to /usr/include/pthread.h -- even
in a ``make all'' or ``make check'' case, not ``make install''!  This
will only be triggered on a re-make (after the *.d files have been
built), and it can also be triggered in the testsuite where there are
also several #include <pthread.h>.

At first I thought: ``Why would glibc ever install a header from
[glibc]/include/ to /usr/include/; aren't these purely for glibc-local
build-internal headers?''  But this is not true, as it turns out.  For
example, on x86 GNU/Linux, include/limits.h, include/values.h,
include/features.h, include/gnu-versions.h, include/bits/xopen_lim.h,
include/gnu/libc-version.h, include/stubs-biarch.h are installed from
[glibc]/include/ to /usr/include/.


Thinking about it, a cure is to *build* (as in ``make all'') with
``install_root=/INVALID'', thus invalidating the
``$(inst_includedir)/%.h: $(..)include/%.h'' rule.  This works; nice.

For a one-off build of glibc, this issue does never matter, as there are
no *.d files yet.


In the long term, we (GNU/Hurd) are planning on integrating our
libpthread with glibc, as there are other inter-dependency issues, too.
Doing so will resolve this specific case, but the general Makefile oddity
remains.


Grüße,
 Thomas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 489 bytes
Desc: not available
URL: <http://sourceware.org/pipermail/libc-alpha/attachments/20110922/bafa2b8f/attachment.sig>


More information about the Libc-alpha mailing list