https://gcc.gnu.org/g:f31fd0972456d5d5d45ae404d42ca4594e3ac907

commit r17-5380-gf31fd0972456d5d5d45ae404d42ca4594e3ac907
Author: Robert Dubner <[email protected]>
Date:   Mon Oct 19 17:21:23 2026 -0400

    cobol: Incorporate RUNPATH tags into gcobol-generated executables.
    
    Using RUNPATH tags is a better solution of just how a gcobol-generated
    executable goes about locating the .so file needed for execution.
    
    gcc/cobol/ChangeLog:
    
            * gcobolspec.cc (lang_specific_driver): Adjust the generation of
            libgcobol.spec.
            (lang_specific_pre_link): Likewise.
    
    libgcobol/ChangeLog:
    
            * Makefile.am: Incorporate new files.
            * Makefile.in: Regenerate.
            * configure: Regenerate.
            * configure.ac: Specify linker targets.
            * libgcobol.spec.in: Switch to LIBGCOBOL_RPATH_SPEC.
            * README.runpath: New file.
            * mk-rpath-spec.sh: New file.

Diff:
---
 gcc/cobol/gcobolspec.cc     | 11 ++++-
 libgcobol/Makefile.am       | 13 +++++-
 libgcobol/Makefile.in       | 19 +++++++--
 libgcobol/README.runpath    | 97 +++++++++++++++++++++++++++++++++++++++++++++
 libgcobol/configure         | 41 +++++++++++++++++--
 libgcobol/configure.ac      | 28 ++++++++++++-
 libgcobol/libgcobol.spec.in |  2 +-
 libgcobol/mk-rpath-spec.sh  | 11 +++++
 8 files changed, 210 insertions(+), 12 deletions(-)

diff --git a/gcc/cobol/gcobolspec.cc b/gcc/cobol/gcobolspec.cc
index 10ba87e1af85..29718a7d565b 100644
--- a/gcc/cobol/gcobolspec.cc
+++ b/gcc/cobol/gcobolspec.cc
@@ -88,6 +88,9 @@ static std::vector<cl_decoded_option>new_opt;
 static bool need_libgcobol = true;
 static bool need_libcompat = false; // This one need for dialect mf or ibm
 static bool need_libposix = true;
+/* Whether the link needs the runtime specs, independently of whether the
+   user has already supplied -lgcobol.  */
+static bool need_runtime_specs = false;
 
 // #define NOISY 1
 
