From b88f2a8cad14c09bd872f303a27a60e93a916fea Mon Sep 17 00:00:00 2001 From: Sriram RK Date: Mon, 20 May 2024 01:38:59 -0500 Subject: [PATCH 1/1] AIX support, revert the changes from 0b16bb8776bb8. Trim AIX/XLC changes to support gcc only. --- Makefile | 2 - configure | 52 ++++---- configure.ac | 31 ++--- doc/src/sgml/dfunc.sgml | 19 +++ doc/src/sgml/installation.sgml | 118 +++++++++++++++++- doc/src/sgml/runtime.sgml | 23 ++++ meson.build | 57 +++++---- src/Makefile.shlib | 29 +++++ src/backend/Makefile | 20 +++ src/backend/meson.build | 15 +++ src/backend/port/aix/mkldexport.sh | 61 +++++++++ src/backend/utils/error/elog.c | 2 + src/backend/utils/misc/ps_status.c | 4 +- src/bin/pg_basebackup/t/010_pg_basebackup.pl | 3 +- src/bin/pg_verifybackup/t/008_untar.pl | 3 +- src/bin/pg_verifybackup/t/010_client_untar.pl | 3 +- src/include/c.h | 4 +- src/include/port/aix.h | 14 +++ src/include/storage/s_lock.h | 31 ++++- src/interfaces/libpq/Makefile | 2 +- src/interfaces/libpq/meson.build | 5 +- src/makefiles/Makefile.aix | 39 ++++++ src/port/README | 2 +- src/port/strerror.c | 2 + src/template/aix | 26 ++++ src/test/regress/Makefile | 5 + src/test/regress/expected/sanity_check.out | 29 +++++ src/test/regress/expected/test_setup.out | 4 + src/test/regress/regress.c | 40 ++++++ src/test/regress/sql/sanity_check.sql | 26 ++++ src/test/regress/sql/test_setup.sql | 5 + src/tools/gen_export.pl | 11 +- src/tools/pginclude/headerscheck | 1 + 33 files changed, 598 insertions(+), 90 deletions(-) create mode 100755 src/backend/port/aix/mkldexport.sh create mode 100644 src/include/port/aix.h create mode 100644 src/makefiles/Makefile.aix create mode 100644 src/template/aix diff --git a/Makefile b/Makefile index 8a2ec9396b..9bc1a4ec17 100644 --- a/Makefile +++ b/Makefile @@ -13,8 +13,6 @@ # AIX make defaults to building *every* target of the first rule. Start with # a single-target, empty rule to make the other targets non-default. -# (We don't support AIX anymore, but if someone tries to build on AIX anyway, -# at least they'll get the instructions to run 'configure' first.) all: all check install installdirs installcheck installcheck-parallel uninstall clean distclean maintainer-clean dist distcheck world check-world install-world installcheck-world: diff --git a/configure b/configure index 89644f2249..03271f1861 100755 --- a/configure +++ b/configure @@ -2988,6 +2988,7 @@ else # --with-template not given case $host_os in + aix*) template=aix ;; cygwin*|msys*) template=cygwin ;; darwin*) template=darwin ;; dragonfly*) template=netbsd ;; @@ -6849,6 +6850,11 @@ if test x"$pgac_cv_prog_CXX_cxxflags__fno_strict_aliasing" = x"yes"; then fi +elif test "$PORTNAME" = "aix"; then + # AIX's xlc has to have strict aliasing turned off too + # Igonoring the XLC falgs -qnoansialias, -qlonglong +{ $as_echo_n "Running AIX gcc for now... " >&6; } + fi # If the compiler knows how to hide symbols, add the switch needed for that to @@ -7003,6 +7009,9 @@ if test x"$pgac_cv_prog_CXX_cxxflags__fvisibility_inlines_hidden" = x"yes"; then fi have_visibility_attribute=$pgac_cv_prog_CC_cflags__fvisibility_hidden +elif test "$PORTNAME" = "aix"; then + # Note that xlc accepts -fvisibility=hidden as a file. + { $as_echo_n "Running AIX gcc for now... " >&6; } fi if test "$have_visibility_attribute" = "yes"; then @@ -12860,7 +12869,8 @@ fi fi -# Note: We can test for libldap_r only after we know PTHREAD_LIBS +# Note: We can test for libldap_r only after we know PTHREAD_LIBS; +# also, on AIX, we may need to have openssl in LIBS for this step. if test "$with_ldap" = yes ; then _LIBS="$LIBS" if test "$PORTNAME" != "win32"; then @@ -14718,6 +14728,10 @@ fi # spelling it understands, because it conflicts with # __declspec(restrict). Therefore we define pg_restrict to the # appropriate definition, which presumably won't conflict. +# +# Allow platforms with buggy compilers to force restrict to not be +# used by setting $FORCE_DISABLE_RESTRICT=yes in the relevant +# template. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 $as_echo_n "checking for C/C++ restrict keyword... " >&6; } if ${ac_cv_c_restrict+:} false; then : @@ -14764,7 +14778,7 @@ _ACEOF ;; esac -if test "$ac_cv_c_restrict" = "no"; then +if test "$ac_cv_c_restrict" = "no" -o "x$FORCE_DISABLE_RESTRICT" = "xyes"; then pg_restrict="" else pg_restrict="$ac_cv_c_restrict" @@ -16951,28 +16965,18 @@ _ACEOF # Compute maximum alignment of any basic type. -# -# We require 'double' to have the strictest alignment among the basic types, -# because otherwise the C ABI might impose 8-byte alignment on some of the -# other C types that correspond to TYPALIGN_DOUBLE SQL types. That could -# cause a mismatch between the tuple layout and the C struct layout of a -# catalog tuple. We used to carefully order catalog columns such that any -# fixed-width, attalign=4 columns were at offsets divisible by 8 regardless -# of MAXIMUM_ALIGNOF to avoid that, but we no longer support any platforms -# where TYPALIGN_DOUBLE != MAXIMUM_ALIGNOF. -# -# We assume without checking that long's alignment is at least as strong as -# char, short, or int. Note that we intentionally do not consider any types -# wider than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8 would be too -# much of a penalty for disk and memory space. - -MAX_ALIGNOF=$ac_cv_alignof_double - -if test $ac_cv_alignof_long -gt $MAX_ALIGNOF ; then - as_fn_error $? "alignment of 'long' is greater than the alignment of 'double'" "$LINENO" 5 -fi -if test x"$HAVE_LONG_LONG_INT_64" = xyes && test $ac_cv_alignof_long_long_int -gt $MAX_ALIGNOF ; then - as_fn_error $? "alignment of 'long long int' is greater than the alignment of 'double'" "$LINENO" 5 +# We assume long's alignment is at least as strong as char, short, or int; +# but we must check long long (if it is being used for int64) and double. +# Note that we intentionally do not consider any types wider than 64 bits, +# as allowing MAXIMUM_ALIGNOF to exceed 8 would be too much of a penalty +# for disk and memory space. + +MAX_ALIGNOF=$ac_cv_alignof_long +if test $MAX_ALIGNOF -lt $ac_cv_alignof_double ; then + MAX_ALIGNOF=$ac_cv_alignof_double +fi +if test x"$HAVE_LONG_LONG_INT_64" = xyes && test $MAX_ALIGNOF -lt $ac_cv_alignof_long_long_int ; then + MAX_ALIGNOF="$ac_cv_alignof_long_long_int" fi cat >>confdefs.h <<_ACEOF diff --git a/configure.ac b/configure.ac index c7322e292c..22069395a6 100644 --- a/configure.ac +++ b/configure.ac @@ -62,6 +62,7 @@ PGAC_ARG_REQ(with, template, [NAME], [override operating system template], # --with-template not given case $host_os in + aix*) template=aix ;; cygwin*|msys*) template=cygwin ;; darwin*) template=darwin ;; dragonfly*) template=netbsd ;; @@ -1385,7 +1386,8 @@ if test "$with_zstd" = yes ; then AC_CHECK_LIB(zstd, ZSTD_compress, [], [AC_MSG_ERROR([library 'zstd' is required for ZSTD support])]) fi -# Note: We can test for libldap_r only after we know PTHREAD_LIBS +# Note: We can test for libldap_r only after we know PTHREAD_LIBS; +# also, on AIX, we may need to have openssl in LIBS for this step. if test "$with_ldap" = yes ; then _LIBS="$LIBS" if test "$PORTNAME" != "win32"; then @@ -1643,8 +1645,12 @@ PGAC_TYPE_LOCALE_T # spelling it understands, because it conflicts with # __declspec(restrict). Therefore we define pg_restrict to the # appropriate definition, which presumably won't conflict. +# +# Allow platforms with buggy compilers to force restrict to not be +# used by setting $FORCE_DISABLE_RESTRICT=yes in the relevant +# template. AC_C_RESTRICT -if test "$ac_cv_c_restrict" = "no"; then +if test "$ac_cv_c_restrict" = "no" -o "x$FORCE_DISABLE_RESTRICT" = "xyes"; then pg_restrict="" else pg_restrict="$ac_cv_c_restrict" @@ -1996,22 +2002,11 @@ fi AC_CHECK_ALIGNOF(double) # Compute maximum alignment of any basic type. -# -# We require 'double' to have the strictest alignment among the basic types, -# because otherwise the C ABI might impose 8-byte alignment on some of the -# other C types that correspond to TYPALIGN_DOUBLE SQL types. That could -# cause a mismatch between the tuple layout and the C struct layout of a -# catalog tuple. We used to carefully order catalog columns such that any -# fixed-width, attalign=4 columns were at offsets divisible by 8 regardless -# of MAXIMUM_ALIGNOF to avoid that, but we no longer support any platforms -# where TYPALIGN_DOUBLE != MAXIMUM_ALIGNOF. -# -# We assume without checking that long's alignment is at least as strong as -# char, short, or int. Note that we intentionally do not consider any types -# wider than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8 would be too -# much of a penalty for disk and memory space. - -MAX_ALIGNOF=$ac_cv_alignof_double +# We assume long's alignment is at least as strong as char, short, or int; +# but we must check long long (if it is being used for int64) and double. +# Note that we intentionally do not consider any types wider than 64 bits, +# as allowing MAXIMUM_ALIGNOF to exceed 8 would be too much of a penalty +# for disk and memory space. if test $ac_cv_alignof_long -gt $MAX_ALIGNOF ; then AC_MSG_ERROR([alignment of 'long' is greater than the alignment of 'double']) diff --git a/doc/src/sgml/dfunc.sgml b/doc/src/sgml/dfunc.sgml index b94aefcd0c..554f9fac4c 100644 --- a/doc/src/sgml/dfunc.sgml +++ b/doc/src/sgml/dfunc.sgml @@ -202,4 +202,23 @@ gcc -G -o foo.so foo.o server expects to find the shared library files. + + diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml index 1b32d5ca62..60e9a34a03 100644 --- a/doc/src/sgml/installation.sgml +++ b/doc/src/sgml/installation.sgml @@ -3401,7 +3401,7 @@ export MANPATH PostgreSQL can be expected to work on current versions of these operating systems: Linux, Windows, - FreeBSD, OpenBSD, NetBSD, DragonFlyBSD, macOS, Solaris, and illumos. + FreeBSD, OpenBSD, NetBSD, DragonFlyBSD, macOS, AIX, Solaris, and illumos. Other Unix-like systems may also work but are not currently being tested. In most cases, all CPU architectures supported by a given operating system will work. Look in @@ -3445,6 +3445,122 @@ export MANPATH installation issues. + + AIX + + + AIX + installation on + + + + You can use GCC to build PostgreSQL + on AIX. + + + + AIX versions before 7.1 are no longer + tested nor supported by the PostgreSQL + community. + + + + Memory Management + + + + AIX can be somewhat peculiar with regards to the way it does + memory management. You can have a server with many multiples of + gigabytes of RAM free, but still get out of memory or address + space errors when running applications. One example + is loading of extensions failing with unusual errors. + For example, running as the owner of the PostgreSQL installation: + +=# CREATE EXTENSION plperl; +ERROR: could not load library "/opt/dbs/pgsql/lib/plperl.so": A memory address is not in the address space for the process. + + Running as a non-owner in the group possessing the PostgreSQL + installation: + +=# CREATE EXTENSION plperl; +ERROR: could not load library "/opt/dbs/pgsql/lib/plperl.so": Bad address + + Another example is out of memory errors in the PostgreSQL server + logs, with every memory allocation near or greater than 256 MB + failing. + + + + The overall cause of all these problems is the default bittedness + and memory model used by the server process. By default, all + binaries built on AIX are 32-bit. This does not depend upon + hardware type or kernel in use. These 32-bit processes are + limited to 4 GB of memory laid out in 256 MB segments using one + of a few models. The default allows for less than 256 MB in the + heap as it shares a single segment with the stack. + + + + In the case of the plperl example, above, + check your umask and the permissions of the binaries in your + PostgreSQL installation. The binaries involved in that example + were 32-bit and installed as mode 750 instead of 755. Due to the + permissions being set in this fashion, only the owner or a member + of the possessing group can load the library. Since it isn't + world-readable, the loader places the object into the process' + heap instead of the shared library segments where it would + otherwise be placed. + + + + The ideal solution for this is to use a 64-bit + build of PostgreSQL, but that is not always practical, because + systems with 32-bit processors can build, but not run, 64-bit + binaries. + + + + If a 32-bit binary is desired, set LDR_CNTRL to + MAXDATA=0xn0000000, + where 1 <= n <= 8, before starting the PostgreSQL server, + and try different values and postgresql.conf + settings to find a configuration that works satisfactorily. This + use of LDR_CNTRL tells AIX that you want the + server to have MAXDATA bytes set aside for the + heap, allocated in 256 MB segments. When you find a workable + configuration, + ldedit can be used to modify the binaries so + that they default to using the desired heap size. PostgreSQL can + also be rebuilt, passing configure + LDFLAGS="-Wl,-bmaxdata:0xn0000000" + to achieve the same effect. + + + + For a 64-bit build, set OBJECT_MODE to 64 and + pass CC="gcc -maix64" + and LDFLAGS="-Wl,-bbigtoc" + to configure. + If you omit the export of + OBJECT_MODE, your build may fail with linker errors. When + OBJECT_MODE is set, it tells AIX's build utilities + such as ar, as, and ld what + type of objects to default to handling. + + + + By default, overcommit of paging space can happen. While we have + not seen this occur, AIX will kill processes when it runs out of + memory and the overcommit is accessed. The closest to this that + we have seen is fork failing because the system decided that + there was not enough memory for another process. Like many other + parts of AIX, the paging space allocation method and + out-of-memory kill is configurable on a system- or process-wide + basis if this becomes a problem. + + + + Cygwin diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index 6047b8171d..64753d9c01 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -891,6 +891,29 @@ psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such + + AIX + AIXIPC configuration + + + + It should not be necessary to do + any special configuration for such parameters as + SHMMAX, as it appears this is configured to + allow all memory to be used as shared memory. That is the + sort of configuration commonly used for other databases such + as DB/2. + + It might, however, be necessary to modify the global + ulimit information in + /etc/security/limits, as the default hard + limits for file sizes (fsize) and numbers of + files (nofiles) might be too low. + + + + + FreeBSD FreeBSDIPC configuration diff --git a/meson.build b/meson.build index 1c0579d5a6..f1ac154cdc 100644 --- a/meson.build +++ b/meson.build @@ -196,7 +196,26 @@ endif # that purpose. portname = host_system -if host_system == 'cygwin' +if host_system == 'aix' + library_path_var = 'LIBPATH' + + export_file_format = 'aix' + export_fmt = '-Wl,-bE:@0@' + mod_link_args_fmt = ['-Wl,-bI:@0@'] + mod_link_with_dir = 'libdir' + mod_link_with_name = '@0@.imp' + + # M:SRE sets a flag indicating that an object is a shared library. Seems to + # work in some circumstances without, but required in others. + ldflags_sl += '-Wl,-bM:SRE' + ldflags_be += '-Wl,-brtllib' + + # Native memset() is faster, tested on: + # - AIX 5.1 and 5.2, XLC 6.0 (IBM's cc) + # - AIX 5.3 ML3, gcc 4.0.1 + memset_loop_limit = 0 + +elif host_system == 'cygwin' sema_kind = 'unnamed_posix' cppflags += '-D_GNU_SOURCE' dlsuffix = '.dll' @@ -1490,11 +1509,11 @@ sizeof_long = cc.sizeof('long', args: test_c_args) cdata.set('SIZEOF_LONG', sizeof_long) if sizeof_long == 8 cdata.set('HAVE_LONG_INT_64', 1) - pg_int64_type = 'long int' + cdata.set('PG_INT64_TYPE', 'long int') cdata.set_quoted('INT64_MODIFIER', 'l') elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8 cdata.set('HAVE_LONG_LONG_INT_64', 1) - pg_int64_type = 'long long int' + cdata.set('PG_INT64_TYPE', 'long long int') cdata.set_quoted('INT64_MODIFIER', 'll') else error('do not know how to get a 64bit int') @@ -1508,31 +1527,15 @@ endif # Determine memory alignment requirements for the basic C data types. alignof_types = ['short', 'int', 'long', 'double'] +maxalign = 0 foreach t : alignof_types align = cc.alignment(t, args: test_c_args) + if maxalign < align + maxalign = align + endif cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align) endforeach - -# Compute maximum alignment of any basic type. -# -# We require 'double' to have the strictest alignment among the basic types, -# because otherwise the C ABI might impose 8-byte alignment on some of the -# other C types that correspond to TYPALIGN_DOUBLE SQL types. That could -# cause a mismatch between the tuple layout and the C struct layout of a -# catalog tuple. We used to carefully order catalog columns such that any -# fixed-width, attalign=4 columns were at offsets divisible by 8 regardless -# of MAXIMUM_ALIGNOF to avoid that, but we no longer support any platforms -# where TYPALIGN_DOUBLE != MAXIMUM_ALIGNOF. -# -# We assume without checking that int64's alignment is at least as strong -# as long, char, short, or int. Note that we intentionally do not consider -# any types wider than 64 bits, as allowing MAXIMUM_ALIGNOF to exceed 8 -# would be too much of a penalty for disk and memory space. -alignof_double = cdata.get('ALIGNOF_DOUBLE') -if cc.alignment(pg_int64_type, args: test_c_args) > alignof_double - error('alignment of int64 is greater than the alignment of double') -endif -cdata.set('MAXIMUM_ALIGNOF', alignof_double) +cdata.set('MAXIMUM_ALIGNOF', maxalign) cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args)) cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args)) @@ -1581,7 +1584,7 @@ if cc.links(''' if not meson.is_cross_build() r = cc.run(''' /* This must match the corresponding code in c.h: */ - #if defined(__GNUC__) || defined(__SUNPRO_C) + #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__) #define pg_attribute_aligned(a) __attribute__((aligned(a))) #elif defined(_MSC_VER) #define pg_attribute_aligned(a) __declspec(align(a)) @@ -2476,6 +2479,10 @@ endif # conflict. # # We assume C99 support, so we don't need to make this conditional. +# +# XXX: Historically we allowed platforms to disable restrict in template +# files, but that was only added for AIX when building with XLC, which we +# don't support yet. cdata.set('pg_restrict', '__restrict') diff --git a/src/Makefile.shlib b/src/Makefile.shlib index fa81f6ffdd..8ca51ca03f 100644 --- a/src/Makefile.shlib +++ b/src/Makefile.shlib @@ -106,6 +106,20 @@ ifdef SO_MAJOR_VERSION override CPPFLAGS += -DSO_MAJOR_VERSION=$(SO_MAJOR_VERSION) endif +ifeq ($(PORTNAME), aix) + LINK.shared = $(COMPILER) + ifdef SO_MAJOR_VERSION + shlib = lib$(NAME)$(DLSUFFIX).$(SO_MAJOR_VERSION) + endif + haslibarule = yes + # $(exports_file) is also usable as an import file + exports_file = lib$(NAME).exp + BUILD.exports = ( echo '\#! $(shlib)'; $(AWK) '/^[^\#]/ {printf "%s\n",$$1}' $< ) > $@ + ifneq (,$(SHLIB_EXPORTS)) + LINK.shared += -Wl,-bE:$(exports_file) + endif +endif + ifeq ($(PORTNAME), darwin) ifdef soname # linkable library @@ -254,6 +268,14 @@ $(stlib): $(OBJS) | $(SHLIB_PREREQS) touch $@ endif #haslibarule +# AIX wraps shared libraries inside a static library, can be used both +# for static and shared linking +ifeq ($(PORTNAME), aix) +$(stlib): $(shlib) + rm -f $(stlib) + $(AR) $(AROPT) $(stlib) $(shlib) +endif # aix + ifeq (,$(filter cygwin win32,$(PORTNAME))) # Normal case @@ -267,8 +289,11 @@ ifneq ($(shlib), $(shlib_major)) endif # Make sure we have a link to a name without any version numbers ifneq ($(shlib), $(shlib_bare)) +# except on AIX, where that's not a thing +ifneq ($(PORTNAME), aix) rm -f $(shlib_bare) $(LN_S) $(shlib) $(shlib_bare) +endif # aix endif # shlib_bare endif # shlib_major @@ -376,6 +401,9 @@ install-lib-static: $(stlib) installdirs-lib install-lib-shared: $(shlib) installdirs-lib ifdef soname +# we don't install $(shlib) on AIX +# (see http://archives.postgresql.org/message-id/52EF20B2E3209443BC37736D00C3C1380A6E79FE@EXADV1.host.magwien.gv.at) +ifneq ($(PORTNAME), aix) $(INSTALL_SHLIB) $< '$(DESTDIR)$(libdir)/$(shlib)' ifneq ($(PORTNAME), cygwin) ifneq ($(PORTNAME), win32) @@ -391,6 +419,7 @@ ifneq ($(shlib), $(shlib_bare)) endif endif # not win32 endif # not cygwin +endif # not aix ifneq (,$(findstring $(PORTNAME),win32 cygwin)) $(INSTALL_SHLIB) $< '$(DESTDIR)$(bindir)/$(shlib)' endif diff --git a/src/backend/Makefile b/src/backend/Makefile index 6700aec039..954b14962f 100644 --- a/src/backend/Makefile +++ b/src/backend/Makefile @@ -62,12 +62,14 @@ all: submake-libpgport submake-catalog-headers submake-utils-headers postgres $( ifneq ($(PORTNAME), cygwin) ifneq ($(PORTNAME), win32) +ifneq ($(PORTNAME), aix) postgres: $(OBJS) $(CC) $(CFLAGS) $(call expand_subsys,$^) $(LDFLAGS) $(LIBS) -o $@ endif endif +endif ifeq ($(PORTNAME), cygwin) @@ -94,6 +96,24 @@ libpostgres.a: postgres endif # win32 +ifeq ($(PORTNAME), aix) + +postgres: $(POSTGRES_IMP) + $(CC) $(CFLAGS) $(call expand_subsys,$(OBJS)) $(LDFLAGS) -Wl,-bE:$(top_builddir)/src/backend/$(POSTGRES_IMP) $(LIBS) -Wl,-brtllib -o $@ + +# Linking to a single .o with -r is a lot faster than building a .a or passing +# all objects to MKLDEXPORT. +# +# It looks alluring to use $(CC) -r instead of ld -r, but that doesn't +# trivially work with gcc, due to gcc specific static libraries linked in with +# -r. +$(POSTGRES_IMP): $(OBJS) + ld -r -o SUBSYS.o $(call expand_subsys,$^) + $(MKLDEXPORT) SUBSYS.o . > $@ + @rm -f SUBSYS.o + +endif # aix + $(top_builddir)/src/port/libpgport_srv.a: | submake-libpgport diff --git a/src/backend/meson.build b/src/backend/meson.build index 436c04af08..8767aaba67 100644 --- a/src/backend/meson.build +++ b/src/backend/meson.build @@ -91,6 +91,21 @@ if cc.get_id() == 'msvc' # be restricted to b_pch=true. backend_link_with += postgres_lib +elif host_system == 'aix' + # The '.' argument leads mkldexport.sh to emit "#! .", which refers to the + # main executable, allowing extension libraries to resolve their undefined + # symbols to symbols in the postgres binary. + postgres_imp = custom_target('postgres.imp', + command: [files('port/aix/mkldexport.sh'), '@INPUT@', '.'], + input: postgres_lib, + output: 'postgres.imp', + capture: true, + install: true, + install_dir: dir_lib, + build_by_default: false, + ) + backend_link_args += '-Wl,-bE:@0@'.format(postgres_imp.full_path()) + backend_link_depends += postgres_imp endif backend_input = [] diff --git a/src/backend/port/aix/mkldexport.sh b/src/backend/port/aix/mkldexport.sh new file mode 100755 index 0000000000..adf3793e86 --- /dev/null +++ b/src/backend/port/aix/mkldexport.sh @@ -0,0 +1,61 @@ +#!/bin/sh +# +# mkldexport +# create an AIX exports file from an object file +# +# src/backend/port/aix/mkldexport.sh +# +# Usage: +# mkldexport objectfile [location] +# where +# objectfile is the current location of the object file. +# location is the eventual (installed) location of the +# object file (if different from the current +# working directory). +# +# [This file comes from the Postgres 4.2 distribution. - ay 7/95] +# +# Header: /usr/local/devel/postgres/src/tools/mkldexport/RCS/mkldexport.sh,v 1.2 1994/03/13 04:59:12 aoki Exp +# + +# setting this to nm -B might be better +# ... due to changes in AIX 4.x ... +# ... let us search in different directories - Gerhard Reithofer +if [ -x /usr/ucb/nm ] +then NM=/usr/ucb/nm +elif [ -x /usr/bin/nm ] +then NM=/usr/bin/nm +elif [ -x /usr/ccs/bin/nm ] +then NM=/usr/ccs/bin/nm +elif [ -x /usr/usg/bin/nm ] +then NM=/usr/usg/bin/nm +else echo "Fatal error: cannot find `nm' ... please check your installation." + exit 1 +fi + +CMDNAME=`basename $0` +if [ -z "$1" ]; then + echo "Usage: $CMDNAME object [location]" + exit 1 +fi +OBJNAME=`basename $1` +if [ "`basename $OBJNAME`" != "`basename $OBJNAME .o`" ]; then + OBJNAME=`basename $OBJNAME .o`.so +fi +if [ -z "$2" ]; then + echo '#!' +else + if [ "$2" = "." ]; then + # for the base executable (AIX 4.2 and up) + echo '#! .' + else + echo '#!' $2 + fi +fi +$NM -BCg $1 | \ + egrep ' [TDB] ' | \ + sed -e 's/.* //' | \ + egrep -v '\$' | \ + sed -e 's/^[.]//' | \ + sort | \ + uniq diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index d91a85cb2d..7b51e94f4a 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -908,7 +908,9 @@ errcode_for_file_access(void) /* Wrong object type or state */ case ENOTDIR: /* Not a directory */ case EISDIR: /* Is a directory */ +#if defined(ENOTEMPTY) && (ENOTEMPTY != EEXIST) /* same code on AIX */ case ENOTEMPTY: /* Directory not empty */ +#endif edata->sqlerrcode = ERRCODE_WRONG_OBJECT_TYPE; break; diff --git a/src/backend/utils/misc/ps_status.c b/src/backend/utils/misc/ps_status.c index 9da6377402..532eac31b4 100644 --- a/src/backend/utils/misc/ps_status.c +++ b/src/backend/utils/misc/ps_status.c @@ -50,7 +50,7 @@ bool update_process_title = DEFAULT_UPDATE_PROCESS_TITLE; #define PS_USE_SETPROCTITLE_FAST #elif defined(HAVE_SETPROCTITLE) #define PS_USE_SETPROCTITLE -#elif defined(__linux__) || defined(__sun) || defined(__darwin__) +#elif defined(__linux__) || defined(_AIX) || defined(__sun) || defined(__darwin__) #define PS_USE_CLOBBER_ARGV #elif defined(WIN32) #define PS_USE_WIN32 @@ -60,7 +60,7 @@ bool update_process_title = DEFAULT_UPDATE_PROCESS_TITLE; /* Different systems want the buffer padded differently */ -#if defined(__linux__) || defined(__darwin__) +#if defined(_AIX) || defined(__linux__) || defined(__darwin__) #define PS_PADDING '\0' #else #define PS_PADDING ' ' diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl index 2d4b75a6fe..ce936959c1 100644 --- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl +++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl @@ -401,7 +401,8 @@ SKIP: { my $tar = $ENV{TAR}; # don't check for a working tar here, to accommodate various odd - # cases. If tar doesn't work the init_from_backup below will fail. + # cases such as AIX. If tar doesn't work the init_from_backup below + # will fail. skip "no tar program available", 1 if (!defined $tar || $tar eq ''); diff --git a/src/bin/pg_verifybackup/t/008_untar.pl b/src/bin/pg_verifybackup/t/008_untar.pl index 7a09f3b75b..30d9f3f7f0 100644 --- a/src/bin/pg_verifybackup/t/008_untar.pl +++ b/src/bin/pg_verifybackup/t/008_untar.pl @@ -104,7 +104,8 @@ for my $tc (@test_configuration) { my $tar = $ENV{TAR}; # don't check for a working tar here, to accommodate various odd - # cases. If tar doesn't work the init_from_backup below will fail. + # cases such as AIX. If tar doesn't work the init_from_backup below + # will fail. skip "no tar program available", 1 if (!defined $tar || $tar eq ''); diff --git a/src/bin/pg_verifybackup/t/010_client_untar.pl b/src/bin/pg_verifybackup/t/010_client_untar.pl index 8c076d46de..45010d79ac 100644 --- a/src/bin/pg_verifybackup/t/010_client_untar.pl +++ b/src/bin/pg_verifybackup/t/010_client_untar.pl @@ -134,7 +134,8 @@ for my $tc (@test_configuration) { my $tar = $ENV{TAR}; # don't check for a working tar here, to accommodate various odd - # cases. If tar doesn't work the init_from_backup below will fail. + # cases such as AIX. If tar doesn't work the init_from_backup below + # will fail. skip "no tar program available", 1 if (!defined $tar || $tar eq ''); diff --git a/src/include/c.h b/src/include/c.h index dc1841346c..641cd9bdf1 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -182,7 +182,7 @@ #define PG_USED_FOR_ASSERTS_ONLY pg_attribute_unused() #endif -/* GCC supports format attributes */ +/* GCC support format attributes */ #if defined(__GNUC__) #define pg_attribute_format_arg(a) __attribute__((format_arg(a))) #define pg_attribute_printf(f,a) __attribute__((format(PG_PRINTF_ATTRIBUTE, f, a))) @@ -192,7 +192,7 @@ #endif /* GCC and Sunpro support aligned, packed and noreturn */ -#if defined(__GNUC__) || defined(__SUNPRO_C) +#if defined(__GNUC__) || defined(__SUNPRO_C) #define pg_attribute_aligned(a) __attribute__((aligned(a))) #define pg_attribute_noreturn() __attribute__((noreturn)) #define pg_attribute_packed() __attribute__((packed)) diff --git a/src/include/port/aix.h b/src/include/port/aix.h new file mode 100644 index 0000000000..c54c95d4a5 --- /dev/null +++ b/src/include/port/aix.h @@ -0,0 +1,14 @@ +/* + * src/include/port/aix.h + */ +#define CLASS_CONFLICT +#define DISABLE_XOPEN_NLS + +/* Commenting for XLC + * "IBM XL C/C++ for AIX, V12.1" miscompiles, for 32-bit, some inline + * expansions of ginCompareItemPointers() "long long" arithmetic. To take + * advantage of inlining, build a 64-bit PostgreSQL. +#if defined(__ILP32__) && defined(__IBMC__) +#define PG_FORCE_DISABLE_INLINE +#endif + */ diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h index 29ac6cdcd9..69582f4ae7 100644 --- a/src/include/storage/s_lock.h +++ b/src/include/storage/s_lock.h @@ -414,6 +414,12 @@ typedef unsigned int slock_t; * an isync is a sufficient synchronization barrier after a lwarx/stwcx loop. * But if the spinlock is in ordinary memory, we can use lwsync instead for * better performance. + * + * Ordinarily, we'd code the branches here using GNU-style local symbols, that + * is "1f" referencing "1:" and so on. But some people run gcc on AIX with + * IBM's assembler as backend, and IBM's assembler doesn't do local symbols. + * So hand-code the branch offsets; fortunately, all PPC instructions are + * exactly 4 bytes each, so it's not too hard to count. */ static __inline__ int tas(volatile slock_t *lock) @@ -424,17 +430,15 @@ tas(volatile slock_t *lock) __asm__ __volatile__( " lwarx %0,0,%3,1 \n" " cmpwi %0,0 \n" -" bne 1f \n" +" bne $+16 \n" /* branch to li %1,1 */ " addi %0,%0,1 \n" " stwcx. %0,0,%3 \n" -" beq 2f \n" -"1: \n" +" beq $+12 \n" /* branch to lwsync */ " li %1,1 \n" -" b 3f \n" -"2: \n" +" b $+12 \n" /* branch to end of asm sequence */ " lwsync \n" " li %1,0 \n" -"3: \n" + : "=&b"(_t), "=r"(_res), "+m"(*lock) : "r"(lock) : "memory", "cc"); @@ -662,6 +666,21 @@ tas(volatile slock_t *lock) #if !defined(HAS_TEST_AND_SET) /* We didn't trigger above, let's try here */ +#if defined(_AIX) /* AIX */ +/* + * AIX (POWER) + */ +#define HAS_TEST_AND_SET + +#include + +typedef int slock_t; + +#define TAS(lock) _check_lock((slock_t *) (lock), 0, 1) +#define S_UNLOCK(lock) _clear_lock((slock_t *) (lock), 0) +#endif /* _AIX */ + + /* These are in sunstudio_(sparc|x86).s */ #if defined(__SUNPRO_C) && (defined(__i386) || defined(__x86_64__) || defined(__sparc__) || defined(__sparc)) diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index b36a765764..154429d4d1 100644 --- a/src/interfaces/libpq/Makefile +++ b/src/interfaces/libpq/Makefile @@ -114,7 +114,7 @@ backend_src = $(top_srcdir)/src/backend # coding rule. libpq-refs-stamp: $(shlib) ifneq ($(enable_coverage), yes) -ifeq (,$(filter solaris,$(PORTNAME))) +ifeq (,$(filter aix solaris,$(PORTNAME))) @if nm -A -u $< 2>/dev/null | grep -v -e __cxa_atexit -e __tsan_func_exit | grep exit; then \ echo 'libpq must not be calling any function which invokes exit'; exit 1; \ fi diff --git a/src/interfaces/libpq/meson.build b/src/interfaces/libpq/meson.build index ed2a4048d1..7e2017daf0 100644 --- a/src/interfaces/libpq/meson.build +++ b/src/interfaces/libpq/meson.build @@ -54,8 +54,9 @@ libpq_c_args = ['-DSO_MAJOR_VERSION=5'] # libpq_st, and {pgport,common}_shlib for libpq_sh # # We could try to avoid building the source files twice, but it probably adds -# more complexity than its worth (reusing object files requires also linking -# to the library on windows or breaks precompiled headers). +# more complexity than its worth (AIX doesn't support link_whole yet, reusing +# object files requires also linking to the library on windows or breaks +# precompiled headers). libpq_st = static_library('libpq', libpq_sources, include_directories: [libpq_inc], diff --git a/src/makefiles/Makefile.aix b/src/makefiles/Makefile.aix new file mode 100644 index 0000000000..dd16a7a037 --- /dev/null +++ b/src/makefiles/Makefile.aix @@ -0,0 +1,39 @@ +# MAKE_EXPORTS is required for svr4 loaders that want a file of +# symbol names to tell them what to export/import. +MAKE_EXPORTS= true + +# -blibpath must contain ALL directories where we should look for libraries +libpath := $(shell echo $(subst -L,:,$(filter -L/%,$(LDFLAGS))) | sed -e's/ //g'):/usr/lib:/lib + +# when building with gcc, need to make sure that libgcc can be found +ifeq ($(GCC), yes) +libpath := $(libpath):$(dir $(shell gcc -print-libgcc-file-name)) +endif + +rpath = -Wl,-blibpath:'$(rpathdir)$(libpath)' + +LDFLAGS_SL += -Wl,-bnoentry -Wl,-H512 -Wl,-bM:SRE + +# gcc needs to know it's building a shared lib, otherwise it'll not emit +# correct code / link to the right support libraries +ifeq ($(GCC), yes) +LDFLAGS_SL += -shared +endif + +# env var name to use in place of LD_LIBRARY_PATH +ld_library_path_var = LIBPATH + + +POSTGRES_IMP= postgres.imp + +ifdef PGXS +BE_DLLLIBS= -Wl,-bI:$(pkglibdir)/$(POSTGRES_IMP) +else +BE_DLLLIBS= -Wl,-bI:$(top_builddir)/src/backend/$(POSTGRES_IMP) +endif + +MKLDEXPORT_DIR=src/backend/port/aix +MKLDEXPORT=$(top_srcdir)/$(MKLDEXPORT_DIR)/mkldexport.sh + +%$(DLSUFFIX): %.o + $(CC) $(CFLAGS) $*.o $(LDFLAGS) $(LDFLAGS_SL) -o $@ $(BE_DLLLIBS) diff --git a/src/port/README b/src/port/README index ed5c54a72f..97f18a6233 100644 --- a/src/port/README +++ b/src/port/README @@ -28,5 +28,5 @@ applications. from libpgport are linked first. This avoids having applications dependent on symbols that are _used_ by libpq, but not intended to be exported by libpq. libpq's libpgport usage changes over time, so such a -dependency is a problem. Windows, Linux, and macOS use an export +dependency is a problem. Windows, Linux, AIX, and macOS use an export list to control the symbols exported by libpq. diff --git a/src/port/strerror.c b/src/port/strerror.c index 4918ba821c..1070a49802 100644 --- a/src/port/strerror.c +++ b/src/port/strerror.c @@ -214,8 +214,10 @@ get_errno_symbol(int errnum) return "ENOTCONN"; case ENOTDIR: return "ENOTDIR"; +#if defined(ENOTEMPTY) && (ENOTEMPTY != EEXIST) /* same code on AIX */ case ENOTEMPTY: return "ENOTEMPTY"; +#endif case ENOTSOCK: return "ENOTSOCK"; #ifdef ENOTSUP diff --git a/src/template/aix b/src/template/aix new file mode 100644 index 0000000000..903f8a8f8a --- /dev/null +++ b/src/template/aix @@ -0,0 +1,26 @@ +# src/template/aix + +# Commenting for XLC +# Set default options if using xlc. This formerly included -qsrcmsg, but that +# option elicits internal compiler errors from xlc v16.1.0. Note: configure +# will add -qnoansialias if the compiler accepts it, even if user specifies a +# non-default CFLAGS setting. +#if test "$GCC" != yes ; then +# case $host_os in +# *) +# CFLAGS="-O2 -qmaxmem=16384" +# ;; +# esac + + # Due to a compiler bug, see 20171013023536.GA492146@rfd.leadboat.com for details, + # force restrict not to be used when compiling with xlc. +# FORCE_DISABLE_RESTRICT=yes +#fi + +# Extra CFLAGS for code that will go into a shared library +CFLAGS_SL="" + +# Native memset() is faster, tested on: +# AIX 5.1 and 5.2, XLC 6.0 (IBM's cc) +# AIX 5.3 ML3, gcc 4.0.1 +MEMSET_LOOP_LIMIT=0 diff --git a/src/test/regress/Makefile b/src/test/regress/Makefile index 6409a485e8..7c665ff892 100644 --- a/src/test/regress/Makefile +++ b/src/test/regress/Makefile @@ -7,6 +7,11 @@ # GNU make uses a make file named "GNUmakefile" in preference to "Makefile" # if it exists. Postgres is shipped with a "GNUmakefile". + +# AIX make defaults to building *every* target of the first rule. Start with +# a single-target, empty rule to make the other targets non-default. +all: + all install clean check installcheck: @echo "You must use GNU make to use Postgres. It may be installed" @echo "on your system with the name 'gmake'." diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out index 8370c1561c..c5c675b750 100644 --- a/src/test/regress/expected/sanity_check.out +++ b/src/test/regress/expected/sanity_check.out @@ -25,3 +25,32 @@ SELECT relname, relkind ---------+--------- (0 rows) +-- +-- When ALIGNOF_DOUBLE==4 (e.g. AIX), the C ABI may impose 8-byte alignment on +-- some of the C types that correspond to TYPALIGN_DOUBLE SQL types. To ensure +-- catalog C struct layout matches catalog tuple layout, arrange for the tuple +-- offset of each fixed-width, attalign='d' catalog column to be divisible by 8 +-- unconditionally. Keep such columns before the first NameData column of the +-- catalog, since packagers can override NAMEDATALEN to an odd number. +-- +WITH check_columns AS ( + SELECT relname, attname, + array( + SELECT t.oid + FROM pg_type t JOIN pg_attribute pa ON t.oid = pa.atttypid + WHERE pa.attrelid = a.attrelid AND + pa.attnum > 0 AND pa.attnum < a.attnum + ORDER BY pa.attnum) AS coltypes + FROM pg_attribute a JOIN pg_class c ON c.oid = attrelid + JOIN pg_namespace n ON c.relnamespace = n.oid + WHERE attalign = 'd' AND relkind = 'r' AND + attnotnull AND attlen <> -1 AND n.nspname = 'pg_catalog' +) +SELECT relname, attname, coltypes, get_columns_length(coltypes) + FROM check_columns + WHERE get_columns_length(coltypes) % 8 != 0 OR + 'name'::regtype::oid = ANY(coltypes); + relname | attname | coltypes | get_columns_length +---------+---------+----------+-------------------- +(0 rows) + diff --git a/src/test/regress/expected/test_setup.out b/src/test/regress/expected/test_setup.out index 3d0eeec996..5d9e6bf12b 100644 --- a/src/test/regress/expected/test_setup.out +++ b/src/test/regress/expected/test_setup.out @@ -209,6 +209,10 @@ CREATE FUNCTION ttdummy () RETURNS trigger AS :'regresslib' LANGUAGE C; +CREATE FUNCTION get_columns_length(oid[]) + RETURNS int + AS :'regresslib' + LANGUAGE C STRICT STABLE PARALLEL SAFE; -- Use hand-rolled hash functions and operator classes to get predictable -- result on different machines. The hash function for int4 simply returns -- the sum of the values passed to it and the one for text returns the length diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c index deffaea578..cc633864d7 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -1221,3 +1221,43 @@ binary_coercible(PG_FUNCTION_ARGS) PG_RETURN_BOOL(IsBinaryCoercible(srctype, targettype)); } + +/* + * Return the length of the portion of a tuple consisting of the given array + * of data types. The input data types must be fixed-length data types. + */ +PG_FUNCTION_INFO_V1(get_columns_length); +Datum +get_columns_length(PG_FUNCTION_ARGS) +{ + ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0); + Oid *type_oids; + int ntypes; + int column_offset = 0; + + if (ARR_HASNULL(ta) && array_contains_nulls(ta)) + elog(ERROR, "argument must not contain nulls"); + + if (ARR_NDIM(ta) > 1) + elog(ERROR, "argument must be empty or one-dimensional array"); + + type_oids = (Oid *) ARR_DATA_PTR(ta); + ntypes = ArrayGetNItems(ARR_NDIM(ta), ARR_DIMS(ta)); + for (int i = 0; i < ntypes; i++) + { + Oid typeoid = type_oids[i]; + int16 typlen; + bool typbyval; + char typalign; + + get_typlenbyvalalign(typeoid, &typlen, &typbyval, &typalign); + + /* the data type must be fixed-length */ + if (typlen < 0) + elog(ERROR, "type %u is not fixed-length data type", typeoid); + + column_offset = att_align_nominal(column_offset + typlen, typalign); + } + + PG_RETURN_INT32(column_offset); +} diff --git a/src/test/regress/sql/sanity_check.sql b/src/test/regress/sql/sanity_check.sql index 162e5324b5..7f338d191c 100644 --- a/src/test/regress/sql/sanity_check.sql +++ b/src/test/regress/sql/sanity_check.sql @@ -19,3 +19,29 @@ SELECT relname, relkind FROM pg_class WHERE relkind IN ('v', 'c', 'f', 'p', 'I') AND relfilenode <> 0; + +-- +-- When ALIGNOF_DOUBLE==4 (e.g. AIX), the C ABI may impose 8-byte alignment on +-- some of the C types that correspond to TYPALIGN_DOUBLE SQL types. To ensure +-- catalog C struct layout matches catalog tuple layout, arrange for the tuple +-- offset of each fixed-width, attalign='d' catalog column to be divisible by 8 +-- unconditionally. Keep such columns before the first NameData column of the +-- catalog, since packagers can override NAMEDATALEN to an odd number. +-- +WITH check_columns AS ( + SELECT relname, attname, + array( + SELECT t.oid + FROM pg_type t JOIN pg_attribute pa ON t.oid = pa.atttypid + WHERE pa.attrelid = a.attrelid AND + pa.attnum > 0 AND pa.attnum < a.attnum + ORDER BY pa.attnum) AS coltypes + FROM pg_attribute a JOIN pg_class c ON c.oid = attrelid + JOIN pg_namespace n ON c.relnamespace = n.oid + WHERE attalign = 'd' AND relkind = 'r' AND + attnotnull AND attlen <> -1 AND n.nspname = 'pg_catalog' +) +SELECT relname, attname, coltypes, get_columns_length(coltypes) + FROM check_columns + WHERE get_columns_length(coltypes) % 8 != 0 OR + 'name'::regtype::oid = ANY(coltypes); diff --git a/src/test/regress/sql/test_setup.sql b/src/test/regress/sql/test_setup.sql index 06b0e2121f..1b2d434683 100644 --- a/src/test/regress/sql/test_setup.sql +++ b/src/test/regress/sql/test_setup.sql @@ -257,6 +257,11 @@ CREATE FUNCTION ttdummy () AS :'regresslib' LANGUAGE C; +CREATE FUNCTION get_columns_length(oid[]) + RETURNS int + AS :'regresslib' + LANGUAGE C STRICT STABLE PARALLEL SAFE; + -- Use hand-rolled hash functions and operator classes to get predictable -- result on different machines. The hash function for int4 simply returns -- the sum of the values passed to it and the one for text returns the length diff --git a/src/tools/gen_export.pl b/src/tools/gen_export.pl index d9fdaaaf6d..888c8a197a 100644 --- a/src/tools/gen_export.pl +++ b/src/tools/gen_export.pl @@ -16,11 +16,12 @@ GetOptions( 'input:s' => \$input, 'output:s' => \$output) or die "wrong arguments"; -if (not( $format eq 'darwin' +if (not( $format eq 'aix' + or $format eq 'darwin' or $format eq 'gnu' or $format eq 'win')) { - die "$0: $format is not yet handled (only darwin, gnu, win are)\n"; + die "$0: $format is not yet handled (only aix, darwin, gnu, win are)\n"; } open(my $input_handle, '<', $input) @@ -55,7 +56,11 @@ while (<$input_handle>) } elsif (/^(\S+)\s+(\S+)/) { - if ($format eq 'darwin') + if ($format eq 'aix') + { + print $output_handle "$1\n"; + } + elsif ($format eq 'darwin') { print $output_handle "_$1\n"; } diff --git a/src/tools/pginclude/headerscheck b/src/tools/pginclude/headerscheck index 4a157d0a5f..cfd8c6896c 100755 --- a/src/tools/pginclude/headerscheck +++ b/src/tools/pginclude/headerscheck @@ -85,6 +85,7 @@ do # These files are platform-specific, and c.h will include the # one that's relevant for our current platform anyway. + test "$f" = src/include/port/aix.h && continue test "$f" = src/include/port/cygwin.h && continue test "$f" = src/include/port/darwin.h && continue test "$f" = src/include/port/freebsd.h && continue -- 2.41.0