From 98af27c6331c4fe161f7cab5c16768587f7fcb9a Mon Sep 17 00:00:00 2001
From: AIX-dev <postgres-ibm-aix@wwpdl.vnet.ibm.com>
Date: Tue, 9 Dec 2025 09:49:31 -0600
Subject: [PATCH] Support for AIX.

---
 Makefile                                   |  2 -
 configure                                  | 37 ++++++++++---
 configure.ac                               | 29 +++++++++-
 meson.build                                | 27 ++++++++--
 src/Makefile.shlib                         | 29 ++++++++++
 src/backend/Makefile                       | 20 +++++++
 src/backend/meson.build                    | 18 +++++++
 src/backend/port/aix/mkldexport.sh         | 61 ++++++++++++++++++++++
 src/backend/utils/error/elog.c             |  2 +
 src/include/port/aix.h                     | 26 +++++++++
 src/include/storage/s_lock.h               | 52 +++---------------
 src/interfaces/ecpg/compatlib/meson.build  |  2 +-
 src/interfaces/ecpg/ecpglib/meson.build    |  2 +-
 src/interfaces/ecpg/pgtypeslib/meson.build |  2 +-
 src/interfaces/libpq/meson.build           |  2 +-
 src/makefiles/Makefile.aix                 | 34 ++++++++++++
 src/port/strerror.c                        |  2 +
 src/template/aix                           |  6 +++
 src/tools/gen_export.pl                    | 11 +++-
 19 files changed, 300 insertions(+), 64 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 8a2ec9396b6..9bc1a4ec17b 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 3a0ed11fa8e..c4749a8e5b6 100755
--- a/configure
+++ b/configure
@@ -3020,6 +3020,7 @@ else
 # --with-template not given
 
 case $host_os in
+  aix*) template=aix ;;
   cygwin*|msys*) template=cygwin ;;
   darwin*) template=darwin ;;
 dragonfly*) template=netbsd ;;
@@ -17006,13 +17007,37 @@ _ACEOF
 # 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
+echo "Checking for MAX ALIGN - $PORTNAME"
+if test "$PORTNAME" != "aix"; then
+    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 $ac_cv_alignof_int64_t -gt $MAX_ALIGNOF ; then
-  as_fn_error $? "alignment of 'int64_t' is greater than the alignment of 'double'" "$LINENO" 5
+    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
+    fi
+else
+# The AIX 'power' alignment rules apply the natural alignment of the "first
+# member" if it is of a floating-point data type (or is an aggregate whose
+# recursively "first" member or element is such a type). The alignment
+# associated with these types for subsequent members use an alignment value
+# where the floating-point data type is considered to have 4-byte alignment.
+# More info
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99557
+#
+# The double is aligned to 4-bytes on AIX in aggregates. But to maintain
+# alignement across platforms the max alignment of long should be considered.
+      echo "MAX ALIGN ac_cv_alignof_long"
+    MAX_ALIGNOF=$ac_cv_alignof_long
+    if test $MAX_ALIGNOF -lt $ac_cv_alignof_double ; then
+      MAX_ALIGNOF=$ac_cv_alignof_double
+      echo "MAX ALIGN ac_cv_alignof_double"
+    fi
+    if test $MAX_ALIGNOF -lt $ac_cv_alignof_int64_t; then
+      MAX_ALIGNOF="$ac_cv_alignof_int64_t"
+      echo "MAX ALIGN ac_cv_alignof_int64_t"
+    fi
 fi
 
 cat >>confdefs.h <<_ACEOF
diff --git a/configure.ac b/configure.ac
index c2413720a18..7f1530df2b1 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 ;;
@@ -2006,7 +2007,33 @@ AC_CHECK_ALIGNOF(double)
 # 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 "$PORTNAME" != "aix"; then
+    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 $ac_cv_alignof_int64_t -gt $MAX_ALIGNOF; then
+      as_fn_error $? "alignment of 'long long int' is greater than the alignment of 'double'" "$LINENO" 5
+    fi
+else
+# The AIX 'power' alignment rules apply the natural alignment of the "first
+# member" if it is of a floating-point data type (or is an aggregate whose
+# recursively "first" member or element is such a type). The alignment
+# associated with these types for subsequent members use an alignment value
+# where the floating-point data type is considered to have 4-byte alignment.
+# More info
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99557
+# 
+# The double is aligned to 4-bytes on AIX in aggregates. But to maintain
+# alignement across platforms the max alignment of long should be considered.
+    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 $MAX_ALIGNOF -lt $ac_cv_alignof_int64_t ; then
+      MAX_ALIGNOF="$ac_cv_alignof_int64_t"
+    fi
 
 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/meson.build b/meson.build
index 6e7ddd74683..304a9184075 100644
--- a/meson.build
+++ b/meson.build
@@ -206,6 +206,25 @@ if host_system == 'cygwin'
   mod_link_with_name = 'lib@0@.a'
   mod_link_with_dir = 'libdir'
 
