[exim-cvs] transport dynamic modules

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] transport dynamic modules
Gitweb: https://git.exim.org/exim.git/commitdiff/f4db5740c56f3b29b11a796147086ec8848a7e90
Commit:     f4db5740c56f3b29b11a796147086ec8848a7e90
Parent:     c657b20d9b1dfc2f437cc4ea220fa9ee7ba73088
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Thu Aug 15 14:53:22 2024 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Thu Aug 15 14:53:22 2024 +0100


    transport dynamic modules
---
 doc/doc-docbook/spec.xfpt                          |   3 +-
 doc/doc-txt/NewStuff                               |   4 +-
 src/scripts/Configure-Makefile                     |  17 +-
 src/scripts/MakeLinks                              |   3 +-
 src/scripts/{routers-Makefile => drivers-Makefile} |  60 +++---
 src/src/EDITME                                     |   9 +
 src/src/drtables.c                                 | 215 ++++++---------------
 src/src/globals.h                                  |   7 +-
 src/src/route.c                                    |   1 -
 src/src/routers/Makefile                           |   2 +-
 src/src/transport.c                                |  55 ++++--
 src/src/transports/Makefile                        |  50 ++++-
 src/src/transports/appendfile.c                    |  25 +++
 src/src/transports/autoreply.c                     |  25 +++
 src/src/transports/lmtp.c                          |  25 +++
 src/src/transports/pipe.c                          |  25 +++
 src/src/transports/queuefile.c                     |  25 +++
 src/src/transports/smtp.c                          |  25 +++
 test/confs/0000                                    |   1 +
 test/runtest                                       |  10 +-
 20 files changed, 360 insertions(+), 227 deletions(-)


diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 84597da83..9fbf7a2db 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -2072,6 +2072,7 @@ withdrawn.
.section "Dynamically loaded module support" "SECTdynamicmodules"
.cindex "lookup modules"
.cindex "router modules"
+.cindex "transport modules"
.cindex "dynamic modules"
.cindex ".so building"
On some platforms, Exim supports not compiling all lookup types directly into
@@ -2083,7 +2084,7 @@ dependencies.
Most, but not all, lookup types can be built this way.

.new
-Similarly, router drivers can be built as external modules.
+Similarly, router and transport drivers can be built as external modules.
This permits a smaller exim binary, growing only as needed for the
runtime cofiguration.
.wen
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index bb7f2290e..be0f0c679 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -14,8 +14,8 @@ Version 4.98

3. Events smtp:fail:protocol and smtp:fail:syntax

- 4. JSON lookup support, and all the router driver except manualroute,
-    can now be built as lodable modules
+ 4. JSON lookup support, all the router drivers except manualroute, and all the transport
+    drivers except smtp can now be built as lodable modules


Version 4.98
------------
diff --git a/src/scripts/Configure-Makefile b/src/scripts/Configure-Makefile
index 3b0528940..20e686b51 100755
--- a/src/scripts/Configure-Makefile
+++ b/src/scripts/Configure-Makefile
@@ -10,6 +10,7 @@

LC_ALL=C
export LC_ALL
+set -e


# First off, get the OS type, and check that there is a make file for it.
@@ -291,12 +292,16 @@ rm -f $mftt
cp ../src/lookups/Makefile $look_mf_pre
../scripts/lookups-Makefile

-class="routers"
-cp ../src/$class/Makefile $class/Makefile.predynamic
-../scripts/$class-Makefile
-mv routers/Makefile.postdynamic $class/Makefile
-rm $class/Makefile.predynamic
-class=
+while read class classdef names
+do
+  cp ../src/$class/Makefile $class/Makefile.predynamic
+  CLASS=$class CLASSDEF=$classdef DRNAMES="$names" ../scripts/drivers-Makefile
+  mv $class/Makefile.postdynamic $class/Makefile
+  rm $class/Makefile.predynamic
+done <<-END
+ routers ROUTER        ACCEPT DNSLOOKUP IPLITERAL IPLOOKUP MANUALROUTE QUERYPROGRAM REDIRECT
+ transports TRANSPORT    APPENDFILE AUTOREPLY LMTP PIPE QUEUEFILE SMTP
+END


