Thread: Implicit make rules break test examples

Implicit make rules break test examples

From
Donald Dong
Date:
Hi,

In src/test/example, the implicit make rules produce errors:

make -C ../../../src/backend generated-headers
make[1]: Entering directory '/home/ddong/postgresql/bld/src/backend'
make -C catalog distprep generated-header-symlinks
make[2]: Entering directory '/home/ddong/postgresql/bld/src/backend/catalog'
make[2]: Nothing to be done for 'distprep'.
make[2]: Nothing to be done for 'generated-header-symlinks'.
make[2]: Leaving directory '/home/ddong/postgresql/bld/src/backend/catalog'
make -C utils distprep generated-header-symlinks
make[2]: Entering directory '/home/ddong/postgresql/bld/src/backend/utils'
make[2]: Nothing to be done for 'distprep'.
make[2]: Nothing to be done for 'generated-header-symlinks'.
make[2]: Leaving directory '/home/ddong/postgresql/bld/src/backend/utils'
make[1]: Leaving directory '/home/ddong/postgresql/bld/src/backend'
gcc -Wall -Wmissing-prototypes -Wpointer-arith
-Wdeclaration-after-statement -Werror=vla -Wendif-labels
-Wmissing-format-attribute -Wformat-security -fno-strict-aliasing
-fwrapv -fexcess-precision=standard -Wno-format-truncation -O2
-I/home/ddong/postgresql/bld/../src/interfaces/libpq
-I../../../src/include -I/home/ddong/postgresql/bld/../src/include
-D_GNU_SOURCE   -c -o testlibpq.o
/home/ddong/postgresql/bld/../src/test/examples/testlibpq.c
gcc -L../../../src/port -L../../../src/common -L../../../src/common
-lpgcommon -L../../../src/port -lpgport
-L../../../src/interfaces/libpq -lpq   -Wl,--as-needed
-Wl,-rpath,'/usr/local/pgsql/lib',--enable-new-dtags  testlibpq.o   -o
testlibpq
testlibpq.o: In function `exit_nicely':
testlibpq.c:(.text.unlikely+0x5): undefined reference to `PQfinish'
testlibpq.o: In function `main':
testlibpq.c:(.text.startup+0x22): undefined reference to `PQconnectdb'
testlibpq.c:(.text.startup+0x2d): undefined reference to `PQstatus'
testlibpq.c:(.text.startup+0x44): undefined reference to `PQexec’
…

I think the -lpq flag does not have any effects in the middle of the
arguments. It works if move the flag to the end:

gcc -L../../../src/port -L../../../src/common -L../../../src/common
-lpgcommon -L../../../src/port -lpgport
-L../../../src/interfaces/libpq -Wl,--as-needed
-Wl,-rpath,'/usr/local/pgsql/lib',--enable-new-dtags  testlibpq.o   -o
testlibpq -lpq

So I added an explicit rule to rearrange the flags:

gcc testlibpq.o -o testlibpq -L../../../src/port -L../../../src/common
-L../../../src/common -lpgcommon -L../../../src/port -lpgport
-L../../../src/interfaces/libpq -lpq   -Wl,--as-needed
-Wl,-rpath,'/usr/local/pgsql/lib',--enable-new-dtags

Then the make command works as expected. This is my first time writing
a patch. Please let me know what you think!

Thank you,
Happy new year!
Donald Dong


Re: Implicit make rules break test examples

