From 614cd077da0de9ca92c4e4fb300c39f73ab5ad10 Mon Sep 17 00:00:00 2001
From: Sriram RK <sriram.rk@in.ibm.com>
Date: Fri, 4 Apr 2025 13:16:21 -0500
Subject: [PATCH] AIX support.

---
 Makefile                           |  2 -
 configure                          | 34 ++++++++++++++---
 configure.ac                       | 34 ++++++++++++++---
 src/Makefile.shlib                 | 29 ++++++++++++++
 src/backend/Makefile               | 20 ++++++++++
 src/backend/port/aix/mkldexport.sh | 61 ++++++++++++++++++++++++++++++
 src/backend/utils/error/elog.c     |  2 +
 src/include/port/aix.h             |  4 ++
 src/include/storage/s_lock.h       | 10 ++---
 src/makefiles/Makefile.aix         | 39 +++++++++++++++++++
 src/port/strerror.c                |  2 +
 src/template/aix                   |  7 ++++
 12 files changed, 224 insertions(+), 20 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 11615d1122d..6088fa26679 100755
--- a/configure
+++ b/configure
@@ -3008,6 +3008,7 @@ else
 # --with-template not given
 
 case $host_os in
+  aix*) template=aix ;;
   cygwin*|msys*) template=cygwin ;;
   darwin*) template=darwin ;;
 dragonfly*) template=netbsd ;;
@@ -16953,13 +16954,34 @@ _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
+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
-  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
 fi
 
 cat >>confdefs.h <<_ACEOF
diff --git a/configure.ac b/configure.ac
index debdf165044..c21aaa52064 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 ;;
@@ -1987,13 +1988,34 @@ 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'])
-fi
-if test $ac_cv_alignof_int64_t -gt $MAX_ALIGNOF ; then
-  AC_MSG_ERROR([alignment of 'int64_t' is greater than the alignment of 'double'])
 fi
 AC_DEFINE_UNQUOTED(MAXIMUM_ALIGNOF, $MAX_ALIGNOF, [Define as the maximum alignment requirement of any C data type.])
 
diff --git a/src/Makefile.shlib b/src/Makefile.shlib
index fa81f6ffdd6..13ea84ac185 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/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 8a6b6905079..3a8e9dc30b0 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -904,7 +904,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..7d08480c8c0
--- /dev/null
+++ b/src/include/port/aix.h
@@ -0,0 +1,4 @@
+/*
+ * src/include/port/aix.h
+ */
+
diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h
index 2f73f9fcf57..5da9b3acda4 100644
--- a/src/include/storage/s_lock.h
+++ b/src/include/storage/s_lock.h
@@ -421,17 +421,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");
diff --git a/src/makefiles/Makefile.aix b/src/makefiles/Makefile.aix
new file mode 100644
index 00000000000..d33918f91b9
--- /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/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..48a3ce55cf7
--- /dev/null
+++ b/src/template/aix
@@ -0,0 +1,7 @@
+# src/template/aix
+
+# Extra CFLAGS for code that will go into a shared library
+CFLAGS_SL=""
+
+# Native memset() is faster.
+MEMSET_LOOP_LIMIT=0
-- 
2.41.0

