1#!/usr/bin/perl 2use strict; 3use warnings; 4die "Usage: $0 script.ver dllname build.def import.def\n" if @ARGV != 4; 5my ($verfile, $dllname, $builddef, $importdef) = @ARGV; 6open my $verfh, '<', $verfile or die "Cannot open input file $verfile: $!\n"; 7my $input = join '', <$verfh>; 8close $verfh; 9my @syms; 10my (%cnt, %last, %ords); 11$input =~ s/\/\*.*?\*\///sg; # Remove C comments 12while ($input =~ m/(\S+)\s*\{((?:[^\{\}]|\{(?2)\})+)\}\s*;/sg) { # Split {...} 13 my ($ver, $block) = ($1, $2); 14 while ($block =~ s/(\S+)\s*:((?:[^\{\}:]|\{(?2)\})+)$//sg) { # Split section: 15 my ($section, $syms) = ($1, $2); 16 next if $section ne 'global'; 17 $syms =~ s/\s+//g; 18 foreach (split /;\s*/, $syms) { # Split symbols 19 $cnt{$_}++; 20 $last{$_} = $ver; 21 push @syms, [$_, $ver]; 22 } 23 } 24} 25open my $importfh, '>', $importdef or die "Cannot open output file $importdef: $!\n"; 26open my $buildfh, '>', $builddef or die "Cannot open output file $builddef: $!\n"; 27print $importfh "LIBRARY \"$dllname\"\n"; 28print $importfh "EXPORTS\n"; 29print $buildfh "EXPORTS\n"; 30my $ord = 1; 31foreach (@syms) { 32 my ($sym, $ver) = @{$_}; 33 print $importfh "\"$sym\@$ver\" \@$ord\n"; 34 if ($last{$sym} ne $ver) { 35 print $buildfh "\"$sym\@$ver\" \@$ord\n"; 36 } else { 37 $ords{$sym} = $ord; 38 print $buildfh "\"$sym\@$ver\" = " . (($cnt{$sym} > 1) ? "\"$sym\@\@$ver\"" : $sym) . " \@$ord\n" 39 } 40 $ord++; 41} 42# GNU dlltool has broken calculation of ordinals for aliased symbols, so specify ordinals explicitly 43# GNU LD prior 2.21 has broken handling of symbols with dot character 44# Operator == for defining symbol alias is supported since GNU dlltool 2.21 45print $importfh "$_ \@$ords{$_} == \"$_\@$last{$_}\"\n" foreach sort keys %last; 46close $importfh; 47close $buildfh; 48