From
Donald Dong
Date:
On Mon, Dec 31, 2018 at 11:24 PM Donald Dong <xdong@csumb.edu> wrote:
>
> Hi,
>
> In src/test/example, the implicit make rules produce errors:
>
> make -C ../../../src/backend generated-headers
> make[1]: Entering directory '/home/ddong/postgresql/bld/src/backend'
> make -C catalog distprep generated-header-symlinks
> make[2]: Entering directory '/home/ddong/postgresql/bld/src/backend/catalog'
> make[2]: Nothing to be done for 'distprep'.
> make[2]: Nothing to be done for 'generated-header-symlinks'.
> make[2]: Leaving directory '/home/ddong/postgresql/bld/src/backend/catalog'
> make -C utils distprep generated-header-symlinks
> make[2]: Entering directory '/home/ddong/postgresql/bld/src/backend/utils'
> make[2]: Nothing to be done for 'distprep'.
> make[2]: Nothing to be done for 'generated-header-symlinks'.
> make[2]: Leaving directory '/home/ddong/postgresql/bld/src/backend/utils'
> make[1]: Leaving directory '/home/ddong/postgresql/bld/src/backend'
> gcc -Wall -Wmissing-prototypes -Wpointer-arith
> -Wdeclaration-after-statement -Werror=vla -Wendif-labels
> -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing
> -fwrapv -fexcess-precision=standard -Wno-format-truncation -O2
> -I/home/ddong/postgresql/bld/../src/interfaces/libpq
> -I../../../src/include -I/home/ddong/postgresql/bld/../src/include
> -D_GNU_SOURCE   -c -o testlibpq.o
> /home/ddong/postgresql/bld/../src/test/examples/testlibpq.c
> gcc -L../../../src/port -L../../../src/common -L../../../src/common
> -lpgcommon -L../../../src/port -lpgport
> -L../../../src/interfaces/libpq -lpq   -Wl,--as-needed
> -Wl,-rpath,'/usr/local/pgsql/lib',--enable-new-dtags  testlibpq.o   -o
> testlibpq
> testlibpq.o: In function `exit_nicely':
> testlibpq.c:(.text.unlikely+0x5): undefined reference to `PQfinish'
> testlibpq.o: In function `main':
> testlibpq.c:(.text.startup+0x22): undefined reference to `PQconnectdb'
> testlibpq.c:(.text.startup+0x2d): undefined reference to `PQstatus'
> testlibpq.c:(.text.startup+0x44): undefined reference to `PQexec’
> …
>
> I think the -lpq flag does not have any effects in the middle of the
> arguments. It works if move the flag to the end:
>
> gcc -L../../../src/port -L../../../src/common -L../../../src/common
> -lpgcommon -L../../../src/port -lpgport
> -L../../../src/interfaces/libpq -Wl,--as-needed
> -Wl,-rpath,'/usr/local/pgsql/lib',--enable-new-dtags  testlibpq.o   -o
> testlibpq -lpq
>
> So I added an explicit rule to rearrange the flags:
>
> gcc testlibpq.o -o testlibpq -L../../../src/port -L../../../src/common
> -L../../../src/common -lpgcommon -L../../../src/port -lpgport
> -L../../../src/interfaces/libpq -lpq   -Wl,--as-needed
> -Wl,-rpath,'/usr/local/pgsql/lib',--enable-new-dtags
>
> Then the make command works as expected. This is my first time writing
> a patch. Please let me know what you think!
>
> Thank you,
> Happy new year!
> Donald Dong



--
Donald Dong

Attachment

Re: Implicit make rules break test examples

From
Tom Lane
Date:
Donald Dong <xdong@csumb.edu> writes:
> In src/test/example, the implicit make rules produce errors:

Hm.  "make" in src/test/examples works fine for me.

The only way I can account for the results you're showing is if your
linker is preferring libpq.a to libpq.so, so that reading the library
before the *.o files causes none of it to get pulled in.  But that
isn't the default behavior on any modern platform AFAIK, and certainly
isn't considered good practice these days.  Moreover, if that's what's
happening, I don't see how you would have managed to build PG at all,
because there are a lot of other places where our Makefiles write
$(LDFLAGS) before the *.o files they're trying to link.  Maybe we
shouldn't have done it like that, but it's been working for everybody
else.

What platform are you on exactly, and what toolchain (gcc and ld
versions) are you using?

            regards, tom lane


Re: Implicit make rules break test examples

From
Donald Dong
Date:
Thank you for the explanation! That makes sense. It is strange that it does not work for me.
 
What platform are you on exactly, and what toolchain (gcc and ld
versions) are you using?

I'm using Ubuntu 18.04.1 LTS.