+elif host_system == 'aix'
+  sema_kind = 'unnamed_posix'
+  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'
+  dl_suffix = '.a'
+  cppflags += '-D_GNU_SOURCE'
+
+  # 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:
+  memset_loop_limit = 0
+
 elif host_system == 'darwin'
   dlsuffix = '.dylib'
   library_path_var = 'DYLD_LIBRARY_PATH'
@@ -1766,9 +1785,9 @@ endforeach
 # 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('int64_t', args: test_c_args, prefix: '#include <stdint.h>') > alignof_double
-  error('alignment of int64_t is greater than the alignment of double')
-endif
+#if cc.alignment('int64_t', args: test_c_args, prefix: '#include <stdint.h>') > alignof_double
+#  error('alignment of int64_t is greater than the alignment of double')
+#endif
 cdata.set('MAXIMUM_ALIGNOF', alignof_double)
 
 cdata.set('SIZEOF_LONG', cc.sizeof('long', args: test_c_args))
@@ -1820,7 +1839,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__)
+    #if defined(__GNUC__) || defined(__IBMC__)
     #define pg_attribute_aligned(a) __attribute__((aligned(a)))
     #elif defined(_MSC_VER)
     #define pg_attribute_aligned(a) __declspec(align(a))
diff --git a/src/Makefile.shlib b/src/Makefile.shlib
index 3825af5b228..35adc4174ed 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 both shared libraries and static library, which 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 7344c8c7f5c..572f5430a60 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -63,12 +63,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)
 
@@ -95,6 +97,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 b831a541652..4838f245ab3 100644
--- a/src/backend/meson.build
+++ b/src/backend/meson.build
@@ -125,6 +125,24 @@ if host_system == 'windows'
     '--FILEDESC', 'PostgreSQL Server',])
 endif
 