# See if there is a definition of EXIM_PERL in what we have built so far.
# If so, run Perl to find the default values for PERL_CC, PERL_CCOPTS,
diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks
index f413c625e..998b73bf9 100755
--- a/src/scripts/MakeLinks
+++ b/src/scripts/MakeLinks
@@ -63,7 +63,8 @@ cd ..
d="transports"
mkdir $d
cd $d
-for f in README Makefile appendfile.h appendfile.c autoreply.h \
+# Makefile is generated
+for f in README appendfile.h appendfile.c autoreply.h \
autoreply.c lmtp.h lmtp.c pipe.h pipe.c queuefile.c queuefile.h \
smtp.h smtp.c smtp_socks.c tf_maildir.c tf_maildir.h
do
diff --git a/src/scripts/routers-Makefile b/src/scripts/drivers-Makefile
similarity index 72%
rename from src/scripts/routers-Makefile
rename to src/scripts/drivers-Makefile
index 5bb6a78d8..0c3da19cb 100755
--- a/src/scripts/routers-Makefile
+++ b/src/scripts/drivers-Makefile
@@ -1,17 +1,23 @@
#! /bin/sh

-# Copyright (c) The Exim Maintainers 1995 - 2021
+# Copyright (c) The Exim Maintainers 1995 - 2024
# SPDX-License-Identifier: GPL-2.0-or-later

-# We turn the configure-built build-$foo/routers/Makefile.predynamic into Makefile
+set -e
+class=${CLASS:?}
+classdef=${CLASSDEF:?}
+drnames="${DRNAMES:?}"
+
+# We turn the configure-built build-$foo/$class/Makefile.predynamic into Makefile.
+# This is used for router and transport drivers, called from scripts/Configure-Makefile.

# We always re-exec ourselves at least once, because it's the cleanest and
# most portable way to turn on various features we expect of POSIX sh.
-if [ -z "$EXIM_ROUTER_MAKEFILE_ADJUSTED" ]
+if [ -z "$EXIM_DRIVER_MAKEFILE_ADJUSTED" ]
then
SHELL=/bin/sh
- EXIM_ROUTER_MAKEFILE_ADJUSTED=yes
- export EXIM_ROUTER_MAKEFILE_ADJUSTED
+ EXIM_DRIVER_MAKEFILE_ADJUSTED=yes
+ export EXIM_DRIVER_MAKEFILE_ADJUSTED

# Solaris sh and tr are problematic until we get xpg4 variants
if [ -x /usr/xpg4/bin/sh ]
@@ -46,8 +52,8 @@ then
exec "$SHELL" "$0" "$@"
fi

-input=routers/Makefile.predynamic
-target=routers/Makefile.postdynamic
+input=$class/Makefile.predynamic
+target=$class/Makefile.postdynamic
defs_source=Makefile-t
tag_marker='MAGIC-TAG-MODS-OBJ-RULES-GO-HERE'

@@ -76,10 +82,10 @@ fi
if grep -q "^CFLAGS_DYNAMIC[ $tab?:]*=" "$defs_source"
then
# we have a definition, we're good to go
- echo >&2 ">>> Creating routers/Makefile for building dynamic modules"
+ echo >&2 ">>> Creating $class/Makefile for building dynamic modules"
enable_dynamic=yes
else
- echo >&2 ">>> Creating routers/Makefile without dynamic module support"
+ echo >&2 ">>> Creating $class/Makefile without dynamic module support"
enable_dynamic=''
# We always do something now, since there should always be a lookup,
# and now we need to run in order to put the OBJ=$(OBJ)+ rules in. So we
@@ -91,27 +97,18 @@ fi

want_dynamic() {
local dyn_name="$1"
- local re="ROUTER_${dyn_name}[ $tab]*=[ $tab]*2"
- env | grep -q "^$re"
+ local re="(${classdef}|EXPERIMENTAL)_${dyn_name}[ $tab]*=[ $tab]*2"
+ env | grep -E -q "^$re"
if [ $? -eq 0 ]; then return 0; fi
- grep -q "^[ $tab]*$re" "$defs_source"
+ grep -E -q "^[ $tab]*$re" "$defs_source"
}

want_at_all() {
local want_name="$1"
- local re="ROUTER_${want_name}[ $tab]*=[ $tab]*."
- env | grep -q "^$re"
- if [ $? -eq 0 ]; then return 0; fi
- grep -q "^[ $tab]*$re" "$defs_source"
-}
-
-# Adapted want_at_all above to work for EXPERIMENTAL features
-want_experimental() {
- local want_name="$1"
- local re="EXPERIMENTAL_${want_name}[ $tab]*=[ $tab]*."
- env | grep -q "^$re"
+ local re="(${classdef}|EXPERIMENTAL)_${want_name}[ $tab]*=[ $tab]*."
+ env | grep -E -q "^$re"
if [ $? -eq 0 ]; then return 0; fi
- grep -q "^[ $tab]*$re" "$defs_source"
+ grep -E -q "^[ $tab]*$re" "$defs_source"
}

 # The values of these variables will be emitted into the Makefile.
