1*e0c4386eSCy Schubert#! /usr/bin/env perl 2*e0c4386eSCy Schubert# Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved. 3*e0c4386eSCy Schubert# 4*e0c4386eSCy Schubert# Licensed under the Apache License 2.0 (the "License"). You may not use 5*e0c4386eSCy Schubert# this file except in compliance with the License. You can obtain a copy 6*e0c4386eSCy Schubert# in the file LICENSE in the source distribution or at 7*e0c4386eSCy Schubert# https://www.openssl.org/source/license.html 8*e0c4386eSCy Schubert 9*e0c4386eSCy Schubert# Generate a linker version script suitable for the given platform 10*e0c4386eSCy Schubert# from a given ordinals file. 11*e0c4386eSCy Schubert 12*e0c4386eSCy Schubertuse strict; 13*e0c4386eSCy Schubertuse warnings; 14*e0c4386eSCy Schubert 15*e0c4386eSCy Schubertuse Getopt::Long; 16*e0c4386eSCy Schubertuse FindBin; 17*e0c4386eSCy Schubertuse lib "$FindBin::Bin/perl"; 18*e0c4386eSCy Schubert 19*e0c4386eSCy Schubertuse OpenSSL::Ordinals; 20*e0c4386eSCy Schubert 21*e0c4386eSCy Schubertuse lib '.'; 22*e0c4386eSCy Schubertuse configdata; 23*e0c4386eSCy Schubert 24*e0c4386eSCy Schubertuse File::Spec::Functions; 25*e0c4386eSCy Schubertuse lib catdir($config{sourcedir}, 'Configurations'); 26*e0c4386eSCy Schubertuse platform; 27*e0c4386eSCy Schubert 28*e0c4386eSCy Schubertmy $name = undef; # internal library/module name 29*e0c4386eSCy Schubertmy $ordinals_file = undef; # the ordinals file to use 30*e0c4386eSCy Schubertmy $version = undef; # the version to use for the library 31*e0c4386eSCy Schubertmy $OS = undef; # the operating system family 32*e0c4386eSCy Schubertmy $type = 'lib'; # either lib or dso 33*e0c4386eSCy Schubertmy $verbose = 0; 34*e0c4386eSCy Schubertmy $ctest = 0; 35*e0c4386eSCy Schubertmy $debug = 0; 36*e0c4386eSCy Schubert 37*e0c4386eSCy Schubert# For VMS, some modules may have case insensitive names 38*e0c4386eSCy Schubertmy $case_insensitive = 0; 39*e0c4386eSCy Schubert 40*e0c4386eSCy SchubertGetOptions('name=s' => \$name, 41*e0c4386eSCy Schubert 'ordinals=s' => \$ordinals_file, 42*e0c4386eSCy Schubert 'version=s' => \$version, 43*e0c4386eSCy Schubert 'OS=s' => \$OS, 44*e0c4386eSCy Schubert 'type=s' => \$type, 45*e0c4386eSCy Schubert 'ctest' => \$ctest, 46*e0c4386eSCy Schubert 'verbose' => \$verbose, 47*e0c4386eSCy Schubert # For VMS 48*e0c4386eSCy Schubert 'case-insensitive' => \$case_insensitive) 49*e0c4386eSCy Schubert or die "Error in command line arguments\n"; 50*e0c4386eSCy Schubert 51*e0c4386eSCy Schubertdie "Please supply arguments\n" 52*e0c4386eSCy Schubert unless $name && $ordinals_file && $OS; 53*e0c4386eSCy Schubertdie "--type argument must be equal to 'lib' or 'dso'" 54*e0c4386eSCy Schubert if $type ne 'lib' && $type ne 'dso'; 55*e0c4386eSCy Schubert 56*e0c4386eSCy Schubert# When building a "variant" shared library, with a custom SONAME, also customize 57*e0c4386eSCy Schubert# all the symbol versions. This produces a shared object that can coexist 58*e0c4386eSCy Schubert# without conflict in the same address space as a default build, or an object 59*e0c4386eSCy Schubert# with a different variant tag. 60*e0c4386eSCy Schubert# 61*e0c4386eSCy Schubert# For example, with a target definition that includes: 62*e0c4386eSCy Schubert# 63*e0c4386eSCy Schubert# shlib_variant => "-opt", 64*e0c4386eSCy Schubert# 65*e0c4386eSCy Schubert# we build the following objects: 66*e0c4386eSCy Schubert# 67*e0c4386eSCy Schubert# $ perl -le ' 68*e0c4386eSCy Schubert# for (@ARGV) { 69*e0c4386eSCy Schubert# if ($l = readlink) { 70*e0c4386eSCy Schubert# printf "%s -> %s\n", $_, $l 71*e0c4386eSCy Schubert# } else { 72*e0c4386eSCy Schubert# print 73*e0c4386eSCy Schubert# } 74*e0c4386eSCy Schubert# }' *.so* 75*e0c4386eSCy Schubert# libcrypto-opt.so.1.1 76*e0c4386eSCy Schubert# libcrypto.so -> libcrypto-opt.so.1.1 77*e0c4386eSCy Schubert# libssl-opt.so.1.1 78*e0c4386eSCy Schubert# libssl.so -> libssl-opt.so.1.1 79*e0c4386eSCy Schubert# 80*e0c4386eSCy Schubert# whose SONAMEs and dependencies are: 81*e0c4386eSCy Schubert# 82*e0c4386eSCy Schubert# $ for l in *.so; do 83*e0c4386eSCy Schubert# echo $l 84*e0c4386eSCy Schubert# readelf -d $l | egrep 'SONAME|NEEDED.*(ssl|crypto)' 85*e0c4386eSCy Schubert# done 86*e0c4386eSCy Schubert# libcrypto.so 87*e0c4386eSCy Schubert# 0x000000000000000e (SONAME) Library soname: [libcrypto-opt.so.1.1] 88*e0c4386eSCy Schubert# libssl.so 89*e0c4386eSCy Schubert# 0x0000000000000001 (NEEDED) Shared library: [libcrypto-opt.so.1.1] 90*e0c4386eSCy Schubert# 0x000000000000000e (SONAME) Library soname: [libssl-opt.so.1.1] 91*e0c4386eSCy Schubert# 92*e0c4386eSCy Schubert# We case-fold the variant tag to upper case and replace all non-alnum 93*e0c4386eSCy Schubert# characters with "_". This yields the following symbol versions: 94*e0c4386eSCy Schubert# 95*e0c4386eSCy Schubert# $ nm libcrypto.so | grep -w A 96*e0c4386eSCy Schubert# 0000000000000000 A OPENSSL_OPT_1_1_0 97*e0c4386eSCy Schubert# 0000000000000000 A OPENSSL_OPT_1_1_0a 98*e0c4386eSCy Schubert# 0000000000000000 A OPENSSL_OPT_1_1_0c 99*e0c4386eSCy Schubert# 0000000000000000 A OPENSSL_OPT_1_1_0d 100*e0c4386eSCy Schubert# 0000000000000000 A OPENSSL_OPT_1_1_0f 101*e0c4386eSCy Schubert# 0000000000000000 A OPENSSL_OPT_1_1_0g 102*e0c4386eSCy Schubert# $ nm libssl.so | grep -w A 103*e0c4386eSCy Schubert# 0000000000000000 A OPENSSL_OPT_1_1_0 104*e0c4386eSCy Schubert# 0000000000000000 A OPENSSL_OPT_1_1_0d 105*e0c4386eSCy Schubert# 106*e0c4386eSCy Schubert(my $SO_VARIANT = uc($target{"shlib_variant"} // '')) =~ s/\W/_/g; 107*e0c4386eSCy Schubert 108*e0c4386eSCy Schubertmy $libname = $type eq 'lib' ? platform->sharedname($name) : platform->dsoname($name); 109*e0c4386eSCy Schubert 110*e0c4386eSCy Schubertmy %OS_data = ( 111*e0c4386eSCy Schubert solaris => { writer => \&writer_linux, 112*e0c4386eSCy Schubert sort => sorter_linux(), 113*e0c4386eSCy Schubert platforms => { UNIX => 1 } }, 114*e0c4386eSCy Schubert "solaris-gcc" => 'solaris', # alias 115*e0c4386eSCy Schubert linux => 'solaris', # alias 116*e0c4386eSCy Schubert "bsd-gcc" => 'solaris', # alias 117*e0c4386eSCy Schubert aix => { writer => \&writer_aix, 118*e0c4386eSCy Schubert sort => sorter_unix(), 119*e0c4386eSCy Schubert platforms => { UNIX => 1 } }, 120*e0c4386eSCy Schubert VMS => { writer => \&writer_VMS, 121*e0c4386eSCy Schubert sort => OpenSSL::Ordinals::by_number(), 122*e0c4386eSCy Schubert platforms => { VMS => 1 } }, 123*e0c4386eSCy Schubert vms => 'VMS', # alias 124*e0c4386eSCy Schubert WINDOWS => { writer => \&writer_windows, 125*e0c4386eSCy Schubert sort => OpenSSL::Ordinals::by_name(), 126*e0c4386eSCy Schubert platforms => { WIN32 => 1, 127*e0c4386eSCy Schubert _WIN32 => 1 } }, 128*e0c4386eSCy Schubert windows => 'WINDOWS', # alias 129*e0c4386eSCy Schubert WIN32 => 'WINDOWS', # alias 130*e0c4386eSCy Schubert win32 => 'WIN32', # alias 131*e0c4386eSCy Schubert 32 => 'WIN32', # alias 132*e0c4386eSCy Schubert NT => 'WIN32', # alias 133*e0c4386eSCy Schubert nt => 'WIN32', # alias 134*e0c4386eSCy Schubert mingw => 'WINDOWS', # alias 135*e0c4386eSCy Schubert nonstop => { writer => \&writer_nonstop, 136*e0c4386eSCy Schubert sort => OpenSSL::Ordinals::by_name(), 137*e0c4386eSCy Schubert platforms => { TANDEM => 1 } }, 138*e0c4386eSCy Schubert ); 139*e0c4386eSCy Schubert 140*e0c4386eSCy Schubertdo { 141*e0c4386eSCy Schubert die "Unknown operating system family $OS\n" 142*e0c4386eSCy Schubert unless exists $OS_data{$OS}; 143*e0c4386eSCy Schubert $OS = $OS_data{$OS}; 144*e0c4386eSCy Schubert} while(ref($OS) eq ''); 145*e0c4386eSCy Schubert 146*e0c4386eSCy Schubertmy %disabled_uc = map { my $x = uc $_; $x =~ s|-|_|g; $x => 1 } keys %disabled; 147*e0c4386eSCy Schubert 148*e0c4386eSCy Schubertmy %ordinal_opts = (); 149*e0c4386eSCy Schubert$ordinal_opts{sort} = $OS->{sort} if $OS->{sort}; 150*e0c4386eSCy Schubert$ordinal_opts{filter} = 151*e0c4386eSCy Schubert sub { 152*e0c4386eSCy Schubert my $item = shift; 153*e0c4386eSCy Schubert return 154*e0c4386eSCy Schubert $item->exists() 155*e0c4386eSCy Schubert && platform_filter($item) 156*e0c4386eSCy Schubert && feature_filter($item); 157*e0c4386eSCy Schubert }; 158*e0c4386eSCy Schubertmy $ordinals = OpenSSL::Ordinals->new(from => $ordinals_file); 159*e0c4386eSCy Schubert 160*e0c4386eSCy Schubertmy $writer = $OS->{writer}; 161*e0c4386eSCy Schubert$writer = \&writer_ctest if $ctest; 162*e0c4386eSCy Schubert 163*e0c4386eSCy Schubert$writer->($ordinals->items(%ordinal_opts)); 164*e0c4386eSCy Schubert 165*e0c4386eSCy Schubertexit 0; 166*e0c4386eSCy Schubert 167*e0c4386eSCy Schubertsub platform_filter { 168*e0c4386eSCy Schubert my $item = shift; 169*e0c4386eSCy Schubert my %platforms = ( $item->platforms() ); 170*e0c4386eSCy Schubert 171*e0c4386eSCy Schubert # True if no platforms are defined 172*e0c4386eSCy Schubert return 1 if scalar keys %platforms == 0; 173*e0c4386eSCy Schubert 174*e0c4386eSCy Schubert # For any item platform tag, return the equivalence with the 175*e0c4386eSCy Schubert # current platform settings if it exists there, return 0 otherwise 176*e0c4386eSCy Schubert # if the item platform tag is true 177*e0c4386eSCy Schubert for (keys %platforms) { 178*e0c4386eSCy Schubert if (exists $OS->{platforms}->{$_}) { 179*e0c4386eSCy Schubert return $platforms{$_} == $OS->{platforms}->{$_}; 180*e0c4386eSCy Schubert } 181*e0c4386eSCy Schubert if ($platforms{$_}) { 182*e0c4386eSCy Schubert return 0; 183*e0c4386eSCy Schubert } 184*e0c4386eSCy Schubert } 185*e0c4386eSCy Schubert 186*e0c4386eSCy Schubert # Found no match? Then it's a go 187*e0c4386eSCy Schubert return 1; 188*e0c4386eSCy Schubert} 189*e0c4386eSCy Schubert 190*e0c4386eSCy Schubertsub feature_filter { 191*e0c4386eSCy Schubert my $item = shift; 192*e0c4386eSCy Schubert my @features = ( $item->features() ); 193*e0c4386eSCy Schubert 194*e0c4386eSCy Schubert # True if no features are defined 195*e0c4386eSCy Schubert return 1 if scalar @features == 0; 196*e0c4386eSCy Schubert 197*e0c4386eSCy Schubert my $verdict = ! grep { $disabled_uc{$_} } @features; 198*e0c4386eSCy Schubert 199*e0c4386eSCy Schubert if ($disabled{deprecated}) { 200*e0c4386eSCy Schubert foreach (@features) { 201*e0c4386eSCy Schubert next unless /^DEPRECATEDIN_(\d+)_(\d+)(?:_(\d+))?$/; 202*e0c4386eSCy Schubert my $symdep = $1 * 10000 + $2 * 100 + ($3 // 0); 203*e0c4386eSCy Schubert $verdict = 0 if $config{api} >= $symdep; 204*e0c4386eSCy Schubert print STDERR "DEBUG: \$symdep = $symdep, \$verdict = $verdict\n" 205*e0c4386eSCy Schubert if $debug && $1 == 0; 206*e0c4386eSCy Schubert } 207*e0c4386eSCy Schubert } 208*e0c4386eSCy Schubert 209*e0c4386eSCy Schubert return $verdict; 210*e0c4386eSCy Schubert} 211*e0c4386eSCy Schubert 212*e0c4386eSCy Schubertsub sorter_unix { 213*e0c4386eSCy Schubert my $by_name = OpenSSL::Ordinals::by_name(); 214*e0c4386eSCy Schubert my %weight = ( 215*e0c4386eSCy Schubert 'FUNCTION' => 1, 216*e0c4386eSCy Schubert 'VARIABLE' => 2 217*e0c4386eSCy Schubert ); 218*e0c4386eSCy Schubert 219*e0c4386eSCy Schubert return sub { 220*e0c4386eSCy Schubert my $item1 = shift; 221*e0c4386eSCy Schubert my $item2 = shift; 222*e0c4386eSCy Schubert 223*e0c4386eSCy Schubert my $verdict = $weight{$item1->type()} <=> $weight{$item2->type()}; 224*e0c4386eSCy Schubert if ($verdict == 0) { 225*e0c4386eSCy Schubert $verdict = $by_name->($item1, $item2); 226*e0c4386eSCy Schubert } 227*e0c4386eSCy Schubert return $verdict; 228*e0c4386eSCy Schubert }; 229*e0c4386eSCy Schubert} 230*e0c4386eSCy Schubert 231*e0c4386eSCy Schubertsub sorter_linux { 232*e0c4386eSCy Schubert my $by_version = OpenSSL::Ordinals::by_version(); 233*e0c4386eSCy Schubert my $by_unix = sorter_unix(); 234*e0c4386eSCy Schubert 235*e0c4386eSCy Schubert return sub { 236*e0c4386eSCy Schubert my $item1 = shift; 237*e0c4386eSCy Schubert my $item2 = shift; 238*e0c4386eSCy Schubert 239*e0c4386eSCy Schubert my $verdict = $by_version->($item1, $item2); 240*e0c4386eSCy Schubert if ($verdict == 0) { 241*e0c4386eSCy Schubert $verdict = $by_unix->($item1, $item2); 242*e0c4386eSCy Schubert } 243*e0c4386eSCy Schubert return $verdict; 244*e0c4386eSCy Schubert }; 245*e0c4386eSCy Schubert} 246*e0c4386eSCy Schubert 247*e0c4386eSCy Schubertsub writer_linux { 248*e0c4386eSCy Schubert my $thisversion = ''; 249*e0c4386eSCy Schubert my $currversion_s = ''; 250*e0c4386eSCy Schubert my $prevversion_s = ''; 251*e0c4386eSCy Schubert my $indent = 0; 252*e0c4386eSCy Schubert 253*e0c4386eSCy Schubert for (@_) { 254*e0c4386eSCy Schubert if ($thisversion && $_->version() ne $thisversion) { 255*e0c4386eSCy Schubert die "$ordinals_file: It doesn't make sense to have both versioned ", 256*e0c4386eSCy Schubert "and unversioned symbols" 257*e0c4386eSCy Schubert if $thisversion eq '*'; 258*e0c4386eSCy Schubert print <<"_____"; 259*e0c4386eSCy Schubert}${prevversion_s}; 260*e0c4386eSCy Schubert_____ 261*e0c4386eSCy Schubert $prevversion_s = " OPENSSL${SO_VARIANT}_$thisversion"; 262*e0c4386eSCy Schubert $thisversion = ''; # Trigger start of next section 263*e0c4386eSCy Schubert } 264*e0c4386eSCy Schubert unless ($thisversion) { 265*e0c4386eSCy Schubert $indent = 0; 266*e0c4386eSCy Schubert $thisversion = $_->version(); 267*e0c4386eSCy Schubert $currversion_s = ''; 268*e0c4386eSCy Schubert $currversion_s = "OPENSSL${SO_VARIANT}_$thisversion " 269*e0c4386eSCy Schubert if $thisversion ne '*'; 270*e0c4386eSCy Schubert print <<"_____"; 271*e0c4386eSCy Schubert${currversion_s}{ 272*e0c4386eSCy Schubert global: 273*e0c4386eSCy Schubert_____ 274*e0c4386eSCy Schubert } 275*e0c4386eSCy Schubert print ' ', $_->name(), ";\n"; 276*e0c4386eSCy Schubert } 277*e0c4386eSCy Schubert 278*e0c4386eSCy Schubert print <<"_____"; 279*e0c4386eSCy Schubert local: *; 280*e0c4386eSCy Schubert}${prevversion_s}; 281*e0c4386eSCy Schubert_____ 282*e0c4386eSCy Schubert} 283*e0c4386eSCy Schubert 284*e0c4386eSCy Schubertsub writer_aix { 285*e0c4386eSCy Schubert for (@_) { 286*e0c4386eSCy Schubert print $_->name(),"\n"; 287*e0c4386eSCy Schubert } 288*e0c4386eSCy Schubert} 289*e0c4386eSCy Schubert 290*e0c4386eSCy Schubertsub writer_nonstop { 291*e0c4386eSCy Schubert for (@_) { 292*e0c4386eSCy Schubert print "-export ",$_->name(),"\n"; 293*e0c4386eSCy Schubert } 294*e0c4386eSCy Schubert} 295*e0c4386eSCy Schubert 296*e0c4386eSCy Schubertsub writer_windows { 297*e0c4386eSCy Schubert print <<"_____"; 298*e0c4386eSCy Schubert; 299*e0c4386eSCy Schubert; Definition file for the DLL version of the $libname library from OpenSSL 300*e0c4386eSCy Schubert; 301*e0c4386eSCy Schubert 302*e0c4386eSCy SchubertLIBRARY "$libname" 303*e0c4386eSCy Schubert 304*e0c4386eSCy SchubertEXPORTS 305*e0c4386eSCy Schubert_____ 306*e0c4386eSCy Schubert for (@_) { 307*e0c4386eSCy Schubert print " ",$_->name(); 308*e0c4386eSCy Schubert if (platform->can('export2internal')) { 309*e0c4386eSCy Schubert print "=". platform->export2internal($_->name()); 310*e0c4386eSCy Schubert } 311*e0c4386eSCy Schubert print "\n"; 312*e0c4386eSCy Schubert } 313*e0c4386eSCy Schubert} 314*e0c4386eSCy Schubert 315*e0c4386eSCy Schubertsub collect_VMS_mixedcase { 316*e0c4386eSCy Schubert return [ 'SPARE', 'SPARE' ] unless @_; 317*e0c4386eSCy Schubert 318*e0c4386eSCy Schubert my $s = shift; 319*e0c4386eSCy Schubert my $s_uc = uc($s); 320*e0c4386eSCy Schubert my $type = shift; 321*e0c4386eSCy Schubert 322*e0c4386eSCy Schubert return [ "$s=$type", 'SPARE' ] if $s_uc eq $s; 323*e0c4386eSCy Schubert return [ "$s_uc/$s=$type", "$s=$type" ]; 324*e0c4386eSCy Schubert} 325*e0c4386eSCy Schubert 326*e0c4386eSCy Schubertsub collect_VMS_uppercase { 327*e0c4386eSCy Schubert return [ 'SPARE' ] unless @_; 328*e0c4386eSCy Schubert 329*e0c4386eSCy Schubert my $s = shift; 330*e0c4386eSCy Schubert my $s_uc = uc($s); 331*e0c4386eSCy Schubert my $type = shift; 332*e0c4386eSCy Schubert 333*e0c4386eSCy Schubert return [ "$s_uc=$type" ]; 334*e0c4386eSCy Schubert} 335*e0c4386eSCy Schubert 336*e0c4386eSCy Schubertsub writer_VMS { 337*e0c4386eSCy Schubert my @slot_collection = (); 338*e0c4386eSCy Schubert my $collector = 339*e0c4386eSCy Schubert $case_insensitive ? \&collect_VMS_uppercase : \&collect_VMS_mixedcase; 340*e0c4386eSCy Schubert 341*e0c4386eSCy Schubert my $last_num = 0; 342*e0c4386eSCy Schubert foreach (@_) { 343*e0c4386eSCy Schubert my $this_num = $_->number(); 344*e0c4386eSCy Schubert $this_num = $last_num + 1 if $this_num =~ m|^\?|; 345*e0c4386eSCy Schubert 346*e0c4386eSCy Schubert while (++$last_num < $this_num) { 347*e0c4386eSCy Schubert push @slot_collection, $collector->(); # Just occupy a slot 348*e0c4386eSCy Schubert } 349*e0c4386eSCy Schubert my $type = { 350*e0c4386eSCy Schubert FUNCTION => 'PROCEDURE', 351*e0c4386eSCy Schubert VARIABLE => 'DATA' 352*e0c4386eSCy Schubert } -> {$_->type()}; 353*e0c4386eSCy Schubert push @slot_collection, $collector->($_->name(), $type); 354*e0c4386eSCy Schubert } 355*e0c4386eSCy Schubert 356*e0c4386eSCy Schubert print <<"_____" if defined $version; 357*e0c4386eSCy SchubertIDENTIFICATION=$version 358*e0c4386eSCy Schubert_____ 359*e0c4386eSCy Schubert print <<"_____" unless $case_insensitive; 360*e0c4386eSCy SchubertCASE_SENSITIVE=YES 361*e0c4386eSCy Schubert_____ 362*e0c4386eSCy Schubert print <<"_____"; 363*e0c4386eSCy SchubertSYMBOL_VECTOR=(- 364*e0c4386eSCy Schubert_____ 365*e0c4386eSCy Schubert # It's uncertain how long aggregated lines the linker can handle, 366*e0c4386eSCy Schubert # but it has been observed that at least 1024 characters is ok. 367*e0c4386eSCy Schubert # Either way, this means that we need to keep track of the total 368*e0c4386eSCy Schubert # line length of each "SYMBOL_VECTOR" statement. Fortunately, we 369*e0c4386eSCy Schubert # can have more than one of those... 370*e0c4386eSCy Schubert my $symvtextcount = 16; # The length of "SYMBOL_VECTOR=(" 371*e0c4386eSCy Schubert while (@slot_collection) { 372*e0c4386eSCy Schubert my $set = shift @slot_collection; 373*e0c4386eSCy Schubert my $settextlength = 0; 374*e0c4386eSCy Schubert foreach (@$set) { 375*e0c4386eSCy Schubert $settextlength += 376*e0c4386eSCy Schubert + 3 # two space indentation and comma 377*e0c4386eSCy Schubert + length($_) 378*e0c4386eSCy Schubert + 1 # postdent 379*e0c4386eSCy Schubert ; 380*e0c4386eSCy Schubert } 381*e0c4386eSCy Schubert $settextlength--; # only one space indentation on the first one 382*e0c4386eSCy Schubert my $firstcomma = ','; 383*e0c4386eSCy Schubert 384*e0c4386eSCy Schubert if ($symvtextcount + $settextlength > 1024) { 385*e0c4386eSCy Schubert print <<"_____"; 386*e0c4386eSCy Schubert) 387*e0c4386eSCy SchubertSYMBOL_VECTOR=(- 388*e0c4386eSCy Schubert_____ 389*e0c4386eSCy Schubert $symvtextcount = 16; # The length of "SYMBOL_VECTOR=(" 390*e0c4386eSCy Schubert } 391*e0c4386eSCy Schubert if ($symvtextcount == 16) { 392*e0c4386eSCy Schubert $firstcomma = ''; 393*e0c4386eSCy Schubert } 394*e0c4386eSCy Schubert 395*e0c4386eSCy Schubert my $indent = ' '.$firstcomma; 396*e0c4386eSCy Schubert foreach (@$set) { 397*e0c4386eSCy Schubert print <<"_____"; 398*e0c4386eSCy Schubert$indent$_ - 399*e0c4386eSCy Schubert_____ 400*e0c4386eSCy Schubert $symvtextcount += length($indent) + length($_) + 1; 401*e0c4386eSCy Schubert $indent = ' ,'; 402*e0c4386eSCy Schubert } 403*e0c4386eSCy Schubert } 404*e0c4386eSCy Schubert print <<"_____"; 405*e0c4386eSCy Schubert) 406*e0c4386eSCy Schubert_____ 407*e0c4386eSCy Schubert 408*e0c4386eSCy Schubert if (defined $version) { 409*e0c4386eSCy Schubert $version =~ /^(\d+)\.(\d+)\.(\d+)/; 410*e0c4386eSCy Schubert my $libvmajor = $1; 411*e0c4386eSCy Schubert my $libvminor = $2 * 100 + $3; 412*e0c4386eSCy Schubert print <<"_____"; 413*e0c4386eSCy SchubertGSMATCH=LEQUAL,$libvmajor,$libvminor 414*e0c4386eSCy Schubert_____ 415*e0c4386eSCy Schubert } 416*e0c4386eSCy Schubert} 417*e0c4386eSCy Schubert 418*e0c4386eSCy Schubertsub writer_ctest { 419*e0c4386eSCy Schubert print <<'_____'; 420*e0c4386eSCy Schubert/* 421*e0c4386eSCy Schubert * Test file to check all DEF file symbols are present by trying 422*e0c4386eSCy Schubert * to link to all of them. This is *not* intended to be run! 423*e0c4386eSCy Schubert */ 424*e0c4386eSCy Schubert 425*e0c4386eSCy Schubertint main() 426*e0c4386eSCy Schubert{ 427*e0c4386eSCy Schubert_____ 428*e0c4386eSCy Schubert 429*e0c4386eSCy Schubert my $last_num = 0; 430*e0c4386eSCy Schubert for (@_) { 431*e0c4386eSCy Schubert my $this_num = $_->number(); 432*e0c4386eSCy Schubert $this_num = $last_num + 1 if $this_num =~ m|^\?|; 433*e0c4386eSCy Schubert 434*e0c4386eSCy Schubert if ($_->type() eq 'VARIABLE') { 435*e0c4386eSCy Schubert print "\textern int ", $_->name(), '; /* type unknown */ /* ', 436*e0c4386eSCy Schubert $this_num, ' ', $_->version(), " */\n"; 437*e0c4386eSCy Schubert } else { 438*e0c4386eSCy Schubert print "\textern int ", $_->name(), '(); /* type unknown */ /* ', 439*e0c4386eSCy Schubert $this_num, ' ', $_->version(), " */\n"; 440*e0c4386eSCy Schubert } 441*e0c4386eSCy Schubert 442*e0c4386eSCy Schubert $last_num = $this_num; 443*e0c4386eSCy Schubert } 444*e0c4386eSCy Schubert print <<'_____'; 445*e0c4386eSCy Schubert} 446*e0c4386eSCy Schubert_____ 447*e0c4386eSCy Schubert} 448