Initial version of CrossReport program.
[fedora-mingw.git] / crossreport / crossreport.pl
1 #!/usr/bin/perl -w
2 #
3 # CrossReport - analysis tool.
4 # Copyright (C) 2009 Red Hat Inc.
5 # Written by Richard W.M. Jones <rjones@redhat.com>,
6 # http://fedoraproject.org/wiki/MinGW
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or (at
11 # your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful, but
14 # WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 use strict;
23
24 use Getopt::Long;
25 use Pod::Usage;
26 use GDBM_File;
27 use POSIX qw(strftime floor);
28
29 =pod
30
31 =head1 NAME
32
33 CrossReport - Analysis tool to help cross-compilation to Windows.
34
35 =head1 SYNOPSIS
36
37  mingw32-crossreport [options] /path/to/linuxbinary
38
39 =head1 DESCRIPTION
40
41 CrossReport is a tool to help you analyze the APIs used by a compiled
42 Linux program, in order to work out the effort required to
43 cross-compile that program for Windows, using the Fedora MinGW
44 cross-compiler.
45
46 The simplest way to use it is to point it at an existing Linux binary,
47 and then read the generated report.
48
49 What it does in more detail: It looks at the libraries and API calls
50 used by the Linux binary, and compares them to the libraries and API
51 calls that we currently support under the Fedora MinGW cross-compiler.
52 It then works out what is missing, and produces a report suggesting
53 the amount of work that needs to be done to port the program.  For
54 example, whether whole libraries need to be ported first, and/or how
55 to substitute individual calls to work on Windows.
56
57 =head1 EXAMPLE
58
59 Assuming that the excellent vector graphics editor Inkscape
60 (L<http://www.inkscape.org/>) is installed, you could do:
61
62  mingw32-crossreport /usr/bin/inkscape > inkscape-report.txt
63  less inkscape-report.txt
64
65 =head1 SHORTCOMINGS
66
67 The report is only a general guide.  CrossReport contains a lot of
68 knowledge about common Linux calls and APIs, but does not know about
69 every possible library.
70
71 =head1 DATABASE
72
73 The program relies on a database of MinGW APIs.  The default location
74 for this database is C</usr/share/crossreport/crossreport.db> or the
75 same file in the current working directory.  If the database cannot be
76 found in either location, the program will fail with an error message.
77
78 The database is updated regularly and distributed with CrossReport.
79 To get the best quality report, make sure you are running a recent
80 version of the program.
81
82 =cut
83
84 my $help = '';
85 my $man = '';
86 my $verbose = '';
87 my $binary = '';
88
89 sub get_options
90 {
91     my $result = GetOptions (
92         "help|?" => \$help,
93         "man" => \$man,
94         "verbose" => \$verbose,
95     );
96     die "crossreport: use --help for information about command line options\n"
97         unless $result;
98
99     pod2usage(1) if $help;
100     pod2usage(-exitstatus => 0, -verbose => 2) if $man;
101
102     die "crossreport: no binary specified: use --help for more help\n"
103         if @ARGV != 1;
104
105     $binary = $ARGV[0];
106 }
107
108 my %symbols;
109
110 sub get_db
111 {
112     foreach ("/usr/local/share/crossreport/crossreport.db",
113              "/usr/share/crossreport/crossreport.db",
114              "crossreport.db") {
115         if (-f $_) {
116             tie %symbols, "GDBM_File", $_, &GDBM_READER, 0;
117             return;
118         }
119     }
120     die "Could not find crossreport.db\n"
121 }
122
123 # Get the symbols (API calls) used by the binary.
124
125 my %api = ();                   # Count how each API is used.
126 my @unresolved = ();            # List of unresolved symbols.
127
128 sub get_symbols
129 {
130     my $cmd = "nm -D $binary | grep ' U ' | awk '{print \$2}' | c++filt";
131     open CMD, "$cmd |" or die "$cmd: $!";
132     foreach (<CMD>) {
133         chomp;
134         if (exists $symbols{$_}) {
135             my $rpm_name = $symbols{$_};
136             $api{$rpm_name} = 0 unless exists $api{$rpm_name};
137             $api{$rpm_name}++;
138         } else {
139             push @unresolved, $_;
140         }
141     }
142     close CMD;
143 }
144
145 #----------------------------------------------------------------------
146 # Reporting section.
147
148 # This hash contains our area expertise about some unresolved symbols.
149
150 my $suggest_portability_library =
151     "To get more reliable semantics, we suggest you use a portability\n".
152     "library such as Gnulib, glib2, QtCore, etc.\n";
153 my $warning_about_read_write_on_sockets =
154     "If you are using read/write on sockets, then this won't work on\n".
155     "Windows.  You should use recv/send instead.\n";
156
157 my %report = (
158     "open" =>
159     "Program uses POSIX open/close/read/write/... APIs.  You should be\n".
160     "aware that Win32 provides functions with the same name which do not\n".
161     "have POSIX semantics.  Simple file operations will be fine, but you\n".
162     "will not be able to, for example, open /dev/* or other special files,\n".
163     "and select, locking and other POSIX features will not work the same\n".
164     "way.\n".
165     "\n".
166     "$suggest_portability_library".
167     "\n".
168     "$warning_about_read_write_on_sockets",
169     "close" => '@open',
170     "read" => '@open',
171     "write" => '@open',
172
173     "socket" =>
174     "Program uses Berkeley sockets API.  Windows has a reasonable facsimile\n".
175     "called Winsock.  However it has some annoying API differences, in\n".
176     "particular: (1) You have to use WSAGetLastError instead of errno,\n".
177     "(2) error numbers have different names, (3) you cannot select on,\n".
178     "sockets, (4) a multitude of small API differences, (5) you have to\n".
179     "initialize Winsock before using it by calling WSAStartup.\n".
180     "\n".
181     "$suggest_portability_library".
182     "\n".
183     "$warning_about_read_write_on_sockets",
184     "socketpair" => '@socket',
185     "accept" => '@socket',
186     "bind" => '@socket',
187     "connect" => '@socket',
188     "listen" => '@socket',
189     "getsockopt" => '@socket',
190     "setsockopt" => '@socket',
191     "shutdown" => '@socket',
192
193     "ioctl" =>
194     "Program uses fcntl or ioctl system calls.  Only a tiny fraction of\n".
195     "the functionality of these system calls is available in Windows,\n".
196     "often with differences in semantics.\n".
197     "\n".
198     "$suggest_portability_library",
199     "fcntl" => '@ioctl',
200
201     "select" =>
202     "The select/poll/etc system calls are not available on Windows.  You\n".
203     "have to use WSAWaitForMultipleEvents instead.\n".
204     "\n".
205     "$suggest_portability_library",
206     "poll" => '@select',
207     "epoll_create" => '@select',
208     "epoll_ctl" => '@select',
209     "epoll_wait" => '@select',
210
211     "fork" =>
212     "You cannot use fork to create new processes under Windows.  You have\n".
213     "to replace calls to fork/exec with CreateProcess or CreateThread.\n".
214     "\n".
215     "If your program forks in order to run in parallel or to create\n".
216     "multiple identical workers, then you may have to restructure the\n".
217     "program.\n".
218     "\n".
219     "If your program needs to share resources such as file descriptors\n".
220     "across the fork, then some limited options are available through\n".
221     "CreateProcess, but nothing like as rich as what is available in\n".
222     "Unix.\n".
223     "\n".
224     "For server programs, we suggest using a portability library tuned\n".
225     "for the needs of servers, such as Apache Portable Runtime.\n",
226     "execl" => '@fork',
227     "execlp" => '@fork',
228     "execle" => '@fork',
229     "execv" => '@fork',
230     "execvp" => '@fork',
231     "execve" => '@fork',
232
233     "usleep" =>
234     "usleep/nanosleep system calls do not exist on Windows.  You should\n".
235     "replace this with one of the Win32 equivalents such as Sleep.\n".
236     "\n".
237     "$suggest_portability_library",
238     "nanosleep" => '@usleep',
239
240     "dup" =>
241     "dup/dup2 may not work as expected in Win32.\n".
242     "\n".
243     "$suggest_portability_library",
244     "dup2" => '@dup2',
245
246     "getopt_long" =>
247     "GNU getopt_long is not available in Windows.\n".
248     "\n".
249     "$suggest_portability_library",
250
251     "__stack_chk_fail" =>
252     "The -fstack-protector option may not work with the Fedora MinGW\n".
253     "cross-compiler at this time.\n",
254 );
255
256 # List of symbols for which there is no known problem.
257
258 my %no_report = (
259     __libc_start_main => 1,
260     _exit => 1,
261     fputc => 1,
262     free => 1,
263     fwrite => 1,
264     malloc => 1,
265     strcasecmp => 1,
266     strchr => 1,
267     strcmp => 1,
268     strtol => 1,
269 );
270
271 sub report_start
272 {
273     my $time = time ();
274     my $date = strftime "%a %b %e %H:%M:%S %Y", localtime ($time);
275     my $sym_time = $symbols{__crossreport_time};
276     my $sym_date = strftime "%a %b %e %H:%M:%S %Y", localtime ($sym_time);
277     my $days = floor (($time - $sym_time) / 86400);
278
279     print <<EOT;
280 Cross-compilation report for: $binary
281
282 Report prepared on $date.
283 Symbol database last updated on $sym_date ($days days ago).
284
285 EOT
286 }
287
288 # Report resolved libraries.
289
290 sub report_resolved
291 {
292     print <<EOT;
293 This table shows the supported APIs that this program uses,
294 including the number of different calls made to each API.
295 In most cases, you just need to arrange it so that your program
296 'BuildRequires' these RPMs and links to the libraries within them.
297
298       #calls  RPM name
299 EOT
300
301     foreach (sort (keys %api)) {
302         printf "  %10d  %s\n", $api{$_}, $_;
303     }
304
305     print "\n";
306 }
307
308 # Report unresolved symbols.
309
310 sub report_unresolved
311 {
312     @unresolved = sort @unresolved;
313
314     if (0 == @unresolved) {
315         print <<EOT;
316 No unresolved symbols were found.  Programs which have no
317 unresolved symbols at all are the easiest to port because
318 portability libraries (eg. glib, Qt) have already done all
319 the hard work for you.
320 EOT
321     } else {
322         my $nr_unresolved = @unresolved;
323         print <<EOT;
324 $nr_unresolved unresolved symbols were found.  The full list of symbols
325 is listed as an appendix at the end of this report.  In this
326 section we try to identify known portability problems from
327 this list of symbols.
328
329 EOT
330
331         foreach (@unresolved) {
332             if (!exists $no_report{$_}) {
333                 if (exists $report{$_}) {
334                     my $r = $report{$_};
335                     $r = $report{$1} while $r =~ /@(.*)/;
336                     print "Program uses: $_\n\n$r\n";
337                 }
338             }
339         }
340
341
342         print <<EOT;
343 Appendix - Full list of unresolved symbols
344
345 * = Symbol we were not able to give advice about.  If you know
346 more about this symbol, consider providing a patch for the
347 CrossReport program.
348
349 ✓ = Win32 should supply this symbol, or it can be ignored because
350 it is a side-effect of the Unix toolchain.
351
352 EOT
353
354         foreach (@unresolved) {
355             my $star =
356                 exists $no_report{$_} ? "✓" :
357                 (exists $report{$_} ? " " : "*");
358             print "\t$star $_\n"
359         }
360     }
361 }
362
363 # Main program.
364
365 sub main
366 {
367     get_options ();
368     get_db ();
369     get_symbols ();
370     report_start ();
371     report_resolved ();
372     report_unresolved ();
373 }
374
375 main ();
376
377 =pod
378
379 =head1 COPYRIGHT
380
381 Copyright (C) 2009 Red Hat Inc.
382 Written by Richard W.M. Jones <rjones@redhat.com>.
383
384 This program is free software; you can redistribute it and/or modify
385 it under the terms of the GNU General Public License as published by
386 the Free Software Foundation; either version 2 of the License, or (at
387 your option) any later version.
388
389 This program is distributed in the hope that it will be useful, but
390 WITHOUT ANY WARRANTY; without even the implied warranty of
391 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
392 General Public License for more details.
393
394 You should have received a copy of the GNU General Public License
395 along with this program; if not, write to the Free Software
396 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
397
398 =cut