@@ -162,6 +165,7 @@ lang_specific_driver (struct cl_decoded_option 
**in_decoded_options,
   bool saw_OPT_shared = false;
 
   bool verbose = false;
+  bool linking = true;
 
   // These flags indicate whether we need various libraries
 
@@ -264,6 +268,7 @@ lang_specific_driver (struct cl_decoded_option 
**in_decoded_options,
       case OPT_S:
       case OPT_fsyntax_only:
       case OPT_E:
+       linking = false;
         // With these options, no libraries need be loaded
         need_libgcobol   = false;
         need_libdl       = false;
@@ -427,6 +432,8 @@ lang_specific_driver (struct cl_decoded_option 
**in_decoded_options,
     need_libstdc     = false;
     }
 
+  need_runtime_specs = linking && n_infiles != 0;
+
   /* Second pass through arglist, transforming arguments as appropriate.  */
 
   append_arg(decoded_options[0]); /* Start with command name, of course.  */
@@ -624,8 +631,8 @@ lang_specific_driver (struct cl_decoded_option 
**in_decoded_options,
 int
 lang_specific_pre_link (void)
 {
-  if (need_libgcobol)
-    do_spec ("%:include(libgcobol.spec)");
+  if (need_runtime_specs)
+    return do_spec ("%:include(libgcobol.spec)");
 
   return 0;
 }
diff --git a/libgcobol/Makefile.am b/libgcobol/Makefile.am
index 0dfc706c18c1..402608fd68ed 100644
--- a/libgcobol/Makefile.am
+++ b/libgcobol/Makefile.am
@@ -45,6 +45,16 @@ if BUILD_LIBGCOBOL
 toolexeclib_LTLIBRARIES  = libgcobol.la libgcobol_posix.la 
libgcobol_compat_gnu.la
 toolexeclib_DATA = libgcobol.spec
 
+# Expand the installation directory at make time, after multilib and
+# version-specific directory variables have acquired their final values.
+# DESTDIR is deliberately excluded: it is a staging location, not a runtime
+# search directory.  config.status supplies the other spec substitutions.
+libgcobol.spec: libgcobol.spec.conf Makefile $(srcdir)/mk-rpath-spec.sh
+       $(SHELL) $(srcdir)/mk-rpath-spec.sh "$(toolexeclibdir)" < $< > [email protected]
+       mv [email protected] $@
+
+CLEANFILES = libgcobol.spec libgcobol.spec.tmp
+
 libsubdir := 
$(libdir)/gcc/$(target_noncanonical)/$(version)$(MULTISUBDIR)/cobol
 libsubincludedir = $(libsubdir)
 
@@ -229,6 +239,7 @@ LTCOBCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) 
$(LIBTOOLFLAGS) \
 .cbl.lo:
        $(LTCOBCOMPILE) $(COBFLAGS) $(MULTIFLAGS) -c -o $@ $<
 
-EXTRA_DIST = libgcobol.map libgcobol_posix.map libgcobol_compat_gnu.map
+EXTRA_DIST = libgcobol.map libgcobol_posix.map libgcobol_compat_gnu.map \
+       mk-rpath-spec.sh testsuite/runpath.py README.runpath
 
 endif BUILD_LIBGCOBOL
diff --git a/libgcobol/Makefile.in b/libgcobol/Makefile.in
index b2174b41a898..9ad6aba9f810 100644
--- a/libgcobol/Makefile.in
+++ b/libgcobol/Makefile.in
@@ -148,7 +148,7 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache 
config.log \
  configure.lineno config.status.lineno
 mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
 CONFIG_HEADER = config.h
-CONFIG_CLEAN_FILES = libgcobol.spec
+CONFIG_CLEAN_FILES = libgcobol.spec.conf
 CONFIG_CLEAN_VPATH_FILES =
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
@@ -357,6 +357,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
+LIBGCOBOL_RPATH_SPEC = @LIBGCOBOL_RPATH_SPEC@
 LIBGCOBOL_VERSION = @LIBGCOBOL_VERSION@
 LIBICONV = @LIBICONV@
 LIBM = @LIBM@
@@ -479,6 +480,7 @@ gcc_version := $(shell @get_gcc_base_ver@ 
$(top_srcdir)/../gcc/BASE-VER)
 # Skip the whole process if we are not building libgcobol.
 @BUILD_LIBGCOBOL_TRUE@toolexeclib_LTLIBRARIES = libgcobol.la 
libgcobol_posix.la libgcobol_compat_gnu.la
 @BUILD_LIBGCOBOL_TRUE@toolexeclib_DATA = libgcobol.spec
+@BUILD_LIBGCOBOL_TRUE@CLEANFILES = libgcobol.spec libgcobol.spec.tmp
 @BUILD_LIBGCOBOL_TRUE@libsubdir := 
$(libdir)/gcc/$(target_noncanonical)/$(version)$(MULTISUBDIR)/cobol
 @BUILD_LIBGCOBOL_TRUE@libsubincludedir = $(libsubdir)
 @BUILD_LIBGCOBOL_TRUE@libgcobol_la_SOURCES = \
@@ -640,7 +642,9 @@ gcc_version := $(shell @get_gcc_base_ver@ 
$(top_srcdir)/../gcc/BASE-VER)
 @BUILD_LIBGCOBOL_TRUE@LTCOBCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) 
$(LIBTOOLFLAGS) \
 @BUILD_LIBGCOBOL_TRUE@ --mode=compile $(AM_COBC) $(AM_COBFLAGS)
 
-@BUILD_LIBGCOBOL_TRUE@EXTRA_DIST = libgcobol.map libgcobol_posix.map 
libgcobol_compat_gnu.map
+@BUILD_LIBGCOBOL_TRUE@EXTRA_DIST = libgcobol.map libgcobol_posix.map 
libgcobol_compat_gnu.map \
+@BUILD_LIBGCOBOL_TRUE@ mk-rpath-spec.sh testsuite/runpath.py README.runpath
+
 all: config.h
        $(MAKE) $(AM_MAKEFLAGS) all-am
 
@@ -694,7 +698,7 @@ $(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ 
$(am__configure_deps)
 
 distclean-hdr:
        -rm -f config.h stamp-h1
-libgcobol.spec: $(top_builddir)/config.status $(srcdir)/libgcobol.spec.in
+libgcobol.spec.conf: $(top_builddir)/config.status $(srcdir)/libgcobol.spec.in
        cd $(top_builddir) && $(SHELL) ./config.status $@
 
 install-toolexeclibLTLIBRARIES: $(toolexeclib_LTLIBRARIES)
@@ -1030,6 +1034,7 @@ install-strip:
 mostlyclean-generic:
 
 clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
 
 distclean-generic:
        -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
@@ -1143,6 +1148,14 @@ uninstall-am: uninstall-nobase_libsubincludeHEADERS \
 .PRECIOUS: Makefile
 
 
+# Expand the installation directory at make time, after multilib and
+# version-specific directory variables have acquired their final values.
+# DESTDIR is deliberately excluded: it is a staging location, not a runtime
+# search directory.  config.status supplies the other spec substitutions.
+@[email protected]: libgcobol.spec.conf Makefile 
$(srcdir)/mk-rpath-spec.sh
+@BUILD_LIBGCOBOL_TRUE@ $(SHELL) $(srcdir)/mk-rpath-spec.sh "$(toolexeclibdir)" 
< $< > [email protected]
+@BUILD_LIBGCOBOL_TRUE@ mv [email protected] $@
+
 @BUILD_LIBGCOBOL_TRUE@$(LC_COPYDIR_BUILD)/%.cpy: ${srcdir}/compat/gnu/cpy/%.cpy
 @BUILD_LIBGCOBOL_TRUE@ mkdir -p `dirname $@`
 @BUILD_LIBGCOBOL_TRUE@ cp $< $@
diff --git a/libgcobol/README.runpath b/libgcobol/README.runpath
new file mode 100644
index 000000000000..1dc65bbf149f
--- /dev/null
+++ b/libgcobol/README.runpath
@@ -0,0 +1,97 @@
+Native Linux runtime search paths
+================================
+
+For native Linux builds with shared libraries enabled, libgcobol.spec adds
+--enable-new-dtags and -rpath to ordinary GCobol links.  The path is the
+configured toolexeclibdir, expanded by make so that multilib and
+--enable-version-specific-runtime-libs layouts are respected.  No /opt path
+is hard-coded.  DESTDIR is not part of the path.
+
+The three runtime DSOs receive the same RUNPATH.  This is necessary because
+ELF DT_RUNPATH applies to an object's direct dependencies, not recursively
+to the dependencies of those dependencies.  Private dependencies installed
+elsewhere still need their own suitable search paths.  This change does not
+automatically discover arbitrary directories containing private libxml2,
+libiconv, or other external dependencies.
+
+The path is absolute.  An executable can be moved independently of the
+compiler, but moving the runtime installation requires relinking programs
+(or explicitly overriding the loader search).  $ORIGIN in a user executable
+would refer to that executable's directory, not the compiler's directory.
+
+--disable-libgcobol-rpath restores the previous runtime-path behavior.
+Non-Linux targets, cross builds, and builds without shared libraries do not
+receive these new ELF options.  Darwin's existing rpath flags are unchanged.
+Static and static-PIE links receive no RUNPATH.  -static-libgcobol may still
+need RUNPATH for the shared POSIX/compatibility libraries.  Shared COBOL
+outputs receive RUNPATH too, for their own direct runtime dependencies.
+
+The driver now loads libgcobol.spec for links with inputs even when the
+user explicitly supplied -lgcobol or libgcobol.a.  It must not use the
+"automatically add -lgcobol" decision to decide whether to load specs.
+Compile-only, preprocess-only, assembly-only, relocatable, syntax-only,
+-nostdlib and -nodefaultlibs invocations do not load the runtime specs.
+
+Packaging
+---------
+
+1. Keep libgcobol.spec and the runtime DSOs in their configured installation
+   locations.  Reconfigure/rebuild for a different final prefix.  Stage with
+   DESTDIR; never configure the staging directory as the final prefix.
+
+2. Stop registering the GCobol library directory in /etc/ld.so.conf.d and
+   stop exporting a global LD_LIBRARY_PATH.  On upgrades, remove only the
+   obsolete configuration owned/generated by this package, using the
+   package manager's conffile migration machinery where applicable.  Refresh
+   the loader cache after removing the old registration.  Do not delete
+   unrelated or locally maintained loader configuration.
+
+3. Removing global registration prevents unrelated programs such as apt
+   from selecting GCobol's private libstdc++.so.6 or libgcc_s.so.1.  RUNPATH
+   still makes ALL matching libraries in that directory eligible for the
+   GCobol program itself.  Prefer system dependency packages when their ABI
+   is sufficient.  If private GCC runtimes are necessary, bundle compatible
+   versions deliberately; this patch does not provide per-SONAME isolation.
+
+4. Build all packaged binaries and shared libraries against the oldest
+   supported glibc baseline.  A RUNPATH cannot make a library requiring
+   GLIBC_2.38 run against glibc 2.35.  Audit the compiler executables and any
+   separately packaged tools too: this patch changes generated COBOL links
+   and libgcobol DSOs, not the bootstrap compiler/tool link flags.
+
+5. Previously linked COBOL executables do not acquire RUNPATH on upgrade.
+   Rebuild those executables before relying on removal of the old global
+   configuration.  Include this change in the package's migration notes.
+
+Regression checks
+-----------------
+
+Run the mechanism tests on Linux with a C compiler and readelf:
+
+    python3 libgcobol/testsuite/runpath.py
+
+These exercise GCC spec expansion and the real ELF loader, including a
+negative transitive-dependency test, but do not build the COBOL compiler.
+
+After building and installing the patched compiler into a clean GNU/Linux
+container with no GCobol loader configuration, run, for example:
+
+    python3 libgcobol/testsuite/runpath.py \
+      --gcobol /opt/gcobol/bin/gcobol \
+      --runtime-dir /opt/gcobol/lib64
+
+Use the actual configured runtime directory.  This tests ordinary linking,
+explicit -lgcobol, the mf compatibility dialect, -static-libgcobol, separate
+compilation, shared output, driver suppression options, all runtime DSO
+tags, and execution with the loader cache inhibited.  It prints the actual
+loaded libraries for review.  Static-libgcobol requires static archives to
+have been built/installed.  Dependencies requiring ABI symbols missing
+from the target system are a test failure, not a reason to restore global
+loader registration.
+
+In the package-install/upgrade test, also compare `ldd /usr/bin/apt` before
+and after installation and run `apt --version`.  Its libstdc++ and libgcc_s
+must remain the system copies.  Test fresh installation and upgrade from a
+package that registered /opt/gcobol/lib64, plus removal of the new package.
+Package scripts are maintained outside this upstream GCC source tree; the
+exact migration edits must be made and tested in that packaging repository.
diff --git a/libgcobol/configure b/libgcobol/configure
index 9b26aa99355d..a03c8cd67ab6 100755
--- a/libgcobol/configure
+++ b/libgcobol/configure
@@ -646,6 +646,7 @@ LIBQUADLIB
 LIBQUADSPEC
 LIBXML2_LIBS
 LIBXML2_CPPFLAGS
+LIBGCOBOL_RPATH_SPEC
 extra_ldflags_libgcobol
 LIBGCOBOL_VERSION
 BUILD_LIBGCOBOL_FALSE
@@ -807,6 +808,7 @@ with_toolexeclibdir
 enable_rpath
 with_libiconv_prefix
 with_libiconv_type
+enable_libgcobol_rpath
 with_target_libxml2
 with_target_libxml2_include
 with_target_libxml2_lib
@@ -1464,6 +1466,9 @@ Optional Features:
                           install libraries with @rpath/library-name, requires
                           rpaths to be added to executables
   --disable-rpath         do not hardcode runtime library paths
+  --disable-libgcobol-rpath
+                          do not embed the native Linux libgcobol installation
+                          directory in RUNPATH
   --disable-libquadmath   disable libquadmath support for libgcobol
 
 Optional Packages:
@@ -12220,7 +12225,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12223 "configure"
+#line 12228 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12326,7 +12331,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12329 "configure"
+#line 12334 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -17689,6 +17694,34 @@ case $host in
 esac
 
 
+# Do not add ELF linker options on other targets, or embed build-host paths
+# in programs produced by a cross compiler.  Native Linux installations can
+# find their runtime without changing the system-wide loader configuration.
+# Check whether --enable-libgcobol-rpath was given.
+if test "${enable_libgcobol_rpath+set}" = set; then :
+  enableval=$enable_libgcobol_rpath; case $enableval in
+     yes|no) ;;
+     *) as_fn_error $? "--enable-libgcobol-rpath expects yes or no" "$LINENO" 
5 ;;
+   esac
+else
+  enable_libgcobol_rpath=yes
+fi
+
+LIBGCOBOL_RPATH_SPEC=
+case $host in
+  *-*-linux*)
+    if test x$enable_libgcobol_rpath = xyes \
+       && test x$enable_shared = xyes \
+       && { test -z "$with_cross_host" || test x$with_cross_host = xno; }; then
+      LIBGCOBOL_RPATH_SPEC='%{!static:%{!static-pie:--enable-new-dtags -rpath 
@LIBGCOBOL_RUNTIME_DIR@}}'
+      # RUNPATH is not transitive.  Each runtime DSO needs its own entry
+      # for dependencies installed alongside it (for example libquadmath).
+      extra_ldflags_libgcobol="$extra_ldflags_libgcobol"' 
-Wl,--enable-new-dtags -Wl,-rpath,$(toolexeclibdir)'
+    fi
+    ;;
+esac
+
+
 
 
 
