blob: a44306f7db2386171c2967d7f047863fba744133 [file] [log] [blame]
Jim Cownie5e8470a2013-09-27 10:38:44 +00001#!/usr/bin/env perl
2
3#
4#//===----------------------------------------------------------------------===//
5#//
Chandler Carruth57b08b02019-01-19 10:56:40 +00006#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
7#// See https://llvm.org/LICENSE.txt for license information.
8#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Jim Cownie5e8470a2013-09-27 10:38:44 +00009#//
10#//===----------------------------------------------------------------------===//
11#
12
13# Some pragmas.
14use strict; # Restrict unsafe constructs.
15use warnings; # Enable all warnings.
16
17use FindBin;
18use lib "$FindBin::Bin/lib";
19
20use tools;
21
22our $VERSION = "0.004";
23
24#
25# Subroutines.
26#
27
28sub parse_input($\%) {
29
30 my ( $input, $defs ) = @_;
31 my @bulk = read_file( $input );
32 my %entries;
33 my %ordinals;
34 my @dirs;
35 my $value = 1;
36
37 my $error =
38 sub {
39 my ( $msg, $l, $line ) = @_;
40 runtime_error(
41 "Error parsing file \"$input\" line $l:\n" .
42 " $line" .
43 ( $msg ? $msg . "\n" : () )
44 );
45 }; # sub
46
47 my $n = 0; # Line number.
48 foreach my $line ( @bulk ) {
49 ++ $n;
50 if ( 0 ) {
51 } elsif ( $line =~ m{^\s*(?:#|\n)} ) {
52 # Empty line or comment. Skip it.
53 } elsif ( $line =~ m{^\s*%} ) {
54 # A directive.
55 if ( 0 ) {
56 } elsif ( $line =~ m{^\s*%\s*if(n)?def\s+([A-Za-z0-9_]+)\s*(?:#|\n)} ) {
57 my ( $negation, $name ) = ( $1, $2 );
58 my $dir = { n => $n, line => $line, name => $name, value => $value };
59 push( @dirs, $dir );
60 $value = ( $value and ( $negation xor $defs->{ $name } ) );
61 } elsif ( $line =~ m{^\s*%\s*endif\s*(?:#|\n)} ) {
62 if ( not @dirs ) {
63 $error->( "Orphan %endif directive.", $n, $line );
64 }; # if
65 my $dir = pop( @dirs );
66 $value = $dir->{ value };
67 } else {
68 $error->( "Bad directive.", $n, $line );
69 }; # if
70 } elsif ( $line =~ m{^\s*(-)?\s*([A-Za-z0-9_]+)(?:\s+(\d+|DATA))?\s*(?:#|\n)} ) {
71 my ( $obsolete, $entry, $ordinal ) = ( $1, $2, $3 );
72 if ( $value ) {
73 if ( exists( $entries{ $entry } ) ) {
74 $error->( "Entry \"$entry\" has already been specified.", $n, $line );
75 }; # if
76 $entries{ $entry } = { ordinal => $ordinal, obsolete => defined( $obsolete ) };
77 if ( defined( $ordinal ) and $ordinal ne "DATA" ) {
78 if ( $ordinal >= 1000 and $entry =~ m{\A[ok]mp_} ) {
79 $error->( "Ordinal of user-callable entry must be < 1000", $n, $line );
80 }; # if
81 if ( $ordinal >= 1000 and $ordinal < 2000 ) {
82 $error->( "Ordinals between 1000 and 1999 are reserved.", $n, $line );
83 }; # if
84 if ( exists( $ordinals{ $ordinal } ) ) {
85 $error->( "Ordinal $ordinal has already been used.", $n, $line );
86 }; # if
87 $ordinals{ $ordinal } = $entry;
88 }; # if
89 }; # if
90 } else {
91 $error->( "", $n, $line );
92 }; # if
93 }; # foreach
94
95 if ( @dirs ) {
96 my $dir = pop( @dirs );
Kazuaki Ishizaki4c6a0982020-01-07 14:03:31 +080097 $error->( "Unterminated %if directive.", $dir->{ n }, $dir->{ line } );
Jim Cownie5e8470a2013-09-27 10:38:44 +000098 }; # while
99
100 return %entries;
101
102}; # sub parse_input
103
104sub process(\%) {
105
106 my ( $entries ) = @_;
107
108 foreach my $entry ( keys( %$entries ) ) {
109 if ( not $entries->{ $entry }->{ obsolete } ) {
110 my $ordinal = $entries->{ $entry }->{ ordinal };
Jonathan Peytonebf18302019-04-08 17:59:28 +0000111 # omp_alloc and omp_free are C/C++ only functions, skip "1000+ordinal" for them
112 if ( $entry =~ m{\A[ok]mp_} and $entry ne "omp_alloc" and $entry ne "omp_free" ) {
Jonathan Peyton92ca6182018-09-07 18:25:49 +0000113 if ( not defined( $ordinal ) ) {
Jim Cownie5e8470a2013-09-27 10:38:44 +0000114 runtime_error(
115 "Bad entry \"$entry\": ordinal number is not specified."
116 );
117 }; # if
Jonathan Peyton92ca6182018-09-07 18:25:49 +0000118 if ( $ordinal ne "DATA" ) {
119 $entries->{ uc( $entry ) } = { ordinal => 1000 + $ordinal };
120 }
Jim Cownie5e8470a2013-09-27 10:38:44 +0000121 }; # if
122 }; # if
123 }; # foreach
124
125 return %$entries;
126
127}; # sub process
128
129sub generate_output(\%$) {
130
131 my ( $entries, $output ) = @_;
132 my $bulk;
133
134 $bulk = "EXPORTS\n";
135 foreach my $entry ( sort( keys( %$entries ) ) ) {
136 if ( not $entries->{ $entry }->{ obsolete } ) {
137 $bulk .= sprintf( " %-40s ", $entry );
138 my $ordinal = $entries->{ $entry }->{ ordinal };
139 if ( defined( $ordinal ) ) {
140 if ( $ordinal eq "DATA" ) {
141 $bulk .= "DATA";
142 } else {
143 $bulk .= "\@" . $ordinal;
144 }; # if
145 }; # if
146 $bulk .= "\n";
147 }; # if
148 }; # foreach
149 if ( defined( $output ) ) {
150 write_file( $output, \$bulk );
151 } else {
152 print( $bulk );
153 }; # if
154
155}; # sub generate_ouput
156
157#
158# Parse command line.
159#
160
161my $input; # The name of input file.
162my $output; # The name of output file.
163my %defs;
164
165get_options(
166 "output=s" => \$output,
167 "D|define=s" =>
168 sub {
169 my ( $opt_name, $opt_value ) = @_;
170 my ( $def_name, $def_value );
171 if ( $opt_value =~ m{\A(.*?)=(.*)\z} ) {
172 ( $def_name, $def_value ) = ( $1, $2 );
173 } else {
174 ( $def_name, $def_value ) = ( $opt_value, 1 );
175 }; # if
176 $defs{ $def_name } = $def_value;
177 },
178);
179
180if ( @ARGV == 0 ) {
181 cmdline_error( "Not enough arguments." );
182}; # if
183if ( @ARGV > 1 ) {
184 cmdline_error( "Too many arguments." );
185}; # if
186$input = shift( @ARGV );
187
188#
189# Work.
190#
191
192my %data = parse_input( $input, %defs );
193%data = process( %data );
194generate_output( %data, $output );
195exit( 0 );
196
197__END__
198
199#
200# Embedded documentation.
201#
202
203=pod
204
205=head1 NAME
206
207B<generate-def.pl> -- Generate def file for OpenMP RTL.
208
209=head1 SYNOPSIS
210
211B<generate-def.pl> I<OPTION>... I<file>
212
213=head1 OPTIONS
214
215=over
216
217=item B<--define=>I<name>[=I<value>]
218
219=item B<-D> I<name>[=I<value>]
220
Alp Toker8f2d3f02014-02-24 10:40:15 +0000221Define specified name. If I<value> is omitted, I<name> is defined to 1. If I<value> is 0 or empty,
Jim Cownie5e8470a2013-09-27 10:38:44 +0000222name is B<not> defined.
223
224=item B<--output=>I<file>
225
226=item B<-o> I<file>
227
228Specify output file name. If option is not present, result is printed to stdout.
229
230=item B<--doc>
231
232=item B<--manual>
233
234Print full help message and exit.
235
236=item B<--help>
237
238Print short help message and exit.
239
240=item B<--usage>
241
242Print very short usage message and exit.
243
244=item B<--verbose>
245
246Do print informational messages.
247
248=item B<--version>
249
250Print version and exit.
251
252=item B<--quiet>
253
254Work quiet, do not print informational messages.
255
256=back
257
258=head1 ARGUMENTS
259
260=over
261
262=item I<file>
263
264A name of input file.
265
266=back
267
268=head1 DESCRIPTION
269
270The script reads input file, process conditional directives, checks content for consistency, and
271generates ouptput file suitable for linker.
272
273=head2 Input File Format
274
275=over
276
277=item Comments
278
279 # It's a comment.
280
281Comments start with C<#> symbol and continue to the end of line.
282
283=item Conditional Directives
284
285 %ifdef name
286 %ifndef name
287 %endif
288
Alp Toker8f2d3f02014-02-24 10:40:15 +0000289A part of file surrounded by C<%ifdef I<name>> and C<%endif> directives is a conditional part -- it
Jim Cownie5e8470a2013-09-27 10:38:44 +0000290has effect only if I<name> is defined in the comman line by B<--define> option. C<%ifndef> is a
291negated version of C<%ifdef> -- conditional part has an effect only if I<name> is B<not> defined.
292
293Conditional parts may be nested.
294
295=item Export Definitions
296
297 symbol
298 symbol ordinal
299 symbol DATA
300
301Symbols starting with C<omp_> or C<kmp_> must have ordinal specified. They are subjects for special
302processing: each symbol generates two output lines: original one and upper case version. The ordinal
303number of the second is original ordinal increased by 1000.
304
305=item Obsolete Symbols
306
307 - symbol
308 - symbol ordinal
309 - symbol DATA
310
311Obsolete symbols look like export definitions prefixed with minus sign. Obsolete symbols do not
312affect the output, but obsolete symbols and their ordinals cannot be (re)used in export definitions.
313
314=back
315
316=head1 EXAMPLES
317
318 $ generate-def.pl -D stub -D USE_TCHECK=0 -o libguide.def dllexport
319
320=cut
321
322# end of file #
323