@@ -140,15 +137,15 @@ emit_module_rule() {
       exit 1
     fi
     MODS="${MODS} ${mod_name}.so"
-#    pkgconf=$(grep "^ROUTER_${name}_PC" "$defs_source")
+#    pkgconf=$(grep "^${classdef}_${name}_PC" "$defs_source")
 #    if [ $? -eq 0 ]; then
 #      pkgconf=$(echo $pkgconf | sed 's/^.*= *//')
-#      echo "ROUTER_${mod_name}_INCLUDE = $(pkg-config --cflags $pkgconf)"
-#      echo "ROUTER_${mod_name}_LIBS = $(pkg-config --libs $pkgconf)"
+#      echo "${classdef}_${mod_name}_INCLUDE = $(pkg-config --cflags $pkgconf)"
+#      echo "${classdef}_${mod_name}_LIBS = $(pkg-config --libs $pkgconf)"
 #    else
-#      grep "^ROUTER_${name}_" "$defs_source"
-#      echo "ROUTER_${mod_name}_INCLUDE = \$(ROUTER_${name}_INCLUDE)"
-#      echo "ROUTER_${mod_name}_LIBS = \$(ROUTER_${name}_LIBS)"
+#      grep "^${classdef}_${name}_" "$defs_source"
+#      echo "${classdef}_${mod_name}_INCLUDE = \$(${classdef}_${name}_INCLUDE)"
+#      echo "${classdef}_${mod_name}_LIBS = \$(${classdef}_${name}_LIBS)"
 #    fi
   elif want_at_all "$name"
   then
@@ -162,8 +159,7 @@ exec > "$target"


sed -n "1,/$tag_marker/p" < "$input"

-for name_mod in \
-    ACCEPT DNSLOOKUP IPLITERAL IPLOOKUP MANUALROUTE QUERYPROGRAM REDIRECT
+for name_mod in $drnames
 do
   emit_module_rule $name_mod
 done
diff --git a/src/src/EDITME b/src/src/EDITME
index 5e755692f..820793032 100644
--- a/src/src/EDITME
+++ b/src/src/EDITME
@@ -344,6 +344,15 @@ ROUTER_REDIRECT=yes
 # file. By commenting out those you know you don't want to use, you can make
 # the binary a bit smaller. If you are unsure, leave all of these included for
 # now.
+#
+# If set to "2" instead of "yes" then the corresponding driver will be
+# built as a module and must be installed into LOOKUP_MODULE_DIR (the name
+# is historic).
+# You need to add -export-dynamic -rdynamic to EXTRALIBS. You may also need to
+# add -ldl to EXTRALIBS so that dlopen() is available to Exim. You need to
+# define CFLAGS_DYNAIC and LOOKUP_MODULE_DIR below so the builds are done right,
+# and so the exim binary actually loads dynamic lookup modules.
+# The smtp transport cannot be built as a module.


TRANSPORT_APPENDFILE=yes
TRANSPORT_AUTOREPLY=yes
diff --git a/src/src/drtables.c b/src/src/drtables.c
index b51409096..026f2ff97 100644
--- a/src/src/drtables.c
+++ b/src/src/drtables.c
@@ -230,134 +230,11 @@ exim binary. */

#include "routers/rf_functions.h"

-#ifdef TRANSPORT_APPENDFILE
-# include "transports/appendfile.h"
-#endif
-
-#ifdef TRANSPORT_AUTOREPLY
-# include "transports/autoreply.h"
-#endif
-
-#ifdef TRANSPORT_LMTP
-# include "transports/lmtp.h"
-#endif
-
-#ifdef TRANSPORT_PIPE
-# include "transports/pipe.h"
-#endif
-
-#ifdef EXPERIMENTAL_QUEUEFILE
-# include "transports/queuefile.h"
-#endif
-
-#ifdef TRANSPORT_SMTP
-# include "transports/smtp.h"
-#endif
-

router_info * routers_available = NULL;
+transport_info * transports_available = NULL;


-transport_info * transports_available_newlist = NULL;
-transport_info transports_available_oldarray[] = {
-#ifdef TRANSPORT_APPENDFILE
-  {
-  .drinfo = {
-    .driver_name =    US"appendfile",
-    .options =        appendfile_transport_options,
-    .options_count =    &appendfile_transport_options_count,
-    .options_block =    &appendfile_transport_option_defaults,       /* private options defaults */
-    .options_len =    sizeof(appendfile_transport_options_block),
-    .init =        appendfile_transport_init,
-    },
-  .code =        appendfile_transport_entry,
-  .tidyup =        NULL,
-  .closedown =        NULL,
-  .local =        TRUE
-  },
-#endif
-#ifdef TRANSPORT_AUTOREPLY
-  {
-  .drinfo = {
-    .driver_name =    US"autoreply",
-    .options =        autoreply_transport_options,
-    .options_count =    &autoreply_transport_options_count,
-    .options_block =    &autoreply_transport_option_defaults,
-    .options_len =    sizeof(autoreply_transport_options_block),
-    .init =        autoreply_transport_init,
-    },
-  .code =        autoreply_transport_entry,
-  .tidyup =        NULL,
-  .closedown =        NULL,
-  .local =        TRUE
-  },
-#endif
-#ifdef TRANSPORT_LMTP
-  {
-  .drinfo = {
-    .driver_name =    US"lmtp",
-    .options =        lmtp_transport_options,
-    .options_count =    &lmtp_transport_options_count,
-    .options_block =    &lmtp_transport_option_defaults,
-    .options_len =    sizeof(lmtp_transport_options_block),
-    .init =        lmtp_transport_init,
-    },
-  .code =        lmtp_transport_entry,
-  .tidyup =        NULL,
-  .closedown =        NULL,
-  .local =        TRUE
-  },
-#endif
-#ifdef TRANSPORT_PIPE
-  {
-  .drinfo = {
-    .driver_name =    US"pipe",
-    .options =        pipe_transport_options,
-    .options_count =    &pipe_transport_options_count,
-    .options_block =    &pipe_transport_option_defaults,
-    .options_len =    sizeof(pipe_transport_options_block),
-    .init =        pipe_transport_init,
-    },
-  .code =        pipe_transport_entry,
-  .tidyup =        NULL,
-  .closedown =        NULL,
-  .local =        TRUE
-  },
-#endif
-#ifdef EXPERIMENTAL_QUEUEFILE
-  {
-  .drinfo = {
-    .driver_name =    US"queuefile",
-    .options =        queuefile_transport_options,
-    .options_count =    &queuefile_transport_options_count,
-    .options_block =    &queuefile_transport_option_defaults,
-    .options_len =    sizeof(queuefile_transport_options_block),
-    .init =        queuefile_transport_init,
-    },
-  .code =        queuefile_transport_entry,
-  .tidyup =        NULL,
-  .closedown =        NULL,
-  .local =        TRUE
-  },
-#endif
-#ifdef TRANSPORT_SMTP
-  {
-  .drinfo = {
-    .driver_name =    US"smtp",
-    .options =        smtp_transport_options,
-    .options_count =    &smtp_transport_options_count,
-    .options_block =    &smtp_transport_option_defaults,
-    .options_len =    sizeof(smtp_transport_options_block),
-    .init =        smtp_transport_init,
-    },
-  .code =        smtp_transport_entry,
-  .tidyup =        NULL,
-  .closedown =        smtp_transport_closedown,
-  .local =        FALSE
-  },
-#endif
-  { .drinfo = { .driver_name = US"" }}
-};


#ifndef MACRO_PREDEF

@@ -429,35 +306,69 @@ return g;
 gstring *
 transport_show_supported(gstring * g)
 {
-g = string_cat(g, US"Transports:");
-#ifdef TRANSPORT_APPENDFILE
-  g = string_cat(g, US" appendfile");
-  #ifdef SUPPORT_MAILDIR
-    g = string_cat(g, US"/maildir");    /* damn these subclasses */
-  #endif
-  #ifdef SUPPORT_MAILSTORE
-    g = string_cat(g, US"/mailstore");
-  #endif
-  #ifdef SUPPORT_MBX
-    g = string_cat(g, US"/mbx");
-  #endif
-#endif
-#ifdef TRANSPORT_AUTOREPLY
-  g = string_cat(g, US" autoreply");
-#endif
-#ifdef TRANSPORT_LMTP
-  g = string_cat(g, US" lmtp");
-#endif
-#ifdef TRANSPORT_PIPE
-  g = string_cat(g, US" pipe");
-#endif
-#ifdef EXPERIMENTAL_QUEUEFILE
-  g = string_cat(g, US" queuefile");
-#endif
-#ifdef TRANSPORT_SMTP
-  g = string_cat(g, US" smtp");
+uschar * b = US""        /* static-build transportnames */
+#if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE!=2
+  " appendfile"
+# ifdef SUPPORT_MAILDIR
+    "/maildir"
+# endif
+# ifdef SUPPORT_MAILSTORE
+    "/mailstore"
+# endif
+# ifdef SUPPORT_MBX
+    "/mbx"
+# endif
+#endif
+#if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY!=2
+  " autoreply"
+#endif
+#if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP!=2
+  " lmtp"
+#endif
+#if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE!=2
+  " pipe"
+#endif
+#if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE!=2
+  " queuefile"
+#endif
+#if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP!=2
+  " smtp"
 #endif
-return string_cat(g, US"\n");
+  ;
+
+uschar * d = US""        /* dynamic-module transportnames */
+#if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE==2
+  " appendfile"
+# ifdef SUPPORT_MAILDIR
+    "/maildir"
+# endif
+# ifdef SUPPORT_MAILSTORE
+    "/mailstore"
+# endif
+# ifdef SUPPORT_MBX
+    "/mbx"
+# endif
+#endif
+#if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY==2
+  " autoreply"
+#endif
+#if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP==2
+  " lmtp"
+#endif
+#if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE==2
+  " pipe"
+#endif
+#if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE==2
+  " queuefile"
+#endif
+#if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP==2
+  " smtp"
+#endif
+  ;
+
+if (*b) g = string_fmt_append(g, "Transports (built-in):%s\n", b);
+if (*d) g = string_fmt_append(g, "Transports (dynamic): %s\n", d);
+return g;
 }



diff --git a/src/src/globals.h b/src/src/globals.h
index 6bca06c00..7fc888f5b 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -1111,10 +1111,9 @@ extern int     transport_newlines;     /* Accurate count of number of newline ch
 extern const uschar **transport_filter_argv; /* For on-the-fly filtering */
 extern int     transport_filter_timeout; /* Timeout for same */


-extern transport_info transports_available_oldarray[]; /* Vector of available transports */
-extern transport_info * transports_available_newlist;
-extern transport_instance *transports; /* Chain of instantiated transports */
-extern transport_instance transport_defaults; /* Default values */
+extern transport_info * transports_available;    /* Listof available transports */
+extern transport_instance *transports;        /* Chain of instantiated transports */
+extern transport_instance transport_defaults;    /* Default values */


 extern int     transport_write_timeout;/* Set to time out individual writes */


diff --git a/src/src/route.c b/src/src/route.c
index 07f0a6b20..293d21c50 100644
--- a/src/src/route.c
+++ b/src/src/route.c
@@ -227,7 +227,6 @@ function. */
void
route_init(void)
{
-
int old_pool = store_pool;
store_pool = POOL_PERM;
{
diff --git a/src/src/routers/Makefile b/src/src/routers/Makefile
index d13a493e9..8ff3d81ab 100644
--- a/src/src/routers/Makefile
+++ b/src/src/routers/Makefile
@@ -7,7 +7,7 @@

 # nb: at build time, the version of this file used will have had some
 #     extra variable definitions and prepended to it and module build rules
-#     interpolated below. This is done by scripts/routers-Makefile.
+#     interpolated below. This is done by scripts/drivers-Makefile.


# MAGIC-TAG-MODS-OBJ-RULES-GO-HERE

diff --git a/src/src/transport.c b/src/src/transport.c
index e42625ce8..063fda361 100644
--- a/src/src/transport.c
+++ b/src/src/transport.c
@@ -102,8 +102,7 @@ uschar buf[64];

options_from_list(optionlist_transports, nelem(optionlist_transports), US"TRANSPORTS", NULL);

-//for (transport_info * ti= transports_available; ti->drinfo.driver_name[0]; ti++)
-for (driver_info * di= (driver_info *)transports_available_newlist; di; di = di->next)
+for (driver_info * di= (driver_info *)transports_available; di; di = di->next)
   {
   spf(buf, sizeof(buf), US"_DRIVER_TRANSPORT_%T", di->driver_name);
   builtin_macro_create(buf);
@@ -146,21 +145,51 @@ the work. */
 void
 transport_init(void)
 {
-for (transport_info * tblent = transports_available_oldarray;
-    *tblent->drinfo.driver_name; tblent++)
+int old_pool = store_pool;
+store_pool = POOL_PERM;
   {
-  driver_info * listent = store_get(sizeof(transport_info), tblent);
-  memcpy(listent, tblent, sizeof(transport_info));
-  listent->next = (driver_info *)transports_available_newlist;
-  transports_available_newlist = (transport_info *)listent;
+  driver_info ** anchor = (driver_info **) &transports_available;
+  extern transport_info appendfile_transport_info;
+  extern transport_info autoreply_transport_info;
+  extern transport_info lmtp_transport_info;
+  extern transport_info pipe_transport_info;
+  extern transport_info queuefile_transport_info;
+  extern transport_info smtp_transport_info;
+
+  /* Add the transport drivers that are built for static linkage to the
+  list of availables. */
+
+#if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE!=2
+  add_driver_info(anchor, &appendfile_transport_info.drinfo, sizeof(transport_info));
+#endif
+#if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY!=2
+  add_driver_info(anchor, &autoreply_transport_info.drinfo, sizeof(transport_info));
+#endif
+#if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP!=2
+  add_driver_info(anchor, &lmtp_transport_info.drinfo, sizeof(transport_info));
+#endif
+#if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE!=2
+  add_driver_info(anchor, &pipe_transport_info.drinfo, sizeof(transport_info));
+#endif
+#if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE!=2
+  add_driver_info(anchor, &queuefile_transport_info.drinfo, sizeof(transport_info));
+#endif
+#if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP!=2
+  add_driver_info(anchor, &smtp_transport_info.drinfo, sizeof(transport_info));
+#endif
   }
+store_pool = old_pool;
+
+/* Read the config file "transports" section, creating a transportsinstance list.
+For any yet-undiscovered driver, check for a loadable module and add it to
+those available. */


 readconf_driver_init((driver_instance **)&transports,     /* chain anchor */
-  (driver_info **)&transports_available_newlist,   /* available drivers */
-  sizeof(transport_info),                /* size of info block */
-  &transport_defaults,                   /* default values for generic options */
-  sizeof(transport_instance),            /* size of instance block */
-  optionlist_transports,                 /* generic options */
+  (driver_info **)&transports_available, /* available drivers */
+  sizeof(transport_info),        /* size of info block */
+  &transport_defaults,            /* default values for generic options */
+  sizeof(transport_instance),        /* size of instance block */
+  optionlist_transports,        /* generic options */
   optionlist_transports_size,
   US"transport");


diff --git a/src/src/transports/Makefile b/src/src/transports/Makefile
index 4eea141ec..8f759ecf0 100644
--- a/src/src/transports/Makefile
+++ b/src/src/transports/Makefile
@@ -1,8 +1,16 @@
# Make file for building a library containing all the available transports and
# calling it transports.a. This is called from the main make file, after cd'ing
# to the transports subdirectory.
+#
+# Copyright (c) The Exim Maintainers 2021 - 2024

-OBJ = appendfile.o autoreply.o lmtp.o pipe.o queuefile.o smtp.o smtp_socks.o tf_maildir.o
+# nb: at build time, the version of this file used will have had some
+#     extra variable definitions and prepended to it and module build rules
+#     interpolated below. This is done by scripts/drivers-Makefile.
+
+# MAGIC-TAG-MODS-OBJ-RULES-GO-HERE
+
+all:        transports.a $(MODS)


 transports.a:    $(OBJ)
          @$(RM_COMMAND) -f transports.a
@@ -10,18 +18,40 @@ transports.a:    $(OBJ)
          @$(AR) transports.a $(OBJ)
          $(RANLIB) $@


-.SUFFIXES:       .o .c
+.SUFFIXES:       .o .c .so
 .c.o:;           @echo "$(CC) $*.c"
          $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) $*.c


-appendfile.o:    $(HDRS) appendfile.c appendfile.h tf_maildir.h
-autoreply.o:     $(HDRS) autoreply.c autoreply.h
-lmtp.o:          $(HDRS) lmtp.c lmtp.h
-pipe.o:          $(HDRS) pipe.c pipe.h
-queuefile.o:     $(HDRS) queuefile.c queuefile.h
-smtp.o:          $(HDRS) smtp.c smtp.h
-smtp_socks.o:    $(HDRS) smtp_socks.c smtp.h
+.c.so:;          @echo "$(CC) -shared $*.c"
+         $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) $*.c -o $@
+
+
+$(OBJ) $(MOD): $(HDRS)
+
+autoreply.o autoreply.so:    autoreply.c autoreply.h
+lmtp.o lmtp.so:            lmtp.c lmtp.h
+pipe.o pipe.so:            pipe.c pipe.h
+queuefile.o queuefile.so:    queuefile.c queuefile.h
+
+
+# These ones depend on more than one .c source
+
+appendfile.o:    appendfile.c appendfile.h tf_maildir.c tf_maildir.h
+    @echo "$(CC) appendfile.c tf_maildir.c"
+    $(FE)$(CC) $(CFLAGS) $(INCLUDE) appendfile.c tf_maildir.c -r -o $@
+
+appendfile.so: appendfile.c appendfile.h tf_maildir.c tf_maildir.h
+    @echo "$(CC) -shared appendfile.c tf_maildir.c"
+    $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) \
+        appendfile.c tf_maildir.c -o $@
+
+smtp.o:    smtp.c smtp_socks.c smtp.h
+    @echo "$(CC) smtp.c smtp_socks.c"
+    $(FE)$(CC) $(CFLAGS) $(INCLUDE) smtp.c smtp_socks.c -r -o $@


-tf_maildir.o:    $(HDRS) tf_maildir.c tf_maildir.h appendfile.h
+smtp.so: smtp.c smtp_socks.c smtp.h
+    @echo "$(CC) -shared smtp.c smtp_socks.c"
+    $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) \
+        smtp.c smtp_socks.c -o $@


# End
diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c
index 14ef13c97..08a59543c 100644
--- a/src/src/transports/appendfile.c
+++ b/src/src/transports/appendfile.c
@@ -3319,6 +3319,31 @@ ret_panic:
return FALSE;
}

