From d0eb44fc066d9125dbb097d76975be8278722586 Mon Sep 17 00:00:00 2001
From: Craig Ringer <craig.ringer@2ndquadrant.com>
Date: Mon, 26 Oct 2020 16:39:50 +0800
Subject: [PATCH v1 3/3] On x64 linux, run PQlibInfoPrint() when libpq.so is
 executed

Allow libpq.so to be directly executed. When run, it emits the same version and
configuration information as PQlibInfoPrint().

This approach should work on any or all ELF platforms with dynamic linker
support, but the toolchain support for producing a -shared library that
has an interpreter set in its headers is presently a bit limited.
---
 doc/src/sgml/libpq.sgml              |  7 +++++++
 src/interfaces/libpq/Makefile        |  5 +++++
 src/interfaces/libpq/libpq-version.c | 28 ++++++++++++++++++++++++++++
 3 files changed, 40 insertions(+)

diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index f0e2255d18..77e0e66ebc 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -6436,6 +6436,13 @@ void PQlibInfoPrint(void);
       returned by <xref linkend="libpq-PQlibInfo"/> to the application's
       default stdio output stream (stdout).
      </para>
+     <para>
+      On Linux the same output may be obtained by executing <filename>libpq.so</filename>
+      directly, e.g.
+      <programlisting>
+        $ /usr/pgsql-11/lib/libpq.so
+      </programlisting>
+     </para>
      <note>
       <para>
        This function appeared in <productname>PostgreSQL</productname> version 14.
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index 8a9a6f4c09..330e00bfc9 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -90,6 +90,11 @@ SHLIB_PREREQS = submake-libpgport
 
 SHLIB_EXPORTS = exports.txt
 
+# Support ./libpq.so execution of the built library; see libpq-version.c
+ifeq ($(host_tuple),x86_64-pc-linux-gnu)
+SHLIB_LINK += -Wl,--entry=libpq_exec_main
+endif
+
 PKG_CONFIG_REQUIRES_PRIVATE = libssl libcrypto
 
 all: all-lib
diff --git a/src/interfaces/libpq/libpq-version.c b/src/interfaces/libpq/libpq-version.c
index bab0263848..a24496360d 100644
--- a/src/interfaces/libpq/libpq-version.c
+++ b/src/interfaces/libpq/libpq-version.c
@@ -148,3 +148,31 @@ PQlibInfoPrint(void)
 		ientry ++;
 	}
 }
+
+/*
+ * If gcc and ld or clang and ld.lld would offer a --dynamic-linker=default
+ * or similar to force the .interp section to be emitted when building with
+ * -shared, we wouldn't need this. As it is, limit support for running
+ * libpq as an executable to x64 linux.
+ */
+#if defined(__GNUC__) && defined(__linux__) && defined(__x86_64__)
+const char interp_section[] __attribute__((section(".interp"))) = "/lib64/ld-linux-x86-64.so.2";
+
+/*
+ * Report library version and configuration by dumping PGlibInfoEntries to
+ * stdout when libpq is invoked as ./libpq.so. Do not call this when loading
+ * libpq as a shared library. Use PQlibInfo() instead.
+ *
+ * This won't work on Windows. You can abuse it with rundll32 if you must, but
+ * that's deprecated and should not be relied upon.
+ */
+extern void
+libpq_exec_main(void);
+
+void
+libpq_exec_main(void)
+{
+	PQlibInfoPrint();
+	exit(0);
+}
+#endif
-- 
2.26.2

