Fix more VMS inclusions
[openssl.git] / Configurations / descrip.mms.tmpl
index 873d74f651d7a0d299856019f32673b886061484..85a3c778b7dc05cb590e9098e2eeb2195aa06028 100644 (file)
@@ -9,7 +9,7 @@
   (our $osslprefix_q = platform->osslprefix()) =~ s/\$/\\\$/;
 
   our $sover_dirname = platform->shlib_version_as_filename();
-  our $osslver = sprintf "%02d%02d", split(/\./, $config{version});
+  our $osslver = sprintf "%02d", split(/\./, $config{version});
 
   our $sourcedir = $config{sourcedir};
   our $builddir = $config{builddir};
       @{$unified_info{modules}};
   our @install_modules =
       grep { !$unified_info{attributes}->{modules}->{$_}->{noinst}
-             && !$unified_info{attributes}->{modules}->{$_}->{engine} }
+             && !$unified_info{attributes}->{modules}->{$_}->{engine}
+             && !$unified_info{attributes}->{modules}->{$_}->{fips} }
+      @{$unified_info{modules}};
+  our @install_fipsmodules =
+      grep { !$unified_info{attributes}->{modules}->{$_}->{noinst}
+             && $unified_info{attributes}->{modules}->{$_}->{fips} }
       @{$unified_info{modules}};
   our @install_programs =
       grep { !$unified_info{attributes}->{programs}->{$_}->{noinst} }
                 @cnf_defines,
                 'OPENSSLDIR="""$(OPENSSLDIR_C)"""',
                 'ENGINESDIR="""$(ENGINESDIR_C)"""',
-                'MODULESDIR="""$(MODULESDIR_C)"""',
-                #'$(DEFINES)'
+                'MODULESDIR="""$(MODULESDIR_C)"""'
                 )