+
+
+
+# ifdef DYNLOOKUP
+#  define appendfile_transport_info _transport_info
+# endif
+
+transport_info appendfile_transport_info = {
+.drinfo = {
+  .driver_name =    US"appendfile",
+  .options =        appendfile_transport_options,
+  .options_count =    &appendfile_transport_options_count,
+  .options_block =    &appendfile_transport_option_defaults,    /* private options defaults */
+  .options_len =    sizeof(appendfile_transport_options_block),
+  .init =        appendfile_transport_init,
+# ifdef DYNLOOKUP
+  .dyn_magic =        TRANSPORT_MAGIC,
+# endif
+  },
+.code =        appendfile_transport_entry,
+.tidyup =    NULL,
+.closedown =    NULL,
+.local =    TRUE
+};
+
 #endif    /*!MACRO_PREDEF*/
 #endif    /*TRANSPORT_APPENDFILE*/
 /* End of transport/appendfile.c */
diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c
index a6080695e..9223bc791 100644
--- a/src/src/transports/autoreply.c
+++ b/src/src/transports/autoreply.c
@@ -806,6 +806,31 @@ DEBUG(D_transport) debug_printf("%s transport succeeded\n", trname);
 return FALSE;
 }


+
+
+
+# ifdef DYNLOOKUP
+#  define autoreply_transport_info _transport_info
+# endif
+
+transport_info autoreply_transport_info = {
+.drinfo = {
+  .driver_name =    US"autoreply",
+  .options =        autoreply_transport_options,
+  .options_count =    &autoreply_transport_options_count,
+  .options_block =    &autoreply_transport_option_defaults,
+  .options_len =    sizeof(autoreply_transport_options_block),
+  .init =        autoreply_transport_init,
+# ifdef DYNLOOKUP
+  .dyn_magic =        TRANSPORT_MAGIC,
+# endif
+  },
+.code =        autoreply_transport_entry,
+.tidyup =    NULL,
+.closedown =    NULL,
+.local =    TRUE
+};
+
 #endif    /*!MACRO_PREDEF*/
 #endif    /*TRANSPORT_AUTOREPOL*/
 /* End of transport/autoreply.c */