+if 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
+
+
 postgres = executable('postgres',
   backend_input,
   sources: post_export_backend_sources,
diff --git a/src/backend/port/aix/mkldexport.sh b/src/backend/port/aix/mkldexport.sh
new file mode 100755
index 00000000000..adf3793e868
--- /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 29643c51439..1c933b5afad 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -914,7 +914,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/include/port/aix.h b/src/include/port/aix.h
new file mode 100644
index 00000000000..dd7cfb197cd
--- /dev/null
+++ b/src/include/port/aix.h
@@ -0,0 +1,26 @@
+/*
+ * src/include/port/aix.h
+ */
+
+/* This change is required for the meson changes as the autoconf is not run and
+ * to resolve the conflicts in picking the float.h details by default from the
+ * postgres defined datatypes.
+ */
+#ifdef _AIX
+#ifndef PGDLLIMPORT
+#define PGDLLIMPORT
+#endif  /* PGDLLIMPORT */
+typedef float float4;
+typedef double float8;
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+#define pg_noreturn _Noreturn
+#elif defined(__GNUC__)
+#define pg_noreturn __attribute__((noreturn))
+#else
+#define pg_noreturn
+#endif
+
+#include <stdbool.h>
+
+#endif  /*_AIX */
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 7f8f566bd40..1a0cd5ec019 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -398,60 +398,20 @@ typedef unsigned int slock_t;
 
 #define TAS(lock) tas(lock)
 
-/* On PPC, it's a win to use a non-locking test before the lwarx */
+/* On PPC, use the compiler provided Built-in functions for atomic memory
+ * exchange operations.
+ */
 #define TAS_SPIN(lock)	(*(lock) ? 1 : TAS(lock))
 
-/*
- * The second operand of addi can hold a constant zero or a register number,
- * hence constraint "=&b" to avoid allocating r0.  "b" stands for "address
- * base register"; most operands having this register-or-zero property are
- * address bases, e.g. the second operand of lwax.
- *
- * NOTE: per the Enhanced PowerPC Architecture manual, v1.0 dated 7-May-2002,
- * 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.
- */
 static __inline__ int
 tas(volatile slock_t *lock)
 {
-	slock_t _t;
-	int _res;
-
-	__asm__ __volatile__(
-"	lwarx   %0,0,%3,1	\n"
-"	cmpwi   %0,0		\n"
-"	bne     1f			\n"
-"	addi    %0,%0,1		\n"
-"	stwcx.  %0,0,%3		\n"
-"	beq     2f			\n"
-"1: \n"
-"	li      %1,1		\n"
-"	b       3f			\n"
-"2: \n"
-"	lwsync				\n"
-"	li      %1,0		\n"
-"3: \n"
-:	"=&b"(_t), "=r"(_res), "+m"(*lock)
-:	"r"(lock)
-:	"memory", "cc");
-	return _res;
+  return __sync_lock_test_and_set(lock, 1);
 }
-
-/*
- * PowerPC S_UNLOCK is almost standard but requires a "sync" instruction.
- * But we can use lwsync instead for better performance.
- */
-#define S_UNLOCK(lock)	\
-do \
-{ \
-	__asm__ __volatile__ ("	lwsync \n" ::: "memory"); \
-	*((volatile slock_t *) (lock)) = 0; \
-} while (0)
+#define S_UNLOCK(lock) __sync_lock_release(lock)
 
 #endif /* powerpc */
-
-
+ 
 #if defined(__mips__) && !defined(__sgi)	/* non-SGI MIPS */
 #define HAS_TEST_AND_SET
 
diff --git a/src/interfaces/ecpg/compatlib/meson.build b/src/interfaces/ecpg/compatlib/meson.build
index 56e0a21651b..3f39187cdcc 100644
--- a/src/interfaces/ecpg/compatlib/meson.build
+++ b/src/interfaces/ecpg/compatlib/meson.build
@@ -16,7 +16,7 @@ if host_system == 'windows'
 endif
 
 # see src/interfaces/libpq/meson.build
-ecpg_compat_st = static_library('libecpg_compat',
+ecpg_compat_st = static_library('libecpg_compat_static',
   ecpg_compat_sources,
   include_directories: ecpg_compat_inc,
   c_args: ecpg_compat_c_args,
diff --git a/src/interfaces/ecpg/ecpglib/meson.build b/src/interfaces/ecpg/ecpglib/meson.build
index 8f478c6a73e..e9faf290a2b 100644
--- a/src/interfaces/ecpg/ecpglib/meson.build
+++ b/src/interfaces/ecpg/ecpglib/meson.build
@@ -25,7 +25,7 @@ if host_system == 'windows'
 endif
 
 # see src/interfaces/libpq/meson.build
-ecpglib_st = static_library('libecpg',
+ecpglib_st = static_library('libecpg_static',
   ecpglib_sources,
   include_directories: ecpglib_inc,
   c_args: ecpglib_c_args,
diff --git a/src/interfaces/ecpg/pgtypeslib/meson.build b/src/interfaces/ecpg/pgtypeslib/meson.build
index 02301ec9acb..94d1d0ad1ef 100644
--- a/src/interfaces/ecpg/pgtypeslib/meson.build
+++ b/src/interfaces/ecpg/pgtypeslib/meson.build
@@ -21,7 +21,7 @@ if host_system == 'windows'
 endif
 
 # see src/interfaces/libpq/meson.build
-ecpg_pgtypes_st = static_library('libpgtypes',
+ecpg_pgtypes_st = static_library('libpgtypes_static',
   ecpg_pgtypes_sources,
   include_directories: ecpg_pgtypes_inc,
   c_args: ecpg_pgtypes_c_args,
diff --git a/src/interfaces/libpq/meson.build b/src/interfaces/libpq/meson.build
index a74e885b169..eea175ad14a 100644
--- a/src/interfaces/libpq/meson.build
+++ b/src/interfaces/libpq/meson.build
@@ -57,7 +57,7 @@ libpq_so_c_args = ['-DUSE_DYNAMIC_OAUTH']
 # 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).
-libpq_st = static_library('libpq',
+libpq_st = static_library('libpq_static',
   libpq_sources,
   include_directories: [libpq_inc],
   c_args: libpq_c_args,
diff --git a/src/makefiles/Makefile.aix b/src/makefiles/Makefile.aix
new file mode 100644
index 00000000000..e91b250fd19
--- /dev/null
+++ b/src/makefiles/Makefile.aix
@@ -0,0 +1,34 @@
+# -blibpath:
+# The path to be inserted into the default path (Index 0 path) field of the
+# loader section. When this flag is presented, the -L paths will not be stored.
+# AIX uses a stricter, more explicit approach. The runtime linker expects to
+# tell it exactly where to look using -blibpath.
+# -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
+
+# AIX uses a stricter, more explicit approach. The runtime linker expects
+# to tell it exactly where to look using -blibpath.
+rpath = -Wl,-blibpath:'$(rpathdir)$(libpath)'
+
+# 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/strerror.c b/src/port/strerror.c
index f0746517770..c46b9dc91fc 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 00000000000..22f61093b1b
--- /dev/null
+++ b/src/template/aix
@@ -0,0 +1,6 @@
+# This file is referred for specific flags wrt to AIX build process like
+# cflags.
+# src/template/aix
+
+# Extra CFLAGS for code that will go into a shared library
+CFLAGS_SL=" "
diff --git a/src/tools/gen_export.pl b/src/tools/gen_export.pl
index 86a7742b369..25827c42a68 100644
--- a/src/tools/gen_export.pl
+++ b/src/tools/gen_export.pl
@@ -18,7 +18,8 @@ GetOptions(
 
 if (not(   $format eq 'darwin'
 		or $format eq 'gnu'
-		or $format eq 'win'))
+		or $format eq 'win'
+        or $format eq 'aix'))
 {
 	die "$0: $format is not yet handled (only darwin, gnu, win are)\n";
 }
@@ -46,6 +47,10 @@ elsif ($format eq 'win')
 	}
 	print $output_handle "EXPORTS\n";
 }
+elsif ($format eq 'aix')
+{
+	print $output_handle "#!\n";
+}
 
 while (<$input_handle>)
 {
@@ -63,6 +68,10 @@ while (<$input_handle>)
 		{
 			print $output_handle "    $1;\n";
 		}
+        elsif ($format eq 'aix')
+        {
+            print $output_handle "$1\n";
+        }
 		elsif ($format eq 'win')
 		{
 			print $output_handle "$1 @ $2\n";
-- 
2.41.0

