Configure: Name object files according to the product they are part of
authorRichard Levitte <levitte@openssl.org>
Mon, 10 Sep 2018 00:21:40 +0000 (02:21 +0200)
committerRichard Levitte <levitte@openssl.org>
Tue, 11 Sep 2018 23:59:45 +0000 (01:59 +0200)
This will allow to have different object files for different products,
even if they share the same source code, and possibly different builds
for those different object files.

For example, one can have something like this:

    SOURCES[libfoo]=cookie.c
    INCLUDES[libfoo]=include/foo
    SOURCES[libbar]=cookie.c
    INCLUDES[libbar]=include/bar

This would mean that the object files and libraries would be build
somewhat like this:

    $(CC) -Iinclude/foo -o libfoo-lib-cookie.o cookie.c
    $(AR) $(ARFLAGS) libfoo.a libfoo-lib-cookie.o
    $(CC) -Iinclude/bar -o libbar-lib-cookie.o cookie.c
    $(AR) $(ARFLAGS) libbar.a libbar-lib-cookie.o

Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/7159)

CHANGES
Configurations/common.tmpl
Configure

diff --git a/CHANGES b/CHANGES
index 657f0cf..fab0af4 100644 (file)
--- a/CHANGES
+++ b/CHANGES
      http://web.cs.ucdavis.edu/%7Erogaway/papers/offsets.pdf
      [Paul Dale]
 
+  *) Rename the object files, i.e. give them other names than in previous
+     versions.  Their names now include the name of the final product, as
+     well as its type mnemonic (bin, lib, shlib).
+     [Richard Levitte]
+
  Changes between 1.1.0i and 1.1.1 [11 Sep 2018]
 
   *) Add a new ClientHello callback. Provides a callback interface that gives
