Re: meson's in-tree libpq header search order vs -Dextra_include_dirs

Tristan Partin <tristan@partin.io>

From: "Tristan Partin" <tristan@partin.io>
To: "Tom Lane" <tgl@sss.pgh.pa.us>
Cc: "Thomas Munro" <thomas.munro@gmail.com>, "pgsql-hackers" <pgsql-hackers@postgresql.org>
Date: 2025-11-04T06:17:45Z
Lists: pgsql-hackers
On Mon Nov 3, 2025 at 12:14 AM CST, Tom Lane wrote:
> "Tristan Partin" <tristan@partin.io> writes:
>> What is the benefit of -Dextra_include_dirs when you could use -Dc_flags 
>> or CFLAGS to specify extra include directories? If you tried either of 
>> those as an alternative, would they fix the issue? The existence of the 
>> option goes all the way back to the initial commit of the meson port, so 
>> I presume it exists to mirror --with-includes, but why does that exist?
>
> --with-includes, and likewise --with-libs, exist because there are
> platforms that require it.  For example, on pretty much any
> BSD-derived system, the core /usr/include and /usr/lib files are very
> limited and you'll need to point at places like /usr/pkg/include or
> /opt/local/include or whatever to pull in non-core packages.
>
> I see your point about putting -I flags into CFLAGS, but what you
> are missing is that the order of these flags is unbelievably critical,
> so "just shove it into CFLAGS" is a recipe for failure, especially
> if you haven't even stopped to think about which end to add it at.
> We've learned over decades of trial-and-error with the makefile system
> that treating -I and -L flags specially is more reliable.  (See for
> example all the logic in our autoconf scripts to forcibly separate
> -I and -L out of sources like pkg-config.  Tracing that stuff back to
> the originating commits and mail discussions would be a constructive
> learning exercise.)

I'm well aware of ordering dependencies, and how annoying they can be. 
The perils of C will outlive us all! Given your message and Thomas's 
patch, I decided to take a look at the autotools build on PG 16 (since 
that is what I had checked out, but maybe also maybe useful as the 
original Meson build) and how it compared. Thomas has this hunk in his 
patch:

	diff --git a/src/test/isolation/meson.build b/src/test/isolation/meson.build
	index a180e4e2741..660b11eff8b 100644
	--- a/src/test/isolation/meson.build
	+++ b/src/test/isolation/meson.build
	@@ -35,7 +35,7 @@ pg_isolation_regress = executable('pg_isolation_regress',
	   isolation_sources,
	   c_args: pg_regress_cflags,
	   include_directories: pg_regress_inc,
	-  dependencies: [frontend_code, libpq],
	+  dependencies: [libpq, frontend_code],
	   kwargs: default_bin_args + {
	     'install_dir': dir_pgxs / 'src/test/isolation',
	   },
	@@ -52,7 +52,7 @@ endif
	 isolationtester = executable('isolationtester',
	   isolationtester_sources,
	   include_directories: include_directories('.'),
	-  dependencies: [frontend_code, libpq],
	+  dependencies: [libpq, frontend_code],
	   kwargs: default_bin_args + {
	     'install_dir': dir_pgxs / 'src/test/isolation',
	   },

Taking a look, specifically, at isolationtester, I get the following 
final compilation line for isolationtester.o (please forgive the macOS garbage):

	gcc -Wall -Wmissing-prototypes -Wpointer-arith \
		-Wdeclaration-after-statement -Werror=vla \
		-Werror=unguarded-availability-new -Wendif-labels \
		-Wmissing-format-attribute -Wcast-function-type \
		-Wformat-security -fno-strict-aliasing -fwrapv \
		-fexcess-precision=standard -Wno-unused-command-line-argument \
		-Wno-compound-token-split-by-macro -Wno-format-truncation \
		-Wno-cast-function-type-strict -O2 -I. \
		-I/Users/tristan.partin/Projects/work/postgres/build-autotools/../src/test/isolation \
		-I/Users/tristan.partin/Projects/work/postgres/build-autotools/../src/interfaces/libpq \
		-I/Users/tristan.partin/Projects/work/postgres/build-autotools/../src/test/isolation/../regress \
		-I../../../src/include \
		-I/Users/tristan.partin/Projects/work/postgres/build-autotools/../src/include \
		-isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX26.0.sdk \
		-c -o isolationtester.o \
		/Users/tristan.partin/Projects/work/postgres/build-autotools/../src/test/isolation/isolationtester.c

The first include directory that isn't the source or build directory is 
the in-tree libpq headers. I assume that is controlled by:

	override CPPFLAGS := -I. -I$(srcdir) -I$(libpq_srcdir) \
		-I$(srcdir)/../regress $(CPPFLAGS)

Thomas's patch seemingly makes the meson build equivalent to the
autotools build. Just for good measure, following --with-includes, the 
include directories in that configure argument end up in CPPFLAGS:

	CPPFLAGS="$CPPFLAGS $INCLUDES"

where INCLUDES is:

	#
	# Include directories
	#
	ac_save_IFS=$IFS
	IFS="${IFS}${PATH_SEPARATOR}"
	# SRCH_INC comes from the template file
	for dir in $with_includes $SRCH_INC; do
	  if test -d "$dir"; then
	    INCLUDES="$INCLUDES -I$dir"
	  else
	    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Include directory $dir does not exist." >&5
	$as_echo "$as_me: WARNING: *** Include directory $dir does not exist." >&2;}
	  fi
	done
	IFS=$ac_save_IFS

From my perspective, it looks like the autotools build has just been 
_lucky_ to avoid this problem. I don't see anything that inherently 
prevents the problem that Thomas ran into. In my opinion Thomas's patch 
is just a parity patch. It's incredible that it took this long to find.

-- 
Tristan Partin
Databricks (https://databricks.com)