diff --git a/src/src/transports/lmtp.c b/src/src/transports/lmtp.c
index ae9295292..1bff274c1 100644
--- a/src/src/transports/lmtp.c
+++ b/src/src/transports/lmtp.c
@@ -808,6 +808,31 @@ MINUS_N:
   return FALSE;
 }


+
+
+
+# ifdef DYNLOOKUP
+#  define lmtp_transport_info _transport_info
+# endif
+
+transport_info lmtp_transport_info = {
+.drinfo = {
+  .driver_name =    US"lmtp",
+  .options =        lmtp_transport_options,
+  .options_count =    &lmtp_transport_options_count,
+  .options_block =    &lmtp_transport_option_defaults,
+  .options_len =    sizeof(lmtp_transport_options_block),
+  .init =        lmtp_transport_init,
+# ifdef DYNLOOKUP
+  .dyn_magic =        TRANSPORT_MAGIC,
+# endif
+  },
+.code =        lmtp_transport_entry,
+.tidyup =    NULL,
+.closedown =    NULL,
+.local =    TRUE
+};
+
 #endif    /*!MACRO_PREDEF*/
 #endif    /*TRANSPORT_LMTP*/
 /* End of transport/lmtp.c */
diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c
index 1b90c4314..b765eeae5 100644
--- a/src/src/transports/pipe.c
+++ b/src/src/transports/pipe.c
@@ -1128,6 +1128,31 @@ if (addr->transport_return != OK)
 return FALSE;
 }