@@ -18420,7 +18453,7 @@ fi
 SPEC_LIBGCOBOL_DEPS="$LIBS"
 
 
-ac_config_files="$ac_config_files Makefile libgcobol.spec"
+ac_config_files="$ac_config_files Makefile 
libgcobol.spec.conf:libgcobol.spec.in"
 
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: libgcobol has been configured." >&5
@@ -19546,7 +19579,7 @@ do
     "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
     "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
-    "libgcobol.spec") CONFIG_FILES="$CONFIG_FILES libgcobol.spec" ;;
+    "libgcobol.spec.conf") CONFIG_FILES="$CONFIG_FILES 
libgcobol.spec.conf:libgcobol.spec.in" ;;
 
   *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
diff --git a/libgcobol/configure.ac b/libgcobol/configure.ac
index 5baf9f12ed09..9c9295483429 100644
--- a/libgcobol/configure.ac
+++ b/libgcobol/configure.ac
@@ -204,6 +204,32 @@ case $host in
 esac
 AC_SUBST(extra_ldflags_libgcobol)
 
+# Do not add ELF linker options on other targets, or embed build-host paths
+# in programs produced by a cross compiler.  Native Linux installations can
+# find their runtime without changing the system-wide loader configuration.
+AC_ARG_ENABLE([libgcobol-rpath],
+  [AS_HELP_STRING([--disable-libgcobol-rpath],
+    [do not embed the native Linux libgcobol installation directory in 
RUNPATH])],
+  [case $enableval in
+     yes|no) ;;
+     *) AC_MSG_ERROR([--enable-libgcobol-rpath expects yes or no]) ;;
+   esac],
+  [enable_libgcobol_rpath=yes])
+LIBGCOBOL_RPATH_SPEC=
+case $host in
+  *-*-linux*)
+    if test x$enable_libgcobol_rpath = xyes \
+       && test x$enable_shared = xyes \
+       && { test -z "$with_cross_host" || test x$with_cross_host = xno; }; then
+      LIBGCOBOL_RPATH_SPEC='%{!static:%{!static-pie:--enable-new-dtags -rpath 
@LIBGCOBOL_RUNTIME_DIR@}}'
+      # RUNPATH is not transitive.  Each runtime DSO needs its own entry
+      # for dependencies installed alongside it (for example libquadmath).
+      extra_ldflags_libgcobol="$extra_ldflags_libgcobol"' 
-Wl,--enable-new-dtags -Wl,-rpath,$(toolexeclibdir)'
+    fi
+    ;;
+esac
+AC_SUBST(LIBGCOBOL_RPATH_SPEC)
+
 AC_CHECK_HEADERS_ONCE(floatingpoint.h ieeefp.h fenv.h fptrap.h \
 complex.h stdlib.h errno.h)
 