gcc version:
gcc (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0

ld version:
GNU ld (GNU Binutils for Ubuntu) 2.30

Regards,
Donald Dong


On Tue, Jan 1, 2019 at 9:54 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Donald Dong <xdong@csumb.edu> writes:
> In src/test/example, the implicit make rules produce errors:

Hm.  "make" in src/test/examples works fine for me.

The only way I can account for the results you're showing is if your
linker is preferring libpq.a to libpq.so, so that reading the library
before the *.o files causes none of it to get pulled in.  But that
isn't the default behavior on any modern platform AFAIK, and certainly
isn't considered good practice these days.  Moreover, if that's what's
happening, I don't see how you would have managed to build PG at all,
because there are a lot of other places where our Makefiles write
$(LDFLAGS) before the *.o files they're trying to link.  Maybe we
shouldn't have done it like that, but it's been working for everybody
else.

What platform are you on exactly, and what toolchain (gcc and ld
versions) are you using?

                        regards, tom lane


--
Donald Dong

Re: Implicit make rules break test examples

From
Tom Lane
Date:
Donald Dong <xdong@csumb.edu> writes:
> Thank you for the explanation! That makes sense. It is strange that it does
> not work for me.

Yeah, I still can't account for the difference in behavior between your
platform and mine (I tried several different ones here, and they all
manage to build src/test/examples).  However, I'm now convinced that
we do have an issue, because I found another place that does fail on my
platforms: src/interfaces/libpq/test gives failures like

uri-regress.o: In function `main':
uri-regress.c:58: undefined reference to `pg_printf'

the reason being that the link command lists -lpgport before
uri-regress.o, and since we only make the .a flavor of libpgport, it's
definitely going to be order-sensitive.  (This has probably been busted
since we changed over to using snprintf.c everywhere, but nobody noticed
because this test isn't normally run.)

The reason we haven't noticed this already seems to be that in all the
places where it matters, we have explicit link rules that order things
like this:

    $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)

However, the places that are having problems are trying to rely on
gmake's implicit rule, which according to their manual is

  Linking a single object file
     `N' is made automatically from `N.o' by running the linker
     (usually called `ld') via the C compiler.  The precise command
     used is `$(CC) $(LDFLAGS) N.o $(LOADLIBES) $(LDLIBS)'.

So really the problem here is that we're doing the wrong thing by
injecting -l switches into LDFLAGS; it would be more standard to
put them into LDLIBS (or maybe LOADLIBES, though I think that's
not commonly used).

I hesitate to try to change that though.  The places that are messing with
that are injecting both -L and -l switches, and we want to keep putting
the -L switches into LDFLAGS because of the strong likelihood that the
initial (autoconf-derived) value of LDFLAGS contains -L switches; our
switches pointing at within-tree directories need to come first.
So the options seem to be:

1. Redefine our makefile conventions as being that internal -L switches
go into LDFLAGS_INTERNAL but internal -l switches go into LDLIBS_INTERNAL,
and we use the same recursive-expansion dance for LDLIBS[_INTERNAL] as for
LDFLAGS[_INTERNAL], and we have to start mentioning LDLIBS in our explicit
link rules.  This would be a pretty invasive patch, I'm afraid, and would
almost certainly break some third-party extensions' Makefiles.  It'd be
the cleanest solution in a green field, I think, but our Makefiles are
hardly a green field.

2. Be sure to override the gmake implicit link rule with an explicit
link rule everywhere --- basically like your patch, but touching more
places.  This seems like the least risky alternative in the short
run, but we'd be highly likely to reintroduce such problems in future.

3. Replace the default implicit link rule with one of our own.
Conceivably this also breaks some extensions' Makefiles, though
I think that's less likely.

I observe that ecpg's Makefile.regress is already doing #3:

%: %.o
    $(CC) $(CFLAGS) $< $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@

so what we'd be talking about is moving that to some more global spot,
probably Makefile.global.  (I wonder why the target is not specified
as $@$(X) here?)

I notice that the platform-specific makefiles in src/makefiles
are generally also getting it wrong in their implicit rules for
building shlibs, eg in Makefile.linux:

# Rule for building a shared library from a single .o file
%.so: %.o
    $(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_SL) -shared -o $@ $<

Per this discussion, that needs to be more like

    $(CC) $(CFLAGS) $< $(LDFLAGS) $(LDFLAGS_SL) -shared -o $@

in case a reference to libpgport or libpgcommon has been inserted
into LDFLAGS.  I'm a bit surprised that that hasn't bitten us
already.

            regards, tom lane


Re: Implicit make rules break test examples

From
Donald Dong
Date:
> I observe that ecpg's Makefile.regress is already doing #3:
> %: %.o
>         $(CC) $(CFLAGS) $< $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@
> so what we'd be talking about is moving that to some more global spot,
> probably Makefile.global.  (I wonder why the target is not specified
> as $@$(X) here?)


Thank you for pointing that out!
I think #3 is a better choice since it's less invasive and would
potentially avoid similar problems in the future. I think may worth
the risks of breaking some extensions. I moved the rule to the
Makefile.global and added  $(X) in case it's set.

I also updated the order in Makefile.linux in the same patch since
they have the same cause. I'm not sure if changes are necessary for
other platforms, and I am not able to test it, unfortunately.

I've built it again on Ubuntu and tested src/test/examples and
src/interfaces/libpq/test. There are no errors.

Thank you again for the awesome explanation,
Donald Dong

On Tue, Jan 1, 2019 at 11:54 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
>
> Donald Dong <xdong@csumb.edu> writes:
> > Thank you for the explanation! That makes sense. It is strange that it does
> > not work for me.
>
> Yeah, I still can't account for the difference in behavior between your
> platform and mine (I tried several different ones here, and they all
> manage to build src/test/examples).  However, I'm now convinced that
> we do have an issue, because I found another place that does fail on my
> platforms: src/interfaces/libpq/test gives failures like
>
> uri-regress.o: In function `main':
> uri-regress.c:58: undefined reference to `pg_printf'
>
> the reason being that the link command lists -lpgport before
> uri-regress.o, and since we only make the .a flavor of libpgport, it's
> definitely going to be order-sensitive.  (This has probably been busted
> since we changed over to using snprintf.c everywhere, but nobody noticed
> because this test isn't normally run.)
>
> The reason we haven't noticed this already seems to be that in all the
> places where it matters, we have explicit link rules that order things
> like this:
>
>         $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
>
> However, the places that are having problems are trying to rely on
> gmake's implicit rule, which according to their manual is
>
>   Linking a single object file
>      `N' is made automatically from `N.o' by running the linker
>      (usually called `ld') via the C compiler.  The precise command
>      used is `$(CC) $(LDFLAGS) N.o $(LOADLIBES) $(LDLIBS)'.
>
> So really the problem here is that we're doing the wrong thing by
> injecting -l switches into LDFLAGS; it would be more standard to
> put them into LDLIBS (or maybe LOADLIBES, though I think that's
> not commonly used).
>
> I hesitate to try to change that though.  The places that are messing with
> that are injecting both -L and -l switches, and we want to keep putting
> the -L switches into LDFLAGS because of the strong likelihood that the
> initial (autoconf-derived) value of LDFLAGS contains -L switches; our
> switches pointing at within-tree directories need to come first.
> So the options seem to be:
>
> 1. Redefine our makefile conventions as being that internal -L switches
> go into LDFLAGS_INTERNAL but internal -l switches go into LDLIBS_INTERNAL,
> and we use the same recursive-expansion dance for LDLIBS[_INTERNAL] as for
> LDFLAGS[_INTERNAL], and we have to start mentioning LDLIBS in our explicit
> link rules.  This would be a pretty invasive patch, I'm afraid, and would
> almost certainly break some third-party extensions' Makefiles.  It'd be
> the cleanest solution in a green field, I think, but our Makefiles are
> hardly a green field.
>
> 2. Be sure to override the gmake implicit link rule with an explicit
> link rule everywhere --- basically like your patch, but touching more
> places.  This seems like the least risky alternative in the short
> run, but we'd be highly likely to reintroduce such problems in future.
>
> 3. Replace the default implicit link rule with one of our own.
> Conceivably this also breaks some extensions' Makefiles, though
> I think that's less likely.
>
> I observe that ecpg's Makefile.regress is already doing #3:
>
> %: %.o
>         $(CC) $(CFLAGS) $< $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@
>
> so what we'd be talking about is moving that to some more global spot,
> probably Makefile.global.  (I wonder why the target is not specified
> as $@$(X) here?)
>
> I notice that the platform-specific makefiles in src/makefiles
> are generally also getting it wrong in their implicit rules for
> building shlibs, eg in Makefile.linux:
>
> # Rule for building a shared library from a single .o file
> %.so: %.o
>         $(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_SL) -shared -o $@ $<
>
> Per this discussion, that needs to be more like
>
>         $(CC) $(CFLAGS) $< $(LDFLAGS) $(LDFLAGS_SL) -shared -o $@
>
> in case a reference to libpgport or libpgcommon has been inserted
> into LDFLAGS.  I'm a bit surprised that that hasn't bitten us
> already.
>
>                         regards, tom lane



-- 
Donald Dong

Attachment

Re: Implicit make rules break test examples

From
Tom Lane
Date:
Donald Dong <xdong@csumb.edu> writes:
> I think #3 is a better choice since it's less invasive and would
> potentially avoid similar problems in the future. I think may worth
> the risks of breaking some extensions. I moved the rule to the
> Makefile.global and added  $(X) in case it's set.

Yeah, I think #3 is the best choice too.

I'm not quite sure about the $(X) addition --- it makes the output
file not agree with what gmake thinks the target is.  However, I
observe other places doing the same thing, so let's try that and
see what the buildfarm thinks.

> I also updated the order in Makefile.linux in the same patch since
> they have the same cause. I'm not sure if changes are necessary for
> other platforms, and I am not able to test it, unfortunately.

That's what we have a buildfarm for.  Pushed, we'll soon find out.

            regards, tom lane