+
+
+
+# ifdef DYNLOOKUP
+#  define pipe_transport_info _transport_info
+# endif
+
+transport_info pipe_transport_info = {
+.drinfo = {
+  .driver_name =    US"pipe",
+  .options =        pipe_transport_options,
+  .options_count =    &pipe_transport_options_count,
+  .options_block =    &pipe_transport_option_defaults,
+  .options_len =    sizeof(pipe_transport_options_block),
+  .init =        pipe_transport_init,
+# ifdef DYNLOOKUP
+  .dyn_magic =        TRANSPORT_MAGIC,
+# endif
+  },
+.code =        pipe_transport_entry,
+.tidyup =    NULL,
+.closedown =    NULL,
+.local =    TRUE
+};
+
 #endif    /*!MACRO_PREDEF*/
 #endif    /*TRASPORT_PIPE*/
 /* End of transport/pipe.c */
diff --git a/src/src/transports/queuefile.c b/src/src/transports/queuefile.c
index 2c35b3145..64031e55d 100644
--- a/src/src/transports/queuefile.c
+++ b/src/src/transports/queuefile.c
@@ -285,5 +285,30 @@ put in the first address of a batch. */
 return FALSE;
 }


+
+
+
+# ifdef DYNLOOKUP
+#  define queuefile_transport_info _transport_info
+# endif
+
+transport_info queuefile_transport_info = {
+.drinfo = {
+  .driver_name =    US"queuefile",
+  .options =        queuefile_transport_options,
+  .options_count =    &queuefile_transport_options_count,
+  .options_block =    &queuefile_transport_option_defaults,
+  .options_len =    sizeof(queuefile_transport_options_block),
+  .init =        queuefile_transport_init,
+# ifdef DYNLOOKUP
+  .dyn_magic =        TRANSPORT_MAGIC,
+# endif
+  },
+.code =        queuefile_transport_entry,
+.tidyup =    NULL,
+.closedown =    NULL,
+.local =    TRUE
+};
+
 #endif /*!MACRO_PREDEF*/
 #endif /*EXPERIMENTAL_QUEUEFILE*/
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index 25858d982..d25a2b1f6 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -6230,6 +6230,31 @@ DEBUG(D_transport) debug_printf("Leaving %s transport\n", trname);
 return TRUE;   /* Each address has its status */
 }