+      . '$(DEFINES)'
       . "'extradefines'";
   our $lib_asflags =
       join(' ', $target{lib_asflags} || (), @{$config{lib_asflags}},
       join(',', @{$target{dso_defines}}, @{$target{module_defines}},
                 @{$config{dso_defines}}, @{$config{module_defines}},
                 @cnf_defines,
-                #'$(DEFINES)'
                 )
+      . '$(DEFINES)'
       . "'extradefines'";
   our $dso_asflags =
       join(' ', $target{dso_asflags} || (), $target{module_asflags} || (),
       join(',', @{$target{bin_defines}},
                 @{$config{bin_defines}},
                 @cnf_defines,
-                #'$(DEFINES)'
                 )
+      . '$(DEFINES)'
       . "'extradefines'";
   our $bin_asflags =
       join(' ', $target{bin_asflags} || (),
                @cnf_ldflags, '$(LDFLAGS)');
   our $bin_ex_libs = join('', @cnf_ex_libs, '$(EX_LIBS)');
 
-  # This is a horrible hack, but is needed because recursive inclusion of files
-  # in different directories does not work well with HP C.
-  my $sd = sourcedir("crypto", "async", "arch");
+  # These are horrible hacks, but are needed because recursive inclusion of
+  # files in different directories does not work well with VMS C.  We try to
+  # help by specifying extra relative directories.  They must always be in Unix
+  # format, relative to the directory where the .c file is located.  The logic
+  # is that any inclusion, merged with one of these relative directories, will
+  # find the requested inclusion file.
   foreach (grep /\[\.crypto\.async\.arch\].*\.o$/, keys %{$unified_info{sources}}) {
       my $obj = platform->obj($_);
-      $unified_info{before}->{$obj}
-          = qq(arch_include = F\$PARSE("$sd","A.;",,,"SYNTAX_ONLY") - "A.;"
-        define arch 'arch_include');
-      $unified_info{after}->{$obj}
-          = qq(deassign arch);
+      push @{$unified_info{includes_extra}->{$obj}}, qw(../);
+  }
+  foreach (grep /\[\.crypto\.ec\.curve448\].*?\.o$/, keys %{$unified_info{sources}}) {
+      my $obj = platform->obj($_);
+      push @{$unified_info{includes_extra}->{$obj}}, qw(./arch_32 ./arch64);
+  }
+  foreach (grep /\[\.crypto\.ec\.curve448.arch_(?:32|64)\].*?\.o$/, keys %{$unified_info{sources}}) {
+      my $obj = platform->obj($_);
+      push @{$unified_info{includes_extra}->{$obj}}, qw(../);
+  }
+  foreach (grep /\[\.ssl\].*?\.o$/, keys %{$unified_info{sources}}) {
+      my $obj = platform->obj($_);
+      # Most of the files in [.ssl.record.methods] include "ssl_local.h"
+      # which includes things like "record/record.h".  Adding "./" as an
+      # inclusion directory helps making this sort of header from these
+      # directories.
+      push @{$unified_info{includes_extra}->{$obj}}, qw(./);
+  }
+  foreach (grep /\[\.ssl\.(?:record|statem)\].*?\.o$/, keys %{$unified_info{sources}}) {
+      my $obj = platform->obj($_);
+      # Most of the files in [.ssl.record] and [.ssl.statem] include
+      # "../ssl_local.h", which includes things like "record/record.h".
+      # Adding "../" as an inclusion directory helps making this sort of header
+      # from these directories.
+      push @{$unified_info{includes_extra}->{$obj}}, qw(../);
+
   }
-  my $sd32 = sourcedir("crypto", "ec", "curve448", "arch_32");
-  my $sd64 = sourcedir("crypto", "ec", "curve448", "arch_64");
-  foreach (grep /\[\.crypto\.ec\.curve448.*?\].*?\.o$/, keys %{$unified_info{sources}}) {
+  foreach (grep /\[\.ssl\.record\.methods\].*?\.o$/, keys %{$unified_info{sources}}) {
       my $obj = platform->obj($_);
-      $unified_info{before}->{$obj}
-          = qq(arch_32_include = F\$PARSE("$sd32","A.;",,,"SYNTAX_ONLY") - "A.;"
-        define arch_32 'arch_32_include'
-        arch_64_include = F\$PARSE("$sd64","A.;",,,"SYNTAX_ONLY") - "A.;"
-        define arch_64 'arch_64_include');
-      $unified_info{after}->{$obj}
-          = qq(deassign arch_64
-        deassign arch_32);
+      # Most of the files in [.ssl.record.methods] include "../../ssl_local.h"
+      # which includes things like "record/record.h".  Adding "../../" as an
+      # inclusion directory helps making this sort of header from these
+      # directories.
+      push @{$unified_info{includes_extra}->{$obj}}, qw(../../);
   }
-  my $sd1 = sourcedir("ssl","record");
-  my $sd2 = sourcedir("ssl","statem");
-  my @ssl_locl_users = grep(/^\[\.(?:ssl\.(?:record|statem)|test)\].*\.o$/,
-                            keys %{$unified_info{sources}});
-  foreach (@ssl_locl_users) {
+  foreach (grep /\[\.test\].*?\.o$/, keys %{$unified_info{sources}}) {
       my $obj = platform->obj($_);
-      $unified_info{before}->{$obj}
-          = qq(record_include = F\$PARSE("$sd1","A.;",,,"SYNTAX_ONLY") - "A.;"
-        define record 'record_include'
-        statem_include = F\$PARSE("$sd2","A.;",,,"SYNTAX_ONLY") - "A.;"
-        define statem 'statem_include');
-      $unified_info{after}->{$obj}
-          = qq(deassign statem
-        deassign record);
+      push @{$unified_info{includes_extra}->{$obj}}, qw(../ssl ./helpers);
+      # Some of the sources in [.test] also include headers like
+      # "../ssl/record/methods/recmethod_local.h", which in turn might include
+      # "../../ssl_local.h", so these object files need yet another hack.
+      # We could make this specific to just the object files that are affected
+      # directly, but that would end up with more whack-a-mole of this sort, so
+      # nah, we do it broadly.
+      push @{$unified_info{includes_extra}->{$obj}}, qw(../ssl/record/methods);
+  }
+  foreach (grep /\[\.test\.helpers\].*?\.o$/, keys %{$unified_info{sources}}) {
+      my $obj = platform->obj($_);
+      push @{$unified_info{includes_extra}->{$obj}}, qw(../../ssl);
   }
 
   # This makes sure things get built in the order they need
@@ -266,6 +290,7 @@ VERBOSE=$(V)
 VERBOSE_FAILURE=$(VF)
 
 VERSION={- "$config{full_version}" -}
+VERSION_NUMBER={- "$config{version}" -}
 MAJOR={- $config{major} -}
 MINOR={- $config{minor} -}
 SHLIB_VERSION_NUMBER={- $config{shlib_version} -}
@@ -273,15 +298,23 @@ SHLIB_TARGET={- $target{shared_target} -}
 
 LIBS={- join(", ", map { "-\n\t".$_.".OLB" } @libs) -}
 SHLIBS={- join(", ", map { "-\n\t".$_.".EXE" } @shlibs) -}
-FIPSMODULENAME={- # We do some extra checking here, as there should be only one
-                  use File::Basename;
-                  my @fipsmodules =
-                      grep { !$unified_info{attributes}->{modules}->{$_}->{noinst}
-                             && $unified_info{attributes}->{modules}->{$_}->{fips} }
-                      @{$unified_info{modules}};
-                  die "More that one FIPS module" if scalar @fipsmodules > 1;
+MODULES={- join(", ", map { "-\n\t".$_.".EXE" }
+                      # Drop all modules that are dependencies, they will
+                      # be processed through their dependents
+                      grep { my $x = $_;
+                             !grep { grep { $_ eq $x } @$_ }
+                                   values %{$unified_info{depends}} }
+                      @{$unified_info{modules}}) -}
+FIPSMODULE={- # We do some extra checking here, as there should be only one
+              use File::Basename;
+              our @fipsmodules =
+                  grep { !$unified_info{attributes}->{modules}->{$_}->{noinst}
+                         && $unified_info{attributes}->{modules}->{$_}->{fips} }
+                  @{$unified_info{modules}};
+              die "More that one FIPS module" if scalar @fipsmodules > 1;
+              join(" ", map { platform->dso($_) } @fipsmodules) -}
+FIPSMODULENAME={- die "More that one FIPS module" if scalar @fipsmodules > 1;
                   join(", ", map { basename(platform->dso($_)) } @fipsmodules) -}
-MODULES={- join(", ", map { "-\n\t".$_.".EXE" } @{$unified_info{modules}}) -}
 PROGRAMS={- join(", ", map { "-\n\t".$_.".EXE" } @{$unified_info{programs}}) -}
 SCRIPTS={- join(", ", map { "-\n\t".$_ } @{$unified_info{scripts}}) -}
 {- output_off() if $disabled{makedepend}; "" -}
@@ -311,6 +344,8 @@ INSTALL_LIBS={- join(", ", map { "-\n\t".$_.".OLB" } @install_libs) -}
 INSTALL_SHLIBS={- join(", ", map { "-\n\t".$_.".EXE" } @install_shlibs) -}
 INSTALL_ENGINES={- join(", ", map { "-\n\t".$_.".EXE" } @install_engines) -}
 INSTALL_MODULES={- join(", ", map { "-\n\t".$_.".EXE" } @install_modules) -}
+INSTALL_FIPSMODULE={- join(", ", map { "-\n\t".$_.".EXE" } @install_fipsmodules) -}
+INSTALL_FIPSMODULECONF=[.providers]fipsmodule.cnf
 INSTALL_PROGRAMS={- join(", ", map { "-\n\t".$_.".EXE" } @install_programs) -}
 BIN_SCRIPTS={- join(", ", @install_bin_scripts) -}
 MISC_SCRIPTS={- join(", ", @install_misc_scripts) -}
@@ -344,7 +379,7 @@ OPENSSLDIR_C={- platform->osslprefix() -}DATAROOT:[000000]
 # Where installed ENGINE modules reside, for C
 ENGINESDIR_C={- platform->osslprefix() -}ENGINES{- $sover_dirname.$target{pointer_size} -}:
 # Where modules reside, for C
-MODULESDIR_C={- platform->osslprefix() -}MODULES{- $sover_dirname.$target{pointer_size} -}:
+MODULESDIR_C={- platform->osslprefix() -}MODULES{- $target{pointer_size} -}:
 
 ##### User defined commands and flags ################################
 
@@ -378,17 +413,10 @@ CPPFLAGS_Q={- (my $c = $lib_cppflags.$cppflags) =~ s|"|""|g;
               $x; -}
 
 # .FIRST and .LAST are special targets with MMS and MMK.
-# The defines in there are for C.  includes that look like
-# this:
-#
-#    #include <openssl/foo.h>
-#    #include "internal/bar.h"
-#
-# will use the logical names to find the files.  Expecting
-# DECompHP C to find files in subdirectories of whatever was
-# given with /INCLUDE is a fantasy, unfortunately.
 NODEBUG=@
 .FIRST :
+        {- join( "\n        \$(NODEBUG) ", @{ $target{setup_commands} // [] },
+                                           '!' ) -}
         $(NODEBUG) sourcetop = F$PARSE("$(SRCDIR)","[]A.;",,,"SYNTAX_ONLY,NO_CONCEAL") - ".][000000" - "[000000." - "][" - "]A.;" + ".]"
         $(NODEBUG) DEFINE ossl_sourceroot 'sourcetop'
         $(NODEBUG) !
@@ -424,7 +452,9 @@ NODEBUG=@
         $(NODEBUG) ! them, so we create it instead.  This is an unfortunate
         $(NODEBUG) ! necessity.
         $(NODEBUG) !
-        $(NODEBUG) DEFINE openssl "{- sourcedir('include/openssl') -}
+        $(NODEBUG) openssl_inc1 = F$PARSE("[.include.openssl]","A.;",,,"syntax_only") - "A.;"
+        $(NODEBUG) openssl_inc2 = F$PARSE("sourcetop:[include.openssl]","A.;",,,"SYNTAX_ONLY") - "A.;"
+        $(NODEBUG) DEFINE openssl 'openssl_inc1','openssl_inc2'
         $(NODEBUG) !
         $(NODEBUG) ! Figure out the architecture
         $(NODEBUG) !
@@ -437,15 +467,16 @@ NODEBUG=@
 
 .LAST :
         $(NODEBUG) {- join("\n\t\$(NODEBUG) ", map { "DEASSIGN ".uc($_) } @shlibs) || "!" -}
+        $(NODEBUG) DEASSIGN openssl
         $(NODEBUG) DEASSIGN ossl_dataroot
         $(NODEBUG) DEASSIGN ossl_installroot
-        $(NODEBUG) DEASSIGN openssl
+        $(NODEBUG) DEASSIGN ossl_sourceroot
 .DEFAULT :
         @ ! MMS cannot handle no actions...
 
 # The main targets ###################################################
 
-{- dependmagic('build_sw'); -} : build_libs_nodep, build_modules_nodep, build_programs_nodep copy-utils
+{- dependmagic('build_sw'); -} : build_libs_nodep, build_modules_nodep, build_programs_nodep
 {- dependmagic('build_libs'); -} : build_libs_nodep
 {- dependmagic('build_modules'); -} : build_modules_nodep
 {- dependmagic('build_programs'); -} : build_programs_nodep
@@ -474,7 +505,7 @@ build_all_generated : $(GENERATED_MANDATORY) $(GENERATED) build_docs
 all : build_sw build_docs
 
 test : tests
-{- dependmagic('tests'); -} : build_programs_nodep, build_modules_nodep copy-utils run_tests
+{- dependmagic('tests'); -} : build_programs_nodep, build_modules_nodep run_tests
 run_tests :
         @ ! {- output_off() if $disabled{tests}; "" -}
         DEFINE SRCTOP "$(SRCDIR)"
@@ -498,7 +529,7 @@ list-tests :
         @ WRITE SYS$OUTPUT "Tests are not supported with your chosen Configure options"
         @ ! {- output_on() if !$disabled{tests}; "" -}
 
-install : install_sw install_ssldirs install_docs install_msg
+install : install_sw install_ssldirs install_docs {- $disabled{fips} ? "" : "install_fips" -} install_msg
 
 install_msg :
         @ WRITE SYS$OUTPUT ""
@@ -514,7 +545,7 @@ install_msg :
 check_install :
         spawn/nolog @ossl_installroot:[SYSTEST]openssl_ivp{- $osslver -}.com
 
-uninstall : uninstall_docs uninstall_sw
+uninstall : uninstall_docs uninstall_sw {- $disabled{fips} ? "" : "uninstall_fips" -}
 
 # Because VMS wants the generation number (or *) to delete files, we can't
 # use $(LIBS), $(PROGRAMS), $(GENERATED) and $(MODULES) directly.
@@ -541,11 +572,11 @@ clean : libclean
         - DELETE []vmsconfig.pm;*
 
 distclean : clean
+        - DELETE [.include.openssl]configuration.h;*
         - DELETE configdata.pm;*
         - DELETE descrip.mms;*
 
 depend : descrip.mms
-descrip.mms : FORCE
        @ ! {- output_off() if $disabled{makedepend}; "" -}
        @ $(PERL) {- sourcefile("util", "add-depends.pl") -} "{- $config{makedep_scheme} -}"
        @ ! {- output_on() if $disabled{makedepend}; "" -}
@@ -562,17 +593,22 @@ install_docs : install_html_docs
 
 uninstall_docs : uninstall_html_docs
 
-install_fips : install_sw
+{- output_off() if $disabled{fips}; "" -}
+install_fips : build_sw $(INSTALL_FIPSMODULECONF)
+       @ WRITE SYS$OUTPUT "*** Installing FIPS module"
+       - CREATE/DIR ossl_installroot:[MODULES{- $target{pointer_size} -}.'arch']
+       - CREATE/DIR/PROT=(S:RWED,O:RWE,G:RE,W:RE) OSSL_DATAROOT:[000000]
+       COPY/PROT=W:RE $(INSTALL_FIPSMODULES) -
+                ossl_installroot:[MODULES{- $target{pointer_size} -}.'arch']$(FIPSMODULENAME)
        @ WRITE SYS$OUTPUT "*** Installing FIPS module configuration"
-       @ WRITE SYS$OUTPUT "fipsinstall $(DESTDIR)$(MODULESDIR)/$(FIPSMODULENAME).cnf"
-       openssl fipsinstall -
-               -module ossl_installroot:[MODULES{- $sover_dirname.$target{pointer_size} -}.'arch']$(FIPSMODULENAME) -
-               -out ossl_installroot:[MODULES{- $sover_dirname.$target{pointer_size} -}.'arch']$(FIPSMODULENAME).cnf -
-               -macopt "hexkey:$(FIPSKEY)"
+       COPY/PROT=W:RE $(INSTALL_FIPSMODULECONF) OSSL_DATAROOT:[000000]
 
-uninstall_fips : uninstall_sw
+uninstall_fips :
        @ WRITE SYS$OUTPUT "*** Uninstalling FIPS module configuration"
-       DELETE ossl_installroot:[MODULES{- $sover_dirname.$target{pointer_size} -}.'arch']$(FIPSMODULENAME).cnf;*
+       DELETE OSSL_DATAROOT:[000000]fipsmodule.cnf;*
+       @ WRITE SYS$OUTPUT "*** Uninstalling FIPS module"
+       DELETE ossl_installroot:[MODULES{- $target{pointer_size} -}.'arch']$(FIPSMODULENAME);*
+{- output_on() if $disabled{fips}; "" -}
 
 install_ssldirs : check_INSTALLTOP
         - CREATE/DIR/PROT=(S:RWED,O:RWE,G:RE,W:RE) OSSL_DATAROOT:[000000]
@@ -600,7 +636,9 @@ install_dev : check_INSTALLTOP install_runtime_libs
         @ WRITE SYS$OUTPUT "*** Installing development files"
         @ ! Install header files
         - CREATE/DIR ossl_installroot:[include.openssl]
-        COPY/PROT=W:R openssl:*.h ossl_installroot:[include.openssl]
+        COPY/PROT=W:R ossl_sourceroot:[include.openssl]*.h -
+                ossl_installroot:[include.openssl]
+        COPY/PROT=W:R [.include.openssl]*.h ossl_installroot:[include.openssl]
         @ ! Install static (development) libraries
         - CREATE/DIR ossl_installroot:[LIB.'arch']
         {- join("\n        ",
@@ -619,9 +657,9 @@ install_engines : check_INSTALLTOP install_runtime_libs build_modules
 install_modules : check_INSTALLTOP install_runtime_libs build_modules
         @ {- output_off() unless scalar @install_modules; "" -} !
         @ WRITE SYS$OUTPUT "*** Installing modules"
-        - CREATE/DIR ossl_installroot:[MODULES{- $sover_dirname.$target{pointer_size} -}.'arch']
+        - CREATE/DIR ossl_installroot:[MODULES{- $target{pointer_size} -}.'arch']
         {- join("\n        ",
-                map { "COPY/PROT=W:RE $_.EXE ossl_installroot:[MODULES$sover_dirname$target{pointer_size}.'arch']" }
+                map { "COPY/PROT=W:RE $_.EXE ossl_installroot:[MODULES$target{pointer_size}.'arch']" }
                 @install_modules) -}
         @ {- output_on() unless scalar @install_modules; "" -} !
 
@@ -733,16 +771,6 @@ check_INSTALLTOP :
         @ IF "$(INSTALLTOP)" .EQS. "" THEN -
                 EXIT %x10000002
 
-# Helper targets #####################################################
-
-copy-utils : [.util]wrap.pl
-
-[.util]wrap.pl : configdata.pm
-       @ IF "$(SRCDIR)" .NES. "$(BLDDIR)" THEN -
-               CREATE/DIR/LOG [.util]
-       @ IF "$(SRCDIR)" .NES. "$(BLDDIR)" THEN -
-               COPY/LOG ossl_sourceroot:[util]wrap.pl [.util]
-
 # Developer targets ##################################################
 
 debug_logicals :
@@ -750,7 +778,16 @@ debug_logicals :
 
 # Building targets ###################################################
 
-configdata.pm : $(SRCDIR)Configure $(SRCDIR)config.com {- join(" ", @{$config{build_file_templates}}, @{$config{build_infos}}, @{$config{conf_files}}) -}
+descrip.mms : configdata.pm {- join(" ", @{$config{build_file_templates}}) -}
+       perl configdata.pm
+        @ WRITE SYS$OUTPUT "*************************************************"
+        @ WRITE SYS$OUTPUT "***                                           ***"
+        @ WRITE SYS$OUTPUT "***   Please run the same mms command again   ***"
+        @ WRITE SYS$OUTPUT "***                                           ***"
+        @ WRITE SYS$OUTPUT "*************************************************"
+        @ PIPE ( EXIT %X10000000 )
+
+configdata.pm : $(SRCDIR)Configure $(SRCDIR)config.com {- join(" ", @{$config{build_infos}}, @{$config{conf_files}}) -}
         perl configdata.pm -r
         @ WRITE SYS$OUTPUT "*************************************************"
         @ WRITE SYS$OUTPUT "***                                           ***"
@@ -767,6 +804,17 @@ reconfigure reconf :
   use File::Spec::Functions qw/abs2rel rel2abs catfile catdir/;
   use File::Spec::Unix;
 
+  # Helper function to convert dependencies in platform agnostic form to
+  # dependencies in platform form.
+  sub compute_platform_depends {
+      map { my $x = $_;
+
+            grep { $x eq $_ } @{$unified_info{programs}} and platform->bin($x)
+            or grep { $x eq $_ } @{$unified_info{modules}} and platform->dso($x)
+            or grep { $x eq $_ } @{$unified_info{libraries}} and platform->lib($x)
+            or platform->convertext($x); } @_;
+  }
+
   # Helper function to figure out dependencies on libraries
   # It takes a list of library names and outputs a list of dependencies
   sub compute_lib_depends {
@@ -855,9 +903,62 @@ EOF
       return ($filename, $scripture);
   }
 
+  # On VMS, (some) header file directories include the files
+  # __DECC_INCLUDE_EPILOGUE.H and __DECC_INCLUDE_PROLOGUE.H.
+  # When header files are generated, and the build directory
+  # isn't the same as the source directory, these files must
+  # be copied alongside the generated header file, or their
+  # effect will be lost.
+  # We use the same include file cache as make_includefile
+  # to check if the scripture to copy these files has already
+  # been generated.
+  sub make_decc_include_files {
+      my $outd = shift;
+      my $ind = shift;
+
+      # If the build directory and the source directory are the
+      # same, there's no need to copy the prologue and epilogue
+      # files.
+      return ('') if $outd eq $ind;
+
+      my $outprologue = catfile($outd, '__DECC_INCLUDE_PROLOGUE.H');
+      my $outepilogue = catfile($outd, '__DECC_INCLUDE_EPILOGUE.H');
+      my $inprologue = catfile($ind, '__DECC_INCLUDE_PROLOGUE.H');
+      my $inepilogue = catfile($ind, '__DECC_INCLUDE_EPILOGUE.H');
+      my @filenames = ();
+      my $scripture = '';
+
+      if ($includefile_cache{$outprologue}) {
+          push @filenames, $outprologue;
+      } elsif (-f $inprologue) {
+          my $local_scripture .= <<"EOF";
+$outprologue : $inprologue
+       COPY $inprologue $outprologue
+EOF
+          $includefile_cache{$outprologue} = $local_scripture;
+
+          push @filenames, $outprologue;
+          $scripture .= $local_scripture;
+      }
+      if ($includefile_cache{$outepilogue}) {
+          push @filenames, $outepilogue;
+      } elsif (-f $inepilogue) {
+          my $local_scripture .= <<"EOF";
+$outepilogue : $inepilogue
+       COPY $inepilogue $outepilogue
+EOF
+          $includefile_cache{$outepilogue} = $local_scripture;
+
+          push @filenames, $outepilogue;
+          $scripture .= $local_scripture;
+      }
+
+      return (@filenames, $scripture);
+  }
+
   sub generatetarget {
       my %args = @_;
-      my $deps = join(" ", @{$args{deps}});
+      my $deps = join(" ", compute_platform_depends(@{$args{deps}}));
       return <<"EOF";
 $args{target} : $deps
 EOF
@@ -869,7 +970,9 @@ EOF
       my $gen_args = join('', map { " $_" }
                               @{$args{generator}}[1..$#{$args{generator}}]);
       my $gen_incs = join("", map { ' "-I'.$_.'"' } @{$args{generator_incs}});
-      my $deps = join(", -\n\t\t", @{$args{generator_deps}}, @{$args{deps}});
+      my $deps = join(", -\n\t\t",
+                      compute_platform_depends(@{$args{generator_deps}},
+                                               @{$args{deps}}));
 
       if ($args{src} =~ /\.html$/) {
           #
@@ -878,9 +981,10 @@ EOF
           my $title = basename($args{src}, ".html");
           my $pod = $gen0;
           my $mkpod2html = sourcefile('util', 'mkpod2html.pl');
+          my $srcdoc = sourcedir('doc');
           return <<"EOF";
 $args{src} : $pod
-       \$(PERL) $mkpod2html -i $pod -o \$\@ -t "$title" -r "\$(SRCDIR)/doc"
+       \$(PERL) $mkpod2html -i $pod -o \$\@ -t "$title" -r "$srcdoc"
 EOF
       } elsif ($args{src} =~ /\.(\d)$/) {
           #
@@ -893,7 +997,7 @@ EOF
           #
           my $target = platform->def($args{src});
           my $mkdef = sourcefile('util', 'mkdef.pl');
-          my $ord_ver = $args{intent} eq 'lib' ? ' --version $(VERSION)' : '';
+          my $ord_ver = $args{intent} eq 'lib' ? ' --version $(VERSION_NUMBER)' : '';
           my $ord_name =
               $args{generator}->[1] || basename($args{product}, '.EXE');
           my $case_insensitive =
@@ -901,9 +1005,10 @@ EOF
               ? '' : ' --case-insensitive';
           return <<"EOF";
 $target : $gen0 $deps $mkdef
-       \$(PERL) $mkdef$ord_ver --ordinals $gen0 --name $ord_name "--OS" "VMS"$case_insensitive > $target
+       \$(PERL) $mkdef$ord_ver --type $args{intent} --ordinals $gen0 --name $ord_name "--OS" "VMS"$case_insensitive > $target
 EOF
-      } elsif (platform->isasm($args{src})) {
+      } elsif (platform->isasm($args{src})
+               || platform->iscppasm($args{src})) {
           #
           # Assembler generator
           #
@@ -913,7 +1018,9 @@ EOF
                 dso => "$dso_cflags $dso_cppflags",
                 bin => "$bin_cflags $bin_cppflags" } -> {$args{intent}};
           my $defs = join("", map { ",".$_ } @{$args{defs}});
-          my $target = platform->asm($args{src});
+          my $target = platform->isasm($args{src})
+                       ? platform->asm($args{src})
+                       : $args{src};
 
           my $generator;
           if ($gen0 =~ /\.pl$/) {
@@ -926,21 +1033,6 @@ EOF
           }
 
           if (defined($generator)) {
-              # If the target is named foo.S in build.info, we want to
-              # end up generating foo.s in two steps.
-              if ($args{src} =~ /\.S$/) {
-                   return <<"EOF";
-$target : $gen0 $deps
-       $generator \$\@-S
-        \@ extradefines = "$defs"
-       PIPE \$(CPP) $cppflags \$\@-S | -
-             \$(PERL) -ne "/^#(\\s*line)?\\s*[0-9]+\\s+""/ or print" > \$\@-i
-        \@ DELETE/SYMBOL/LOCAL extradefines
-        RENAME \$\@-i \$\@
-        DELETE \$\@-S;
-EOF
-              }
-              # Otherwise....
               return <<"EOF";
 $target : $gen0 $deps
         \@ extradefines = "$defs"
@@ -962,42 +1054,32 @@ EOF
           my $dofile = abs2rel(rel2abs(catfile($config{sourcedir},
                                                "util", "dofile.pl")),
                                rel2abs($config{builddir}));
-          my @modules = ( 'configdata.pm',
-                          grep { $_ =~ m|\.pm$| } @{$args{deps}} );
-          my %moduleincs = map { '"-I'.dirname($_).'"' => 1 } @modules;
-          $deps = join(' ', $deps, @modules);
-          @modules = map { '"-M'.basename($_, '.pm').'"' } @modules;
-          my $modules = join(' ', '', sort keys %moduleincs, @modules);
+          my @perlmodules = ( 'configdata.pm',
+                              grep { $_ =~ m|\.pm$| } @{$args{deps}} );
+          my %perlmoduleincs = map { '"-I'.dirname($_).'"' => 1 } @perlmodules;
+          my @decc_include_data
+              = make_decc_include_files(dirname($args{src}), dirname($gen0));
+          my $decc_include_scripture = pop @decc_include_data;
+          $deps = join(' ', $deps, @decc_include_data,
+                            compute_platform_depends(@perlmodules));
+          @perlmodules = map { '"-M'.basename($_, '.pm').'"' } @perlmodules;
+          my $perlmodules = join(' ', '', sort keys %perlmoduleincs, @perlmodules);
+
           return <<"EOF";
 $args{src} : $gen0 $deps
-       \$(PERL)$modules $dofile "-o$target{build_file}" $gen0$gen_args > \$\@
+       \$(PERL)$perlmodules $dofile "-o$target{build_file}" $gen0$gen_args > \$\@
+$decc_include_scripture
 EOF
       } elsif (grep { $_ eq $gen0 } @{$unified_info{programs}}) {
           #
           # Generic generator using OpenSSL programs
           #
 
-          # Redo $deps, because programs aren't expected to have deps of their
-          # own.  This is a little more tricky, though, because running programs
-          # may have dependencies on all sorts of files, so we search through
-          # our database of programs and modules to see if our dependencies
-          # are one of those.
-          $deps = join(' ', map { my $x = $_;
-                                  if (grep { $x eq $_ }
-                                          @{$unified_info{programs}}) {
-                                      platform->bin($x);
-                                  } elsif (grep { $x eq $_ }
-                                          @{$unified_info{modules}}) {
-                                      platform->dso($x);
-                                  } else {
-                                      $x;
-                                  }
-                                } @{$args{deps}});
-          # Also redo $gen0, to ensure that we have the proper extension
+          # Redo $gen0, to ensure that we have the proper extension
           $gen0 = platform->bin($gen0);
           return <<"EOF";
 $args{src} : $gen0 $deps
-       PIPE $gen0$gen_args > \$@
+       PIPE MCR $gen0$gen_args > \$@
 EOF
       } else {
           #
@@ -1036,8 +1118,9 @@ EOF
       my $depn = basename($dep);
       my $srcs =
           join(", ", map { abs2rel(rel2abs($_), rel2abs($forward)) } @srcs);
-      my $before = $unified_info{before}->{$obj} || "\@ !";
-      my $after = $unified_info{after}->{$obj} || "\@ !";
+      my $incextra = join(',', map { "\"$_\"" }
+                               @{$unified_info{includes_extra}->{$obj}});
+      $incextra = "/INCLUDE=($incextra)" if $incextra;
 
       my $cflags;
       if ($args{attrs}->{noinst}) {
@@ -1055,6 +1138,7 @@ EOF
                   lib => $lib_cppflags,
                   dso => $dso_cppflags,
                   bin => $bin_cppflags } -> {$args{intent}};
+      $cflags .= $incextra;
       my $defs = join("", map { ",".$_ } @{$args{defs}});
       my $asflags = { shlib => $lib_asflags,
                      lib => $lib_asflags,
@@ -1064,17 +1148,14 @@ EOF
       if ($srcs[0] =~ /\Q${asmext}\E$/) {
           return <<"EOF";
 $obj : $deps
-        ${before}
         SET DEFAULT $forward
         \$(AS) $asflags \$(ASOUTFLAG)${objd}${objn} $srcs
         SET DEFAULT $backward
-        ${after}
         - PURGE $obj
 EOF
       } elsif ($srcs[0] =~ /.S$/) {
          return <<"EOF";
 $obj : $deps
-        ${before}
         SET DEFAULT $forward
         \@ $incs_on
         \@ extradefines = "$defs"
@@ -1084,7 +1165,6 @@ $obj : $deps
         \@ DELETE/SYMBOL/LOCAL extradefines
         \@ $incs_off
         SET DEFAULT $backward
-        ${after}
         \$(AS) $asflags \$(ASOUTFLAG)$obj $obj-asm
         - PURGE $obj
 EOF
@@ -1107,7 +1187,6 @@ EOF
 
       return <<"EOF";
 $obj : $deps
-        ${before}
         SET DEFAULT $forward
         \@ $incs_on
         \@ extradefines = "$defs"
@@ -1115,7 +1194,6 @@ $obj : $deps
         \@ DELETE/SYMBOL/LOCAL extradefines
         \@ $incs_off
         SET DEFAULT $backward
-        ${after}
         - PURGE $obj
 $incdir_scripture
 EOF
@@ -1187,16 +1265,28 @@ EOF
       # previous line's file spec as default, so if no directory spec
       # is present in the current line and the previous line has one that
       # doesn't apply, you're in for a surprise.
+      # Furthermore, we collect all object files and static libraries in
+      # an explicit cluster, to make it clear to the linker that these files
+      # shall be processed before shareable images.
+      # The shareable images are used with /SELECTIVE, to avoid warnings of
+      # multiply defined symbols when the module object files override some
+      # symbols that are present in the shareable image.
       my $write_opt1 =
-          join(",-\"\n\t", map { my $x = $_ =~ /\[/ ? $_ : "[]".$_;
-                                 "WRITE OPT_FILE \"$x" } @objs).
-          "\"";
+          join(",-\"\n\t",
+               "\@ WRITE OPT_FILE \"CLUSTER=_,,",
+               (map { my $x = $_ =~ /\[/ ? $_ : "[]".$_;
+                      "\@ WRITE OPT_FILE \"$x" } @objs),
+               (map { my $x = ($_->{lib} =~ /\[/) ? $_->{lib} : "[]".$_->{lib};
+                      "\@ WRITE OPT_FILE \"$x/LIB" }
+                grep { $_->{lib} =~ m|\.OLB$| }
+                @deps))
+          ."\"";
       my $write_opt2 =
-          join("\n\t", map { my $x = $_->{lib} =~ /\[/
-                                 ? $_->{lib} : "[]".$_->{lib};
-                             $x =~ s|(\.EXE)|$1/SHARE|;
-                             $x =~ s|(\.OLB)|$1/LIB|;
-                             "WRITE OPT_FILE \"$x\"" } @deps)
+          join("\n\t",
+               (map { my $x = ($_->{lib} =~ /\[/) ? $_->{lib} : "[]".$_->{lib};
+                      "\@ WRITE OPT_FILE \"$x/SHARE/SELECTIVE\"" }
+                grep { $_->{lib} =~ m|\.EXE$| }
+                @deps))
           || "\@ !";
       return <<"EOF"
 $dso : $deps
@@ -1251,30 +1341,30 @@ EOF
       # is present in the current line and the previous line has one that
       # doesn't apply, you're in for a surprise.
       my $write_opt1 =
-          join(",-\"\n\t", map { my $x = $_ =~ /\[/ ? $_ : "[]".$_;
-                                 "\@ WRITE OPT_FILE \"$x" } @objs).
-          "\"";
+          "\@ WRITE OPT_FILE \"CASE_SENSITIVE=YES\"\n\t"
+          .join(",-\"\n\t",
+                "\@ WRITE OPT_FILE \"CLUSTER=_,,",
+                (map { my $x = $_ =~ /\[/ ? $_ : "[]".$_;
+                       "\@ WRITE OPT_FILE \"$x" } @objs),
+                (map { my $x = ($_->{lib} =~ /\[/) ? $_->{lib} : "[]".$_->{lib};
+                       # Special hack to include the MAIN object module
+                       # explicitly, if it's known that there is one.
+                       # |incmain| is defined in the rule generation further
+                       # down, with the necessary /INCLUDE=main option unless
+                       # the program has been determined to have a main function
+                       # already.
+                       $_->{attrs}->{has_main}
+                       ? "\@ WRITE OPT_FILE \"$x/LIB''incmain'"
+                       : "\@ WRITE OPT_FILE \"$x/LIB" }
+                 grep { $_->{lib} =~ m|\.OLB$| }
+                 @deps))
+          ."\"";
       my $write_opt2 =
-          join("\n\t", "WRITE OPT_FILE \"CASE_SENSITIVE=YES\"",
-                       map { my @lines = ();
-                             use Data::Dumper;
-                             my $x = $_->{lib} =~ /\[/
-                                 ? $_->{lib} : "[]".$_->{lib};
-                             if ($x =~ m|\.EXE$|) {
-                                 push @lines, "\@ WRITE OPT_FILE \"$x/SHARE\"";
-                             } elsif ($x =~ m|\.OLB$|) {
-                                 # Special hack to include the MAIN object
-                                 # module explicitly.  This will only be done
-                                 # if there isn't a 'main' in the program's
-                                 # object modules already.
-                                 my $main = $_->{attrs}->{has_main}
-                                     ? '/INCLUDE=main' : '';
-                                 push @lines,
-                                     "\@ IF nomain THEN WRITE OPT_FILE \"$x/LIB$main\"",
-                                     "\@ IF .NOT. nomain THEN WRITE OPT_FILE \"$x/LIB\""
-                             }
-                             @lines
-                           } @deps)
+          join("\n\t",
+               (map { my $x = $_->{lib} =~ /\[/ ? $_->{lib} : "[]".$_->{lib};
+                      "\@ WRITE OPT_FILE \"$x/SHARE/SELECTIVE\"" }
+                grep { $_->{lib} =~ m|\.EXE$| }
+                @deps))
           || "\@ !";
       # The linking commands looks a bit complex, but it's for good reason.
       # When you link, say, foo.obj, bar.obj and libsomething.exe/share, and
@@ -1297,6 +1387,8 @@ EOF
       return <<"EOF"
 $bin : $deps
         $analyse_objs
+        @ incmain = "/INCLUDE=main"
+        @ IF .NOT. nomain THEN incmain = ""
         @ OPEN/WRITE/SHARE=READ OPT_FILE $binname.OPT
         $write_opt1
         $write_opt2
@@ -1337,7 +1429,7 @@ EOF
                                            "util", "dofile.pl")),
                            rel2abs($config{builddir}));
       return <<"EOF";
-$script : $sources
+$script : $sources configdata.pm
         \$(PERL) "-I\$(BLDDIR)" "-Mconfigdata" $dofile -
            "-o$target{build_file}" $sources > $script
         SET FILE/PROT=(S:RWED,O:RWED,G:RE,W:RE) $script