@@ -388,7 +414,7 @@ AC_SUBST(SPEC_LIBGCOBOL_DEPS)
 
 AC_CONFIG_FILES([
 Makefile
-libgcobol.spec
+libgcobol.spec.conf:libgcobol.spec.in
 ])
 
 AC_MSG_NOTICE([libgcobol has been configured.])
diff --git a/libgcobol/libgcobol.spec.in b/libgcobol/libgcobol.spec.in
index 461587d1fb8e..470ff17dfada 100644
--- a/libgcobol/libgcobol.spec.in
+++ b/libgcobol/libgcobol.spec.in
@@ -5,4 +5,4 @@
 #
 
 %rename lib liborig
-*lib: @LIBQUADSPEC@ @LIBM@ %(liborig)
+*lib: @LIBGCOBOL_RPATH_SPEC@ @LIBQUADSPEC@ @LIBM@ %(liborig)
diff --git a/libgcobol/mk-rpath-spec.sh b/libgcobol/mk-rpath-spec.sh
new file mode 100644
index 000000000000..c37446dcff31
--- /dev/null
+++ b/libgcobol/mk-rpath-spec.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+# Copyright (C) 2026 Free Software Foundation, Inc.
+# This file is part of GCC, distributed under the GNU General Public License,
+# version 3 or (at your option) any later version.  See COPYING3.
+
+# Escape a literal installation directory for GCC specs, then for a sed
+# replacement.  In particular, whitespace must remain in a single argument
+# and '%' must not introduce a spec expansion.
+test "$#" = 1 || exit 1
+runtime_dir=$(printf '%s\n' "$1" | sed 's/[%]/%%/g; s/[\\ \t]/\\&/g; 
s/[\\&|]/\\&/g') || exit 1
+sed "s|@LIBGCOBOL_RUNTIME_DIR@|$runtime_dir|g"

Reply via email to