+
+
+
+# ifdef DYNLOOKUP
+#  define smtp_transport_info _transport_info
+# endif
+
+transport_info smtp_transport_info = {
+.drinfo = {
+  .driver_name =    US"smtp",
+  .options =        smtp_transport_options,
+  .options_count =    &smtp_transport_options_count,
+  .options_block =    &smtp_transport_option_defaults,
+  .options_len =    sizeof(smtp_transport_options_block),
+  .init =        smtp_transport_init,
+# ifdef DYNLOOKUP
+  .dyn_magic =        TRANSPORT_MAGIC,
+# endif
+  },
+.code =        smtp_transport_entry,
+.tidyup =    NULL,
+.closedown =    smtp_transport_closedown,
+.local =    FALSE
+};
+
 #endif    /*!MACRO_PREDEF*/
 /* vi: aw ai sw=2
 */
diff --git a/test/confs/0000 b/test/confs/0000
index 795701bd7..5db8ac8cf 100644
--- a/test/confs/0000
+++ b/test/confs/0000
@@ -11,5 +11,6 @@ tls_advertise_hosts =
 keep_environment =


begin routers
+begin transports

 # End
diff --git a/test/runtest b/test/runtest
index 292233551..632672324 100755
--- a/test/runtest
+++ b/test/runtest
@@ -1164,7 +1164,7 @@ RESET_AFTER_EXTRA_LINE_READ:
           | Lookups(?:\(built-in\))?:
           | Support\ for:
           | Routers\ \((?:built-in|dynamic)\):