index ad67591..246f18a 100644 (file)
      unless ($disabled{shared} || $lib =~ /\.a$/) {
          $OUT .= libobj2shlib(shlib => $unified_info{sharednames}->{$lib},
                               lib => $lib,
-                              objs => [ @{$unified_info{shared_sources}->{$lib}},
-                                        @{$unified_info{sources}->{$lib}} ],
+                              objs => $unified_info{shared_sources}->{$lib},
                               deps => [ reducedepends(resolvedepends($lib)) ],
                               installed => is_installed($lib));
          foreach ((@{$unified_info{shared_sources}->{$lib}},
      my $lib = shift;
      return "" if $cache{$lib};
      $OUT .= obj2dso(lib => $lib,
-                     objs => [ @{$unified_info{sources}->{$lib}},
-                               @{$unified_info{shared_sources}->{$lib}} ],
+                     objs => $unified_info{shared_sources}->{$lib},
                      deps => [ resolvedepends($lib) ],
                      installed => is_installed($lib));
-     foreach ((@{$unified_info{sources}->{$lib}},
-               @{$unified_info{shared_sources}->{$lib}})) {
+     foreach (@{$unified_info{shared_sources}->{$lib}}) {
          doobj($_, $lib, intent => "dso", installed => is_installed($lib));
      }
      $cache{$lib} = 1;
index f9eda66..a1db916 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -2029,15 +2029,15 @@ EOF
                     $o =~ s/\.[csS]$/.o/; # C and assembler
                     $o =~ s/\.(cc|cpp)$/_cc.o/; # C++
                     $o = cleanfile($buildd, $o, $blddir);
-                    $unified_info{sources}->{$ddest}->{$o} = 1;
-                    $unified_info{sources}->{$o}->{$s} = 1;
+                    $unified_info{sources}->{$ddest}->{$o} = -1;
+                    $unified_info{sources}->{$o}->{$s} = -1;
                 } elsif ($s =~ /\.rc$/) {
                     # We also recognise resource files
                     my $o = $_;
                     $o =~ s/\.rc$/.res/; # Resource configuration
                     my $o = cleanfile($buildd, $o, $blddir);
-                    $unified_info{sources}->{$ddest}->{$o} = 1;
-                    $unified_info{sources}->{$o}->{$s} = 1;
+                    $unified_info{sources}->{$ddest}->{$o} = -1;
+                    $unified_info{sources}->{$o}->{$s} = -1;
                 } else {
                     $unified_info{sources}->{$ddest}->{$s} = 1;
                 }
@@ -2065,15 +2065,15 @@ EOF
                     $o =~ s/\.[csS]$/.o/; # C and assembler
                     $o =~ s/\.(cc|cpp)$/_cc.o/; # C++
                     $o = cleanfile($buildd, $o, $blddir);
-                    $unified_info{shared_sources}->{$ddest}->{$o} = 1;
-                    $unified_info{sources}->{$o}->{$s} = 1;
+                    $unified_info{shared_sources}->{$ddest}->{$o} = -1;
+                    $unified_info{sources}->{$o}->{$s} = -1;
                 } elsif ($s =~ /\.rc$/) {
                     # We also recognise resource files
                     my $o = $_;
                     $o =~ s/\.rc$/.res/; # Resource configuration
                     my $o = cleanfile($buildd, $o, $blddir);
-                    $unified_info{shared_sources}->{$ddest}->{$o} = 1;
-                    $unified_info{sources}->{$o}->{$s} = 1;
+                    $unified_info{shared_sources}->{$ddest}->{$o} = -1;
+                    $unified_info{sources}->{$o}->{$s} = -1;
                 } elsif ($s =~ /\.(def|map|opt)$/) {
                     # We also recognise .def / .map / .opt files
                     # We know they are generated files
@@ -2189,6 +2189,101 @@ EOF
         }
     }
 
+    # Go through all object files and change their names to something that
+    # reflects what they will be built for.  Note that for some source files,
+    # this leads to duplicate object files because they are used multiple times.
+    # the goal is to rename all object files according to this scheme:
+    #    {productname}-{midfix}-{origobjname}.[o|res]
+    # the {midfix} is a keyword indicating the type of product, which is mostly
+    # valuable for libraries since they come in two forms.
+    #
+    # This also reorganises the {sources} and {shared_sources} so that the
+    # former only contains ALL object files that are supposed to end up in
+    # static libraries and programs, while the latter contains ALL object files
+    # that are supposed to end up in shared libraries and DSOs.
+    # The main reason for having two different source structures is to allow
+    # the same name to be used for the static and the shared variants of a
+    # library.
+    {
+        # Take copies so we don't get interference from added stuff
+        my %unified_copy = ();
+        foreach (('sources', 'shared_sources')) {
+            $unified_copy{$_} = { %{$unified_info{$_}} }
+                if defined($unified_info{$_});
+            delete $unified_info{$_};
+        }
+        foreach my $prodtype (('programs', 'libraries', 'engines', 'scripts')) {
+            # $intent serves multi purposes:
+            # - give a prefix for the new object files names
+            # - in the case of libraries, rearrange the object files so static
+            #   libraries use the 'sources' structure exclusively, while shared
+            #   libraries use the 'shared_sources' structure exclusively.
+            my $intent = {
+                programs  => { bin    => { src => [ 'sources' ],
+                                           dst => 'sources' } },
+                libraries => { lib    => { src => [ 'sources' ],
+                                           dst => 'sources' },
+                               shlib  => { prodselect =>
+                                               sub { grep !/\.a$/, @_ },
+                                           src => [ 'sources',
+                                                    'shared_sources' ],
+                                           dst => 'shared_sources' } },
+                engines   => { dso    => { src => [ 'sources',
+                                                    'shared_sources' ],
+                                           dst => 'shared_sources' } },
+                scripts   => { script => { src => [ 'sources' ],
+                                           dst => 'sources' } }
+               } -> {$prodtype};
+            foreach my $kind (keys %$intent) {
+                my @src = @{$intent->{$kind}->{src}};
+                my $dst = $intent->{$kind}->{dst};
+                my $prodselect = $intent->{$kind}->{prodselect} // sub { @_ };
+                foreach my $prod ($prodselect->(keys %{$unified_info{$prodtype}})) {
+                    # %prod_sources has all applicable objects as keys, and
+                    # their corresponding sources as values
+                    my %prod_sources =
+                        map { $_ => [ keys %{$unified_copy{sources}->{$_}} ] }
+                        map { keys %{$unified_copy{$_}->{$prod}} }
+                        @src;
+                    foreach (keys %prod_sources) {
+                        # Only affect object or resource files, the others
+                        # simply get a new value (+1 instead of -1)
+                        if ($_ =~ /\.(o|res)$/) {
+                            (my $prodname = $prod) =~ s|\.a$||;
+                            my $newobj =
+                                catfile(dirname($_),
+                                        basename($prodname)
+                                            . '-' . $kind
+                                            . '-' . basename($_));
+                            $unified_info{$dst}->{$prod}->{$newobj} = 1;
+                            foreach my $src (@{$prod_sources{$_}}) {
+                                $unified_info{sources}->{$newobj}->{$src} = 1;
+                            }
+                            # Adjust dependencies
+                            foreach my $deps (keys %{$unified_info{depends}->{$_}}) {
+                                $unified_info{depends}->{$_}->{$deps} = -1;
+                                $unified_info{depends}->{$newobj}->{$deps} = 1;
+                            }
+                            # Adjust includes
+                            foreach my $k (('source', 'build')) {
+                                next unless
+                                    defined($unified_info{includes}->{$_}->{$k});
+                                my @incs = @{$unified_info{includes}->{$_}->{$k}};
+                                $unified_info{includes}->{$newobj}->{$k} = [ @incs ];
+                            }
+                        } else {
+                            $unified_info{$dst}->{$prod}->{$_} = 1;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    # At this point, we have a number of sources with the value -1.  They
+    # aren't part of the local build and are probably meant for a different
+    # platform, and can therefore be cleaned away.  That happens when making
+    # %unified_info more efficient below.
+
     ### Make unified_info a bit more efficient
     # One level structures
     foreach (("programs", "libraries", "engines", "scripts", "extra", "overrides")) {
@@ -2197,8 +2292,15 @@ EOF
     # Two level structures
     foreach my $l1 (("install", "sources", "shared_sources", "ldadd", "depends")) {
         foreach my $l2 (sort keys %{$unified_info{$l1}}) {
-            $unified_info{$l1}->{$l2} =
-                [ sort keys %{$unified_info{$l1}->{$l2}} ];
+            my @items =
+                sort
+                grep { $unified_info{$l1}->{$l2}->{$_} > 0 }
+                keys %{$unified_info{$l1}->{$l2}};
+            if (@items) {
+                $unified_info{$l1}->{$l2} = [ @items ];
+            } else {
+                delete $unified_info{$l1}->{$l2};
+            }
         }
     }
     # Includes