Skip to content

Commit 033cf41

Browse files
committed
extended functionality and moved it to libtommath/etc
1 parent 39b5417 commit 033cf41

File tree

3 files changed

+335
-173
lines changed

3 files changed

+335
-173
lines changed

etc/make_small_lib.pl

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
#!/usr/bin/env perl
2+
3+
use strict;
4+
use warnings;
5+
6+
use Getopt::Long;
7+
use File::Basename 'basename';
8+
use File::Glob 'bsd_glob';
9+
use File::Spec;
10+
11+
my $sep = File::Spec->catfile('', '');
12+
my %fast_functions = (
13+
s_mp_balance_mul => 1,
14+
s_mp_exptmod_fast => 1,
15+
s_mp_invmod_fast => 1,
16+
s_mp_karatsuba_mul => 1,
17+
s_mp_karatsuba_sqr => 1,
18+
s_mp_montgomery_reduce_fast => 1,
19+
s_mp_mul_digs_fast => 1,
20+
s_mp_mul_high_digs_fast => 1,
21+
s_mp_sqr_fast => 1,
22+
s_mp_toom_mul => 1,
23+
s_mp_toom_sqr => 1
24+
);
25+
my @dependency_list = ();
26+
27+
sub uniq {
28+
my %seen;
29+
grep !$seen{$_}++, @_;
30+
}
31+
32+
sub read_file {
33+
my $f = shift;
34+
open my $fh, "<", $f or die "FATAL: read_rawfile() cannot open file '$f': $!";
35+
binmode $fh;
36+
return do { local $/; <$fh> };
37+
}
38+
39+
sub write_file {
40+
my ($f, $data) = @_;
41+
die "FATAL: write_file() no data" unless defined $data;
42+
open my $fh, ">", $f or die "FATAL: write_file() cannot open file '$f': $!";
43+
binmode $fh;
44+
print $fh $data or die "FATAL: write_file() cannot write to '$f': $!";
45+
close $fh or die "FATAL: write_file() cannot close '$f': $!";
46+
return;
47+
}
48+
49+
sub patch_makefile {
50+
my ($content, @variables) = @_;
51+
for my $v (@variables) {
52+
if ($v =~ /^([A-Z0-9_]+)\s*=.*$/si) {
53+
my $name = $1;
54+
$content =~ s/\n\Q$name\E\b.*?[^\\]\n/\n$v\n/s;
55+
}
56+
else {
57+
die "patch_file failed: " . substr($v, 0, 30) . "..";
58+
}
59+
}
60+
return $content;
61+
}
62+
63+
sub prepare_makefile_variable {
64+
my ($varname, @list) = @_;
65+
my $output = "$varname=";
66+
my $len = length($output);
67+
foreach my $obj (sort @list) {
68+
$len = $len + length $obj;
69+
$obj =~ s/\*/\$/;
70+
if ($len > 100) {
71+
$output .= "\\\n";
72+
$len = length $obj;
73+
}
74+
$output .= $obj . ' ';
75+
}
76+
$output =~ s/ $//;
77+
return $output;
78+
}
79+
80+
sub prepare_msvc_files_xml {
81+
my ($all, $exclude_re, $targets) = @_;
82+
my $last = [];
83+
my $depth = 2;
84+
85+
# sort files in the same order as visual studio (ugly, I know)
86+
my @parts = ();
87+
for my $orig (@$all) {
88+
my $p = basename($orig);
89+
$p =~ s|/|/~|g;
90+
$p =~ s|/~([^/]+)$|/$1|g;
91+
my @l = map { sprintf "% -99s", $_ } split /\//, $p;
92+
push @parts, [ basename($orig), join(':', @l) ];
93+
}
94+
95+
my @sorted = map { $_->[0] } sort { $a->[1] cmp $b->[1] } @parts;
96+
97+
my $files = "<Files>\r\n";
98+
for my $full (@sorted) {
99+
my @items = split /\//, $full; # split by '/'
100+
$full =~ s|/|\\|g; # replace '/' bt '\'
101+
shift @items; # drop first one (src)
102+
pop @items; # drop last one (filename.ext)
103+
my $current = \@items;
104+
if (join(':', @$current) ne join(':', @$last)) {
105+
my $common = 0;
106+
$common++ while ($last->[$common] && $current->[$common] && $last->[$common] eq $current->[$common]);
107+
my $back = @$last - $common;
108+
if ($back > 0) {
109+
$files .= ("\t" x --$depth) . "</Filter>\r\n" for (1..$back);
110+
}
111+
my $fwd = [ @$current ]; splice(@$fwd, 0, $common);
112+
for my $i (0..scalar(@$fwd) - 1) {
113+
$files .= ("\t" x $depth) . "<Filter\r\n";
114+
$files .= ("\t" x $depth) . "\tName=\"$fwd->[$i]\"\r\n";
115+
$files .= ("\t" x $depth) . "\t>\r\n";
116+
$depth++;
117+
}
118+
$last = $current;
119+
}
120+
$files .= ("\t" x $depth) . "<File\r\n";
121+
$files .= ("\t" x $depth) . "\tRelativePath=\"$full\"\r\n";
122+
$files .= ("\t" x $depth) . "\t>\r\n";
123+
if ($full =~ $exclude_re) {
124+
for (@$targets) {
125+
$files .= ("\t" x $depth) . "\t<FileConfiguration\r\n";
126+
$files .= ("\t" x $depth) . "\t\tName=\"$_\"\r\n";
127+
$files .= ("\t" x $depth) . "\t\tExcludedFromBuild=\"true\"\r\n";
128+
$files .= ("\t" x $depth) . "\t\t>\r\n";
129+
$files .= ("\t" x $depth) . "\t\t<Tool\r\n";
130+
$files .= ("\t" x $depth) . "\t\t\tName=\"VCCLCompilerTool\"\r\n";
131+
$files .= ("\t" x $depth) . "\t\t\tAdditionalIncludeDirectories=\"\"\r\n";
132+
$files .= ("\t" x $depth) . "\t\t\tPreprocessorDefinitions=\"\"\r\n";
133+
$files .= ("\t" x $depth) . "\t\t/>\r\n";
134+
$files .= ("\t" x $depth) . "\t</FileConfiguration>\r\n";
135+
}
136+
}
137+
$files .= ("\t" x $depth) . "</File>\r\n";
138+
}
139+
$files .= ("\t" x --$depth) . "</Filter>\r\n" for (@$last);
140+
$files .= "\t</Files>";
141+
return $files;
142+
}
143+
144+
sub process_makefiles {
145+
my ($path, @o) = @_;
146+
my @all = map {$path.$sep . $_} @o;
147+
my $var_o = prepare_makefile_variable("OBJECTS", @o);
148+
(my $var_obj = $var_o) =~ s/\.o\b/.obj/sg;
149+
150+
151+
# update MSVC project files
152+
s/\.o/.c/ for @all;
153+
my $msvc_files = prepare_msvc_files_xml(\@all, qr/NOT_USED_HERE/, ['Debug|Win32', 'Release|Win32', 'Debug|x64', 'Release|x64']);
154+
for my $m (qw/libtommath_VS2008.vcproj/) {
155+
my $old = read_file($path.$sep.$m);
156+
my $new = $old;
157+
$new =~ s|<Files>.*</Files>|$msvc_files|s;
158+
if ($old ne $new) {
159+
write_file($path.$sep.$m, $new);
160+
warn "changed: $path$sep$m\n";
161+
}
162+
}
163+
164+
# update OBJECTS
165+
for my $m (qw/ makefile makefile.shared makefile_include.mk makefile.msvc makefile.unix makefile.mingw /) {
166+
my $old = read_file($path.$sep.$m);
167+
my $new = $m eq 'makefile.msvc' ? patch_makefile($old, $var_obj)
168+
: patch_makefile($old, $var_o);
169+
if ($old ne $new) {
170+
write_file($path.$sep.$m, $new);
171+
warn "changed: $path$sep$m\n";
172+
}
173+
}
174+
}
175+
176+
# TODO: that is not the best way to do it, but a simple one.
177+
sub write_header
178+
{
179+
my ($path, @entries) = @_;
180+
my $tcpath;
181+
my $content = "/* LibTomMath, multiple-precision integer library -- Tom St Denis */\n";
182+
$content = $content . "/* SPDX-License-Identifier: Unlicense */\n";
183+
foreach my $entry (@entries) {
184+
$entry =~ tr/[a-z]/[A-Z]/;
185+
$entry = '#define BN_' . $entry . "_C\n";
186+
$content = $content . $entry;
187+
}
188+
$tcpath = $path . $sep . 'tommath_class.h';
189+
write_file($tcpath, $content);
190+
warn "File $tcpath written\n";
191+
$tcpath = $path . $sep . 'tommath_superclass.h';
192+
write_file($tcpath, "");
193+
warn "File $tcpath emptied\n";
194+
}
195+
196+
sub gather_functions
197+
{
198+
my $path = shift;
199+
my %depmap;
200+
201+
if(-d $path) {
202+
$path = $path . $sep . '*.c';
203+
}
204+
205+
foreach my $filename (glob $path) {
206+
print "filename: " . $filename . " path: ". $path . "\n";
207+
open(my $src, '<', $filename) or die "Can't open source file!\n";
208+
read $src, my $content, -s $src;
209+
close $src;
210+
211+
$filename = basename($filename);
212+
$filename =~ s/^bn_|\.c$//g;
213+
214+
$content =~ s{/\*.*?\*/}{}gs;
215+
my $list = "";
216+
foreach my $line (split /\n/, $content) {
217+
# TODO: change to read public functions only when scanning user source.
218+
while ($line =~ /(fast_)?(s_)?mp\_[a-z_0-9]*(?=\()|(?<=\()mp\_[a-z_0-9]*(?=,)/g) {
219+
my $a = $&;
220+
next if $a eq "mp_err";
221+
if($list eq "") {
222+
$list = $a;
223+
}
224+
else {
225+
$list = $list . "," . $a;
226+
}
227+
}
228+
}
229+
$depmap{$filename} = $list;
230+
}
231+
return %depmap;
232+
}
233+
234+
sub gather_dependencies
235+
{
236+
my ($deplist, $depmap, $funcslist) = @_;
237+
my @funcs = split ',', $funcslist;
238+
if ($deplist =~ /$funcs[0]/) {
239+
return $deplist;
240+
} else {
241+
$deplist = $deplist . $funcs[0];
242+
}
243+
push @dependency_list, $funcs[0];
244+
shift @funcs;
245+
my $olddeplist = $deplist;
246+
foreach my $i (@funcs) {
247+
$deplist = gather_dependencies($deplist, $depmap, ${$depmap}{$i}) if exists ${$depmap}{$i};
248+
}
249+
return $olddeplist;
250+
}
251+
252+
sub start
253+
{
254+
my ($sd, $td, $no, $cm) = @_;
255+
256+
my %depmap;
257+
my %user_functions;
258+
my %ff_hash;
259+
my @functions;
260+
my @tmp;
261+
262+
# TODO: checks&balances
263+
-e $td.$sep."tommath.h" or die "$td.$sep.tommath.h not found, please check path to LibTomMath sources\n";
264+
265+
%depmap = gather_functions($td);
266+
%user_functions = gather_functions($sd);
267+
268+
foreach (sort keys %user_functions) {
269+
push @functions, split /,/ , $user_functions{$_};
270+
}
271+
@functions = uniq(sort @functions);
272+
273+
foreach (@functions) {
274+
exists $depmap{$_} or die "Function \"$_\" does not exist in LibTomMath.\n";
275+
}
276+
277+
# gather dependencies
278+
foreach (sort keys %user_functions) {
279+
gather_dependencies("", \%depmap, $user_functions{$_});
280+
}
281+
@dependency_list = uniq(sort @dependency_list);
282+
283+
# make an even smaller lib by removing non-essential functions (e.g. Karatsuba for multiplication)
284+
if ($no == 1) {
285+
foreach (@dependency_list) {
286+
next if exists $fast_functions{$_};
287+
push @tmp, $_;
288+
}
289+
@dependency_list = @tmp;
290+
@tmp = ();
291+
}
292+
293+
if ($cm == 1) {
294+
foreach my $entry (@dependency_list) {
295+
$entry = 'bn_' . $entry . '.o';
296+
push @tmp, $entry;
297+
}
298+
process_makefiles($td, @tmp);
299+
}
300+
else {
301+
write_header($td, @dependency_list);
302+
}
303+
return 1;
304+
}
305+
306+
sub die_usage {
307+
die <<"EOO";
308+
usage: $0 -s OR $0 --source-dir [./]
309+
$0 -t OR $0 --tommath-dir [./libtommath]
310+
$0 -n OR $0 --no-optimization
311+
$0 -m OR $0 --change-makefiles
312+
313+
The option --source-dir accepts a directory or a single file.
314+
315+
EOO
316+
}
317+
318+
my $source_dir = "";
319+
my $tommath_dir = "libtommath$sep";
320+
my $config_file = "";
321+
my $no_optimizations = 0;
322+
my $change_makefiles = 0;
323+
324+
GetOptions( "s|source-dir=s" => \$source_dir,
325+
"t|tommath-dir=s" => \$tommath_dir,
326+
"n|no-optimizations" => \$no_optimizations,
327+
"m|change-makefiles" => \$change_makefiles,
328+
"h|help" => \my $help
329+
) or die_usage;
330+
331+
my $exit_value = start($source_dir,
332+
$tommath_dir,
333+
$no_optimizations,
334+
$change_makefiles);
335+
exit $exit_value;

make_config.conf

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)