-          | Transports:
+          | Transports\ \((?:built-in|dynamic)\):
           | Malware:
           | log\ selectors\ =
           | cwd=
@@ -3754,7 +3754,7 @@ while (<EXIMINFO>)
     print;
     @temp = split /(\s+)/, $1;
     push(@temp, ' ');
-    my %temp_routers= @temp;
+    my %temp_routers = @temp;
     @parm_routers{keys %temp_routers} = values %temp_routers;
     }


@@ -3762,13 +3762,15 @@ while (<EXIMINFO>)
# that the basic transport name is set, and then the name with each of the
# options.

-  elsif (/^Transports: (.*)/)
+  elsif (/^Transports \((?:built-in|dynamic)\): (.*)/)
     {
     print;
     @temp = split /(\s+)/, $1;
     my($i,$k);
     push(@temp, ' ');
-    %parm_transports = @temp;
+    my %temp_transports = @temp;
+    @parm_transports{keys %temp_transports} = values %temp_transports;
+
     foreach $k (keys %parm_transports)
       {
       if ($k =~ "/")


--
## subscription configuration (requires account):
## https://lists.exim.org/mailman3/postorius/lists/exim-cvs.lists.exim.org/
## unsubscribe (doesn't require an account):
## exim-cvs-unsubscribe@???
## Exim details at http://www.exim.org/
## Please use the Wiki with this list - http://wiki.exim.org/