46b662bf83
Integrated am2dsp.pl for convenience.
1257 lines
31 KiB
Perl
Executable file
1257 lines
31 KiB
Perl
Executable file
#!/usr/bin/perl -w
|
|
|
|
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
|
|
if 0;
|
|
|
|
use strict;
|
|
use Cwd;
|
|
|
|
my $VERSION = "0.1";
|
|
my $PACKAGE = "am2dsp";
|
|
|
|
# String constants.
|
|
my $IGNORE_PATTERN = "^##([^#].*)?\$";
|
|
my $WHITE_PATTERN = "^[ \t]*\$";
|
|
my $COMMENT_PATTERN = "^#";
|
|
my $RULE_PATTERN = "^([\$a-zA-Z_.][-.a-zA-Z0-9_(){}/\$]*) *:([^=].*|)\$";
|
|
my $SUFFIX_RULE_PATTERN = "^\\.([a-zA-Z]+)\\.([a-zA-Z]+)\$";
|
|
my $MACRO_PATTERN = "^([A-Za-z][A-Za-z0-9_]*)[ \t]*([:+]?)=[ \t]*(.*)\$";
|
|
my $BOGUS_MACRO_PATTERN = "^([^ \t]*)[ \t]*([:+]?)=[ \t]*(.*)\$";
|
|
my $IF_PATTERN = "^if[ \t]+\([A-Za-z][A-Za-z0-9_]*\)[ \t]*\(#.*\)?\$";
|
|
my $ELSE_PATTERN = "^else[ \t]*\(#.*\)?\$";
|
|
my $ENDIF_PATTERN = "^endif[ \t]*\(#.*\)?\$";
|
|
my $PATH_PATTERN='(\\w|/|\\.)+';
|
|
# This will pass through anything not of the prescribed form.
|
|
my $INCLUDE_PATTERN = "^include[ \t]+((\\\$\\\(top_srcdir\\\)/${PATH_PATTERN})|(\\\$\\\(srcdir\\\)/${PATH_PATTERN})|([^/\\\$]${PATH_PATTERN}))[ \t]*(#.*)?\$";
|
|
|
|
my $AM_CONDITIONAL_PATTERN = "AM_CONDITIONAL\\((\\w+)";
|
|
my $AM_INIT_AUTOMAKE = "AM_INIT_AUTOMAKE\\(([^,]+),[ \t]*([^)]+)";
|
|
|
|
# Hash table of AM_CONDITIONAL variables seen in configure.
|
|
my %configure_cond = ();
|
|
|
|
# This holds the names which are targets. These also appear in
|
|
# %contents.
|
|
my %targets = ();
|
|
|
|
# This holds the line numbers at which various elements of
|
|
# %contents are defined.
|
|
my %content_lines = ();
|
|
|
|
my %content_seen = ();
|
|
|
|
# This maps the source extension of a suffix rule to its
|
|
# corresponding output extension.
|
|
my %suffix_rules = ();
|
|
|
|
# Hash table of discovered configure substitutions. Keys are names,
|
|
# values are `FILE:LINE' strings which are used by error message
|
|
# generation.
|
|
my %configure_vars = ();
|
|
|
|
# This holds the set of included files.
|
|
my @include_stack = ();
|
|
|
|
my $verbose = 0;
|
|
my $vcond;
|
|
my @conditional_stack = ();
|
|
my %contents = ();
|
|
my %conditional = ();
|
|
|
|
# This holds our (eventual) exit status. We don't actually exit until
|
|
# we have processed all input files.
|
|
my $exit_status = 0;
|
|
|
|
my @make_input_list = ();
|
|
my %make_list = ();
|
|
|
|
# Names used in AC_CONFIG_HEADER call. @config_fullnames holds the
|
|
# name which appears in AC_CONFIG_HEADER, colon and all.
|
|
# @config_names holds the file names. @config_headers holds the '.in'
|
|
# files. Ordinarily these are similar, but they can be different if
|
|
# the weird "NAME:FILE" syntax is used.
|
|
my @config_fullnames = ();
|
|
my @config_names = ();
|
|
my @config_headers = ();
|
|
# Line number at which AC_CONFIG_HEADER appears in configure.ac.
|
|
my $config_header_line = 0;
|
|
|
|
# Relative location of top build directory.
|
|
my $top_builddir = '';
|
|
|
|
my $relative_dir = '.';
|
|
|
|
my $output_vars = '';
|
|
my $output_trailer = '';
|
|
|
|
# List of Makefile.am's to process, and their corresponding outputs.
|
|
my @input_files = ();
|
|
my %output_files = ();
|
|
|
|
# List of files in AC_OUTPUT without Makefile.am, and their outputs.
|
|
my @other_input_files = ();
|
|
|
|
my @var_list = ();
|
|
my %am_vars = ();
|
|
my %def_type = ();
|
|
|
|
my @excluded_dirs = ();
|
|
my @excluded_files = ();
|
|
my $msvc_cflags = "";
|
|
my $msvc_cflagsd = "";
|
|
my $msvc_threads = "";
|
|
my $msvc_libs = "";
|
|
my @extra_sources = ();
|
|
my @extra_projects = ();
|
|
|
|
# Extracted from AM_INIT_AUTOMAKE(package,version)
|
|
my $dsp_package = 'FGFS';
|
|
my $dsp_version = '0.2';
|
|
|
|
my $static_lib = 0;
|
|
|
|
parse_arguments(@ARGV);
|
|
|
|
# Read project configuration file.
|
|
my $rcfile = "am2dsp.cfg";
|
|
read_am2dsprc($rcfile) if -r $rcfile;
|
|
|
|
scan_configure();
|
|
die "am2dsp: no \`Makefile.am' found or specified\n"
|
|
if ! @input_files;
|
|
|
|
if ($static_lib) {
|
|
static_lib_dsp_init($dsp_package);
|
|
} else {
|
|
console_app_dsp_init($dsp_package);
|
|
}
|
|
|
|
my $am_file;
|
|
foreach $am_file (@input_files) {
|
|
dsp_add_group($dsp_package, $am_file) if !exclude_dir($am_file);
|
|
}
|
|
dsp_finish($dsp_package);
|
|
generate_dsw( $dsp_package );
|
|
|
|
sub exclude_dir {
|
|
my $dir = shift;
|
|
foreach my $d (@excluded_dirs) {
|
|
if ($dir =~ "/$d/") {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
sub exclude_file {
|
|
my $file = shift;
|
|
foreach my $f (@excluded_files) {
|
|
if ($file =~ /$f/) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#
|
|
# TODO: option to specify static library or console app.
|
|
#
|
|
sub parse_arguments {
|
|
my @av = @_;
|
|
|
|
while (@av) {
|
|
if ($av[0] eq '--version') {
|
|
} elsif ($av[0] eq '--help') {
|
|
} elsif ($av[0] eq '--verbose' || $av[0] eq '-v') {
|
|
$verbose = 1;
|
|
} elsif ($av[0] eq '--package' || $av[0] eq '-p') {
|
|
require_argument(@av);
|
|
shift @av;
|
|
$dsp_package = $av[0];
|
|
} elsif ($av[0] eq '--lib' || $av[0] eq '-l') {
|
|
# Create a static library
|
|
$static_lib = 1;
|
|
} elsif ($av[0] =~ /^-/) {
|
|
die "am2dsp: unrecognised option -- `$av[0]'\nTry am2dsp --help for more information.\n";
|
|
} else {
|
|
}
|
|
shift @av;
|
|
}
|
|
}
|
|
|
|
sub read_am2dsprc {
|
|
my $rc_file = shift;
|
|
|
|
open( RC_FILE, $rc_file )
|
|
or die "Can't open $rc_file: $!\n";
|
|
my $line;
|
|
while (defined($line = <RC_FILE>)) {
|
|
chomp $line;
|
|
if ($line =~ s/\\$//) {
|
|
# continuation line
|
|
$line .= "%";
|
|
$line .= <RC_FILE>;
|
|
redo unless eof(RC_FILE);
|
|
}
|
|
|
|
next if $line =~ /^$/; # ignore blank lines
|
|
next if $line =~ /^#/; # ignore comments
|
|
|
|
if ($line =~ /exclude_dir\s*=\s*(\S+)/) {
|
|
push( @excluded_dirs, $1 );
|
|
}
|
|
elsif ($line =~ /exclude_file\s*=\s*(\S+)/) {
|
|
my $f;
|
|
($f = $1) =~ s/\\/\\\\/g; # escape path separators, "\" -> "\\"
|
|
push( @excluded_files, $f );
|
|
print "Excluding file: $f\n" if $verbose;
|
|
}
|
|
elsif ($line =~ /include_path\s*=\s*\"(.*)\"/) {
|
|
$msvc_cflags .= " /I \"$1\"";
|
|
$msvc_cflagsd .= " /I \"$1\"";
|
|
}
|
|
elsif ($line =~ /include_path\s*=\s*(\S+)/) {
|
|
$msvc_cflags .= " /I \"$1\"";
|
|
$msvc_cflagsd .= " /I \"$1\"";
|
|
}
|
|
elsif ($line =~ /define\s*=\s*(\S+)/) {
|
|
$msvc_cflags .= " /D \"$1\"";
|
|
$msvc_cflagsd .= " /D \"$1\"";
|
|
}
|
|
elsif ($line =~ /lib_path\s*=\s*(\S+)/) {
|
|
$msvc_libs .= " /libpath:\"$1\"";
|
|
}
|
|
elsif ($line =~ /add_lib\s*=\s*(\S+)/) {
|
|
$msvc_libs .= " $1.lib";
|
|
}
|
|
elsif ($line =~ /type\s*=\s*(\S+)/) {
|
|
my ($type,$threads,$debug) = split /,/, $1;
|
|
print "type=$type, threading=$threads, debug=$debug\n" if $verbose;
|
|
if ($type =~ "ConsoleApplication") {
|
|
$static_lib = 0
|
|
}
|
|
elsif ($type =~ "StaticLibrary") {
|
|
$static_lib = 1
|
|
}
|
|
else {
|
|
# Invalid type
|
|
}
|
|
|
|
my $flags = " /ML"; # single threaded.
|
|
if ($threads =~ /MultithreadedDLL/) {
|
|
$flags = " /MD";
|
|
}
|
|
elsif ($threads =~ /Multithreaded/) {
|
|
$flags = " /MT";
|
|
}
|
|
elsif ($threads =~ /Singlethreaded/) {
|
|
$flags = " /ML";
|
|
}
|
|
else {
|
|
# Invalid threading option.
|
|
}
|
|
|
|
$msvc_cflags .= $flags;
|
|
$flags .= "d";
|
|
$msvc_cflagsd .= $flags;
|
|
}
|
|
elsif ($line =~ /add_source_file\s*=\s*(.*)/) {
|
|
my $rule;
|
|
($rule = $1) =~ s/%/\r\n/g;
|
|
push( @extra_sources, $rule );
|
|
}
|
|
elsif ($line =~ /add_project\s*=\s*(.*)/) {
|
|
push( @extra_projects, $1 );
|
|
}
|
|
}
|
|
close(RC_FILE);
|
|
}
|
|
|
|
# Ensure argument exists, or die.
|
|
sub require_argument
|
|
{
|
|
my ($arg, @arglist) = @_;
|
|
die "am2dsp: no argument given for option \`$arg'\n"
|
|
if ! @arglist;
|
|
}
|
|
|
|
sub scan_configure {
|
|
scan_one_configure_file('configure.ac');
|
|
scan_one_configure_file('aclocal.m4')
|
|
if -f 'aclocal.m4';
|
|
|
|
if (! @input_files) {
|
|
@input_files = @make_input_list;
|
|
%output_files = %make_list;
|
|
}
|
|
}
|
|
|
|
sub scan_one_configure_file {
|
|
my $filename = shift;
|
|
open(CONFIGURE, $filename)
|
|
|| die "am2dsp: can't open \`$filename': $!\n";
|
|
print "am2dsp: reading $filename\n" if $verbose;
|
|
|
|
my $in_ac_output = 0;
|
|
my $ac_output_line = '';
|
|
|
|
while (<CONFIGURE>) {
|
|
# Remove comments from current line.
|
|
s/\bdnl\b.*$//;
|
|
s/\#.*$//;
|
|
|
|
# Skip macro definitions. Otherwise we might be confused into
|
|
# thinking that a macro that was only defined was actually
|
|
# used.
|
|
next if /AC_DEFUN/;
|
|
|
|
# Follow includes. This is a weirdness commonly in use at
|
|
# Cygnus and hopefully nowhere else.
|
|
if (/sinclude\((.*)\)/ && -f $1)
|
|
{
|
|
&scan_one_configure_file ($1);
|
|
}
|
|
|
|
if (! $in_ac_output && ( s/AC_OUTPUT\s*\(\[?// || s/AC_CONFIG_FILES\s*\(\[?// ) ) {
|
|
$in_ac_output = 1;
|
|
$ac_output_line = $.;
|
|
}
|
|
|
|
if ($in_ac_output)
|
|
{
|
|
my $closing = 0;
|
|
if (s/[\]\),].*$//)
|
|
{
|
|
$in_ac_output = 0;
|
|
$closing = 1;
|
|
}
|
|
|
|
# Look at potential Makefile.am's
|
|
foreach (split)
|
|
{
|
|
# Must skip empty string for Perl 4.
|
|
next if $_ eq "\\" || $_ eq '';
|
|
|
|
my ($local,$input,@rest) = split(/:/);
|
|
if (! $input)
|
|
{
|
|
$input = $local;
|
|
}
|
|
else
|
|
{
|
|
$input =~ s/\.in$//;
|
|
}
|
|
|
|
if (-f $input . '.am')
|
|
{
|
|
push(@make_input_list, $input);
|
|
$make_list{$input} = join(':', ($local,@rest));
|
|
}
|
|
else
|
|
{
|
|
# We have a file that automake should cause to be
|
|
# rebuilt, but shouldn't generate itself.
|
|
push (@other_input_files, $_);
|
|
}
|
|
}
|
|
}
|
|
|
|
# Handle configuration headers. A config header of `[$1]'
|
|
# means we are actually scanning AM_CONFIG_HEADER from
|
|
# aclocal.m4.
|
|
if (/A([CM])_CONFIG_HEADER\s*\((.*)\)/
|
|
&& $2 ne '[$1]')
|
|
{
|
|
&am_conf_line_error
|
|
($filename, $., "\`automake requires \`AM_CONFIG_HEADER', not \`AC_CONFIG_HEADER'")
|
|
if $1 eq 'C';
|
|
|
|
$config_header_line = $.;
|
|
my ($one_hdr);
|
|
foreach $one_hdr (split (' ', $2))
|
|
{
|
|
push (@config_fullnames, $one_hdr);
|
|
if ($one_hdr =~ /^([^:]+):(.+)$/)
|
|
{
|
|
push (@config_names, $1);
|
|
push (@config_headers, $2);
|
|
}
|
|
else
|
|
{
|
|
push (@config_names, $one_hdr);
|
|
push (@config_headers, $one_hdr . '.in');
|
|
}
|
|
}
|
|
}
|
|
|
|
if (/$AM_CONDITIONAL_PATTERN/o)
|
|
{
|
|
$configure_cond{$1} = 1;
|
|
}
|
|
|
|
if (/$AM_INIT_AUTOMAKE/o)
|
|
{
|
|
$dsp_package = $1;
|
|
$dsp_version = $2;
|
|
}
|
|
}
|
|
|
|
close(CONFIGURE);
|
|
}
|
|
|
|
sub read_main_am_file {
|
|
$am_file = shift;
|
|
|
|
read_am_file($am_file);
|
|
|
|
my @topdir = ();
|
|
foreach (split(/\//, $relative_dir)) {
|
|
next if $_ eq '.' || $_ eq '';
|
|
if ($_ eq '..') {
|
|
pop @topdir;
|
|
} else {
|
|
push(@topdir, '..');
|
|
}
|
|
}
|
|
@topdir = ('.') if ! @topdir;
|
|
|
|
my $top_builddir = join('/', @topdir);
|
|
|
|
}
|
|
|
|
sub read_am_file {
|
|
$am_file = shift;
|
|
open( AM_FILE, $am_file )
|
|
or die "Can't open $am_file: $!\n";
|
|
print "am2dsp: reading $am_file\n" if $verbose;
|
|
|
|
my $saw_bk = 0;
|
|
my $was_rule = 0;
|
|
my $spacing = '';
|
|
my $comment = '';
|
|
my $last_var_name = '';
|
|
my $blank = 0;
|
|
|
|
while (<AM_FILE>)
|
|
{
|
|
if (/$IGNORE_PATTERN/o)
|
|
{
|
|
# Merely delete comments beginning with two hashes.
|
|
}
|
|
elsif (/$WHITE_PATTERN/o)
|
|
{
|
|
# Stick a single white line before the incoming macro or rule.
|
|
$spacing = "\n";
|
|
$blank = 1;
|
|
}
|
|
elsif (/$COMMENT_PATTERN/o)
|
|
{
|
|
# Stick comments before the incoming macro or rule. Make
|
|
# sure a blank line preceeds first block of comments.
|
|
$spacing = "\n" unless $blank;
|
|
$blank = 1;
|
|
$comment .= $spacing . $_;
|
|
$spacing = '';
|
|
}
|
|
else
|
|
{
|
|
last;
|
|
}
|
|
}
|
|
|
|
$output_vars .= $comment . "\n";
|
|
$comment = '';
|
|
$spacing = "\n";
|
|
my $source_suffix_pattern = '';
|
|
|
|
my $is_ok_macro = 0;
|
|
while ($_)
|
|
{
|
|
$_ .= "\n"
|
|
unless substr ($_, -1, 1) eq "\n";
|
|
|
|
if (/$IGNORE_PATTERN/o)
|
|
{
|
|
# Merely delete comments beginning with two hashes.
|
|
}
|
|
elsif (/$WHITE_PATTERN/o)
|
|
{
|
|
# Stick a single white line before the incoming macro or rule.
|
|
$spacing = "\n";
|
|
&am_line_error ($., "blank line following trailing backslash")
|
|
if $saw_bk;
|
|
}
|
|
elsif (/$COMMENT_PATTERN/o)
|
|
{
|
|
# Stick comments before the incoming macro or rule.
|
|
$comment .= $spacing . $_;
|
|
$spacing = '';
|
|
&am_line_error ($., "comment following trailing backslash")
|
|
if $saw_bk;
|
|
}
|
|
elsif ($saw_bk)
|
|
{
|
|
if ($was_rule)
|
|
{
|
|
$output_trailer .= join ('', @conditional_stack) . $_;
|
|
$saw_bk = /\\$/;
|
|
}
|
|
else
|
|
{
|
|
$saw_bk = /\\$/;
|
|
# Chop newline and backslash if this line is
|
|
# continued. ensure trailing whitespace exists.
|
|
chop if $saw_bk;
|
|
chop if $saw_bk;
|
|
$contents{$last_var_name} .= ' '
|
|
unless $contents{$last_var_name} =~ /\s$/;
|
|
$contents{$last_var_name} .= $_;
|
|
if (@conditional_stack)
|
|
{
|
|
$conditional{$last_var_name} .= "e_cond_val ($_);
|
|
}
|
|
}
|
|
}
|
|
elsif (/$IF_PATTERN/o)
|
|
{
|
|
&am_line_error ($., "$1 does not appear in AM_CONDITIONAL")
|
|
if (! $configure_cond{$1});
|
|
push (@conditional_stack, "\@" . $1 . "_TRUE\@");
|
|
}
|
|
elsif (/$ELSE_PATTERN/o)
|
|
{
|
|
if (! @conditional_stack)
|
|
{
|
|
&am_line_error ($., "else without if");
|
|
}
|
|
elsif ($conditional_stack[$#conditional_stack] =~ /_FALSE\@$/)
|
|
{
|
|
&am_line_error ($., "else after else");
|
|
}
|
|
else
|
|
{
|
|
$conditional_stack[$#conditional_stack]
|
|
=~ s/_TRUE\@$/_FALSE\@/;
|
|
}
|
|
}
|
|
elsif (/$ENDIF_PATTERN/o)
|
|
{
|
|
if (! @conditional_stack)
|
|
{
|
|
&am_line_error ($., ": endif without if");
|
|
}
|
|
else
|
|
{
|
|
pop @conditional_stack;
|
|
}
|
|
}
|
|
elsif (/$RULE_PATTERN/o)
|
|
{
|
|
# Found a rule.
|
|
$was_rule = 1;
|
|
if (defined $contents{$1}
|
|
&& (@conditional_stack
|
|
? ! defined $conditional{$1}
|
|
: defined $conditional{$1}))
|
|
{
|
|
&am_line_error ($1,
|
|
"$1 defined both conditionally and unconditionally");
|
|
}
|
|
# Value here doesn't matter; for targets we only note
|
|
# existence.
|
|
$contents{$1} = 1;
|
|
$targets{$1} = 1;
|
|
my $cond_string = join ('', @conditional_stack);
|
|
if (@conditional_stack)
|
|
{
|
|
if ($conditional{$1})
|
|
{
|
|
&check_ambiguous_conditional ($1, $cond_string);
|
|
$conditional{$1} .= ' ';
|
|
}
|
|
else
|
|
{
|
|
$conditional{$1} = '';
|
|
}
|
|
$conditional{$1} .= $cond_string . ' 1';
|
|
}
|
|
$content_lines{$1} = $.;
|
|
$output_trailer .= $comment . $spacing . $cond_string . $_;
|
|
$comment = $spacing = '';
|
|
$saw_bk = /\\$/;
|
|
|
|
# Check the rule for being a suffix rule. If so, store in
|
|
# a hash.
|
|
|
|
my $source_suffix;
|
|
my $object_suffix;
|
|
|
|
if (($source_suffix, $object_suffix) = ($1 =~ $SUFFIX_RULE_PATTERN))
|
|
{
|
|
$suffix_rules{$source_suffix} = $object_suffix;
|
|
print "Sources ending in .$source_suffix become .$object_suffix\n" if $verbose;
|
|
$source_suffix_pattern = "(" . join('|', keys %suffix_rules) . ")";
|
|
}
|
|
|
|
# FIXME: make sure both suffixes are in SUFFIXES? Or set
|
|
# SUFFIXES from suffix_rules?
|
|
}
|
|
elsif (($is_ok_macro = /$MACRO_PATTERN/o)
|
|
|| /$BOGUS_MACRO_PATTERN/o)
|
|
{
|
|
# Found a macro definition.
|
|
$was_rule = 0;
|
|
$last_var_name = $1;
|
|
if (defined $contents{$1}
|
|
&& (@conditional_stack
|
|
? ! defined $conditional{$1}
|
|
: defined $conditional{$1}))
|
|
{
|
|
&am_line_error ($1,
|
|
"$1 defined both conditionally and unconditionally");
|
|
}
|
|
my $value;
|
|
if ($3 ne '' && substr ($3, -1) eq "\\")
|
|
{
|
|
$value = substr ($3, 0, length ($3) - 1);
|
|
}
|
|
else
|
|
{
|
|
$value = $3;
|
|
}
|
|
my $type = $2;
|
|
if ($type eq '+')
|
|
{
|
|
if (! defined $contents{$last_var_name}
|
|
&& defined $configure_vars{$last_var_name})
|
|
{
|
|
$contents{$last_var_name} = '@' . $last_var_name . '@';
|
|
}
|
|
$contents{$last_var_name} .= ' ' . $value;
|
|
}
|
|
else
|
|
{
|
|
$contents{$last_var_name} = $value;
|
|
# The first assignment to a macro sets the line
|
|
# number. Ideally I suppose we would associate line
|
|
# numbers with random bits of text.
|
|
$content_lines{$last_var_name} = $.;
|
|
}
|
|
my $cond_string = join ('', @conditional_stack);
|
|
if (@conditional_stack)
|
|
{
|
|
my $found = 0;
|
|
my $val;
|
|
if ($conditional{$last_var_name})
|
|
{
|
|
if ($type eq '+')
|
|
{
|
|
# If we're adding to the conditional, and it
|
|
# exists, then we might want to simply replace
|
|
# the old value with the new one.
|
|
my (@new_vals, @cond_vals);
|
|
@cond_vals = split (' ', $conditional{$last_var_name});
|
|
while (@cond_vals)
|
|
{
|
|
$vcond = shift (@cond_vals);
|
|
push (@new_vals, $vcond);
|
|
if (&conditional_same ($vcond, $cond_string))
|
|
{
|
|
$found = 1;
|
|
$val = (&unquote_cond_val (shift (@cond_vals))
|
|
. ' ' . $value);
|
|
push (@new_vals, "e_cond_val ($val));
|
|
}
|
|
else
|
|
{
|
|
push (@new_vals, shift (@cond_vals));
|
|
}
|
|
}
|
|
if ($found)
|
|
{
|
|
$conditional{$last_var_name}
|
|
= join (' ', @new_vals);
|
|
}
|
|
}
|
|
|
|
if (! $found)
|
|
{
|
|
&check_ambiguous_conditional ($last_var_name,
|
|
$cond_string);
|
|
$conditional{$last_var_name} .= ' ';
|
|
$val = $value;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$conditional{$last_var_name} = '';
|
|
$val = $contents{$last_var_name};
|
|
}
|
|
if (! $found)
|
|
{
|
|
$conditional{$last_var_name} .= ($cond_string
|
|
. ' '
|
|
. "e_cond_val ($val));
|
|
}
|
|
}
|
|
# FIXME: this doesn't always work correctly; it will group
|
|
# all comments for a given variable, no matter where
|
|
# defined.
|
|
$am_vars{$last_var_name} = $comment . $spacing;
|
|
$def_type{$last_var_name} = ($type eq ':') ? ':' : '';
|
|
push (@var_list, $last_var_name);
|
|
$comment = $spacing = '';
|
|
$saw_bk = /\\$/;
|
|
|
|
# Error if bogus.
|
|
&am_line_error ($., "bad macro name \`$last_var_name'")
|
|
if ! $is_ok_macro;
|
|
}
|
|
elsif (/$INCLUDE_PATTERN/o)
|
|
{
|
|
my ($path) = $1;
|
|
|
|
if ($path =~ s/^\$\(top_srcdir\)\///)
|
|
{
|
|
push (@include_stack, "\$\(top_srcdir\)/$path");
|
|
}
|
|
else
|
|
{
|
|
$path =~ s/\$\(srcdir\)\///;
|
|
push (@include_stack, "\$\(srcdir\)/$path");
|
|
$path = $relative_dir . "/" . $path;
|
|
}
|
|
&read_am_file ($path);
|
|
}
|
|
else
|
|
{
|
|
# This isn't an error; it is probably a continued rule.
|
|
# In fact, this is what we assume.
|
|
$was_rule = 1;
|
|
$output_trailer .= ($comment . $spacing
|
|
. join ('', @conditional_stack) . $_);
|
|
$comment = $spacing = '';
|
|
$saw_bk = /\\$/;
|
|
}
|
|
|
|
$_ = <AM_FILE>;
|
|
}
|
|
|
|
close(AM_FILE);
|
|
$output_trailer .= $comment;
|
|
|
|
&am_error ("unterminated conditionals: " . join (' ', @conditional_stack))
|
|
if (@conditional_stack);
|
|
}
|
|
|
|
sub initialize_per_input {
|
|
# These two variables are used when generating each Makefile.in.
|
|
# They hold the Makefile.in until it is ready to be printed.
|
|
$output_vars = '';
|
|
$output_trailer = '';
|
|
|
|
# This holds the contents of a Makefile.am, as parsed by
|
|
# read_am_file.
|
|
%contents = ();
|
|
|
|
# This holds the names which are targets. These also appear in
|
|
# %contents.
|
|
%targets = ();
|
|
|
|
# For a variable or target which is defined conditionally, this
|
|
# holds an array of the conditional values. The array is composed
|
|
# of pairs of condition strings (the variables which configure
|
|
# will substitute) and values (the value of a target is
|
|
# meaningless). For an unconditional variable, this is empty.
|
|
%conditional = ();
|
|
|
|
# This holds the line numbers at which various elements of
|
|
# %contents are defined.
|
|
%content_lines = ();
|
|
|
|
# This holds a 1 if a particular variable was examined.
|
|
%content_seen = ();
|
|
|
|
# This is the conditional stack.
|
|
@conditional_stack = ();
|
|
|
|
# This holds the set of included files.
|
|
@include_stack = ();
|
|
|
|
# This holds the "relative directory" of the current Makefile.in.
|
|
# Eg for src/Makefile.in, this is "src".
|
|
$relative_dir = '';
|
|
|
|
# This maps the source extension of a suffix rule to its
|
|
# corresponding output extension.
|
|
%suffix_rules = ();
|
|
|
|
}
|
|
|
|
# Quote a value in order to put it in $conditional. We need to quote
|
|
# spaces, and we need to handle null strings, so that we can later
|
|
# retrieve values by splitting on space.
|
|
sub quote_cond_val
|
|
{
|
|
my ($val) = @_;
|
|
$val =~ s/ /\001/g;
|
|
$val =~ s/\t/\003/g;
|
|
$val = "\002" if $val eq '';
|
|
return $val;
|
|
}
|
|
|
|
# See if a conditional is true. Both arguments are conditional
|
|
# strings. This returns true if the first conditional is true when
|
|
# the second conditional is true.
|
|
sub conditional_true_when
|
|
{
|
|
my ($cond, $when) = @_;
|
|
|
|
# Check the easy case first.
|
|
if ($cond eq $when)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
# Check each component of $cond, which looks @COND1@@COND2@.
|
|
foreach my $comp (split ('@', $cond))
|
|
{
|
|
# The way we split will give null strings between each
|
|
# condition.
|
|
next if ! $comp;
|
|
|
|
if (index ($when, '@' . $comp . '@') == -1)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
# Check for an ambiguous conditional. This is called when a variable
|
|
# or target is being defined conditionally. If we already know about
|
|
# a definition that is true under the same conditions, then we have an
|
|
# ambiguity.
|
|
sub check_ambiguous_conditional
|
|
{
|
|
my ($var_name, $cond) = @_;
|
|
my (@cond_vals) = split (' ', $conditional{$var_name});
|
|
while (@cond_vals)
|
|
{
|
|
my ($vcond) = shift (@cond_vals);
|
|
shift (@cond_vals);
|
|
if (&conditional_true_when ($vcond, $cond)
|
|
|| &conditional_true_when ($cond, $vcond))
|
|
{
|
|
print "$var_name multiply defined in condition";
|
|
}
|
|
}
|
|
}
|
|
|
|
sub am_line_error
|
|
{
|
|
my ($symbol, @args) = @_;
|
|
|
|
if ($symbol && "$symbol" ne '-1')
|
|
{
|
|
my ($file) = "${am_file}";
|
|
|
|
if ($symbol =~ /^\d+$/)
|
|
{
|
|
# SYMBOL is a line number, so just add the colon.
|
|
$file .= ':' . $symbol;
|
|
}
|
|
elsif (defined $content_lines{$symbol})
|
|
{
|
|
# SYMBOL is a variable defined in Makefile.am, so add the
|
|
# line number we saved from there.
|
|
$file .= ':' . $content_lines{$symbol};
|
|
}
|
|
elsif (defined $configure_vars{$symbol})
|
|
{
|
|
# SYMBOL is a variable defined in configure.ac, so add the
|
|
# appropriate line number.
|
|
$file = $configure_vars{$symbol};
|
|
}
|
|
else
|
|
{
|
|
# Couldn't find the line number.
|
|
}
|
|
warn $file, ": ", join (' ', @args), "\n";
|
|
$exit_status = 1;
|
|
}
|
|
else
|
|
{
|
|
&am_error (@args);
|
|
}
|
|
}
|
|
|
|
sub generate_dsw
|
|
{
|
|
my $name = shift;
|
|
my $dsw_name = $name . '.dsw';
|
|
open(DSW, ">$dsw_name")
|
|
|| die "Can't create $dsw_name: $!\n";
|
|
|
|
print "Creating $dsw_name\n" if $verbose;
|
|
|
|
print DSW <<"EOF";
|
|
Microsoft Developer Studio Workspace File, Format Version 6.00\r
|
|
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r
|
|
\r
|
|
###############################################################################\r
|
|
\r
|
|
EOF
|
|
print DSW 'Project: ', "\"$name\"=\".\\", $name, ".dsp\" - Package Owner=<4>\r\n";
|
|
print DSW <<"EOF";
|
|
\r
|
|
Package=<5>\r
|
|
{{{\r
|
|
}}}\r
|
|
\r
|
|
Package=<4>\r
|
|
{{{\r
|
|
}}}\r
|
|
\r
|
|
EOF
|
|
|
|
foreach my $p (@extra_projects) {
|
|
print DSW "###############################################################################\r\n\r\n";
|
|
my ($dsp,$name) = split ',', $p;
|
|
print "Project $name=$dsp\n" if $verbose;
|
|
print DSW "Project: \"$name\"=\"$dsp\" - Package Owner=<4>\r\n\r\n";
|
|
print DSW <<"EOF";
|
|
Package=<5>\r
|
|
{{{\r
|
|
}}}\r
|
|
\r
|
|
Package=<4>\r
|
|
{{{\r
|
|
}}}\r
|
|
\r
|
|
EOF
|
|
}
|
|
|
|
print DSW <<"EOF";
|
|
###############################################################################\r
|
|
\r
|
|
Global:\r
|
|
\r
|
|
Package=<5>\r
|
|
{{{\r
|
|
}}}\r
|
|
\r
|
|
Package=<3>\r
|
|
{{{\r
|
|
}}}\r
|
|
\r
|
|
###############################################################################\r
|
|
\r
|
|
EOF
|
|
close(DSW);
|
|
}
|
|
|
|
sub expand_here {
|
|
local $_ = shift;
|
|
s/\%cflags\%/$msvc_cflags/g;
|
|
s/\%cflagsd\%/$msvc_cflagsd/g;
|
|
s/\%libs\%/$msvc_libs/g;
|
|
return $_;
|
|
}
|
|
|
|
sub console_app_dsp_init
|
|
{
|
|
my $name = shift;
|
|
my $dsp_name = $name . '.dsp';
|
|
|
|
open(DSP, ">$dsp_name")
|
|
|| die "Can't create $dsp_name: $!\n";
|
|
|
|
print "Creating $dsp_name\n" if $verbose;
|
|
|
|
print DSP expand_here(<<"EOF");
|
|
# Microsoft Developer Studio Project File - Name="$name" - Package Owner=<4>\r
|
|
# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
|
|
# ** DO NOT EDIT **\r
|
|
\r
|
|
# TARGTYPE "Win32 (x86) Console Application" 0x0103\r
|
|
\r
|
|
CFG=$name - Win32 Debug\r
|
|
!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
|
|
!MESSAGE use the Export Makefile command and run\r
|
|
!MESSAGE \r
|
|
!MESSAGE NMAKE /f "$name.mak".\r
|
|
!MESSAGE \r
|
|
!MESSAGE You can specify a configuration when running NMAKE\r
|
|
!MESSAGE by defining the macro CFG on the command line. For example:\r
|
|
!MESSAGE \r
|
|
!MESSAGE NMAKE /f "$name.mak" CFG="$name - Win32 Debug"\r
|
|
!MESSAGE \r
|
|
!MESSAGE Possible choices for configuration are:\r
|
|
!MESSAGE \r
|
|
!MESSAGE "$name - Win32 Release" (based on "Win32 (x86) Console Application")\r
|
|
!MESSAGE "$name - Win32 Debug" (based on "Win32 (x86) Console Application")\r
|
|
!MESSAGE \r
|
|
\r
|
|
# Begin Project\r
|
|
# PROP AllowPerConfigDependencies 0\r
|
|
# PROP Scc_ProjName ""\r
|
|
# PROP Scc_LocalPath ""\r
|
|
CPP=cl.exe\r
|
|
RSC=rc.exe\r
|
|
\r
|
|
!IF "\$(CFG)" == "$name - Win32 Release"\r
|
|
\r
|
|
# PROP Use_MFC 0\r
|
|
# PROP Use_Debug_Libraries 0\r
|
|
# PROP Output_Dir "Release"\r
|
|
# PROP Intermediate_Dir "Release"\r
|
|
# PROP Target_Dir ""\r
|
|
# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c %cflags%\r
|
|
# SUBTRACT CPP /YX\r
|
|
# ADD RSC /l 0xc09 /d "NDEBUG"\r
|
|
BSC32=bscmake.exe\r
|
|
# ADD BSC32 /nologo\r
|
|
LINK32=link.exe\r
|
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib uuid.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 %libs%\r
|
|
\r
|
|
!ELSEIF "\$(CFG)" == "$name - Win32 Debug"\r
|
|
\r
|
|
# PROP Use_MFC 0\r
|
|
# PROP Use_Debug_Libraries 1\r
|
|
# PROP Output_Dir "Debug"\r
|
|
# PROP Intermediate_Dir "Debug"\r
|
|
# PROP Ignore_Export_Lib 0\r
|
|
# PROP Target_Dir ""\r
|
|
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c %cflagsd%\r
|
|
# ADD RSC /l 0xc09 /d "_DEBUG"\r
|
|
BSC32=bscmake.exe\r
|
|
# ADD BSC32 /nologo\r
|
|
LINK32=link.exe\r
|
|
# ADD LINK32 kernel32.lib user32.lib winspool.lib comdlg32.lib gdi32.lib shell32.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept %libs%\r
|
|
\r
|
|
!ENDIF \r
|
|
\r
|
|
# Begin Target\r
|
|
\r
|
|
# Name "$name - Win32 Release"\r
|
|
# Name "$name - Win32 Debug"\r
|
|
EOF
|
|
|
|
close(DSP);
|
|
}
|
|
|
|
sub static_lib_dsp_init
|
|
{
|
|
my $name = shift;
|
|
my $dsp_name = $name . '.dsp';
|
|
|
|
open(DSP, ">$dsp_name")
|
|
|| die "Can't create $dsp_name: $!\n";
|
|
|
|
print "Creating $dsp_name\n" if $verbose;
|
|
|
|
print DSP expand_here(<<"EOF");
|
|
# Microsoft Developer Studio Project File - Name="$name" - Package Owner=<4>\r
|
|
# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
|
|
# ** DO NOT EDIT **\r
|
|
\r
|
|
# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
|
|
\r
|
|
CFG=$name - Win32 Debug\r
|
|
!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
|
|
!MESSAGE use the Export Makefile command and run\r
|
|
!MESSAGE \r
|
|
!MESSAGE NMAKE /f "$name.mak".\r
|
|
!MESSAGE \r
|
|
!MESSAGE You can specify a configuration when running NMAKE\r
|
|
!MESSAGE by defining the macro CFG on the command line. For example:\r
|
|
!MESSAGE \r
|
|
!MESSAGE NMAKE /f "$name.mak" CFG="$name - Win32 Debug"\r
|
|
!MESSAGE \r
|
|
!MESSAGE Possible choices for configuration are:\r
|
|
!MESSAGE \r
|
|
!MESSAGE "$name - Win32 Release" (based on "Win32 (x86) Static Library")\r
|
|
!MESSAGE "$name - Win32 Debug" (based on "Win32 (x86) Static Library")\r
|
|
!MESSAGE \r
|
|
\r
|
|
# Begin Project\r
|
|
# PROP AllowPerConfigDependencies 0\r
|
|
# PROP Scc_ProjName ""\r
|
|
# PROP Scc_LocalPath ""\r
|
|
CPP=cl.exe\r
|
|
RSC=rc.exe\r
|
|
\r
|
|
!IF "\$(CFG)" == "$name - Win32 Release"\r
|
|
\r
|
|
# PROP Use_MFC 0\r
|
|
# PROP Use_Debug_Libraries 0\r
|
|
# PROP Output_Dir "Release"\r
|
|
# PROP Intermediate_Dir "Release"\r
|
|
# PROP Target_Dir ""\r
|
|
# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_MBCS" /FD /c %cflags%\r
|
|
# ADD RSC /l 0x409 /d "NDEBUG"\r
|
|
BSC32=bscmake.exe\r
|
|
# ADD BASE BSC32 /nologo\r
|
|
# ADD BSC32 /nologo\r
|
|
LINK32=link.exe -lib\r
|
|
# ADD BASE LIB32 /nologo\r
|
|
# ADD LIB32 /nologo\r
|
|
\r
|
|
!ELSEIF "\$(CFG)" == "$name - Win32 Debug"\r
|
|
\r
|
|
# PROP Use_MFC 0\r
|
|
# PROP Use_Debug_Libraries 1\r
|
|
# PROP Output_Dir "Debug"\r
|
|
# PROP Intermediate_Dir "Debug"\r
|
|
# PROP Target_Dir ""\r
|
|
# ADD CPP /nologo /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_MBCS" /FR /FD /GZ /c %cflagsd%\r
|
|
# ADD RSC /l 0x409 /d "_DEBUG"\r
|
|
BSC32=bscmake.exe\r
|
|
# ADD BASE BSC32 /nologo\r
|
|
# ADD BSC32 /nologo\r
|
|
LINK32=link.exe -lib\r
|
|
# ADD BASE LIB32 /nologo\r
|
|
# ADD LIB32 /nologo\r
|
|
\r
|
|
!ENDIF \r
|
|
\r
|
|
# Begin Target\r
|
|
\r
|
|
# Name "$name - Win32 Release"\r
|
|
# Name "$name - Win32 Debug"\r
|
|
EOF
|
|
|
|
close(DSP);
|
|
}
|
|
|
|
sub dsp_add_source_rule {
|
|
my ($fh,$dsp_name,$group,$file) = @_;
|
|
print $fh "# Begin Source File\r\n";
|
|
print $fh "\r\n";
|
|
print $fh "SOURCE=$file\r\n";
|
|
print $fh "\r\n";
|
|
print $fh "!IF \"\$(CFG)\" == \"$dsp_name - Win32 Release\"\r\n";
|
|
print $fh "\r\n";
|
|
print $fh "# PROP Intermediate_Dir \"Release\\$group\"\r\n";
|
|
print $fh "# PROP Exclude_From_Build 1\r\n" if exclude_file($file);
|
|
print $fh "\r\n";
|
|
print $fh "!ELSEIF \"\$(CFG)\" == \"$dsp_name - Win32 Debug\"\r\n";
|
|
print $fh "\r\n";
|
|
print $fh "# PROP Intermediate_Dir \"Debug\\$group\"\r\n";
|
|
print $fh "# PROP Exclude_From_Build 1\r\n" if exclude_file($file);
|
|
print $fh "\r\n";
|
|
print $fh "!ENDIF \r\n";
|
|
print $fh "\r\n";
|
|
print $fh "# End Source File\r\n";
|
|
}
|
|
|
|
sub dsp_add_group {
|
|
my ($dsp_name,$makefile) = @_;
|
|
my $base_dir = './';
|
|
|
|
initialize_per_input();
|
|
my $relative_dir = dirname($makefile);
|
|
|
|
read_main_am_file($makefile . '.am');
|
|
|
|
open(DSP, ">>$dsp_name" . '.dsp')
|
|
|| die "Can't append to $dsp_name: $!\n";
|
|
|
|
foreach my $key (sort keys %contents) {
|
|
if ($key eq "include_HEADERS") {
|
|
}
|
|
if ($key =~ /^lib(.*)_a_SOURCES/) {
|
|
my $group = 'Lib_' . $1;
|
|
print DSP "# Begin Group \"$group\"\r\n";
|
|
print DSP "\r\n";
|
|
print DSP "# PROP Default_Filter \"\"\r\n";
|
|
my @files = split(' ', $contents{$key});
|
|
foreach (@files) {
|
|
my $file;
|
|
my $src_dir = $base_dir . $relative_dir . '/';
|
|
$src_dir =~ s/\//\\/g; # fixup DOS path separators
|
|
|
|
if (/^\$\(([^\)]*)\)$/) {
|
|
# Found a variable.
|
|
my $varname = $1;
|
|
foreach (split(' ', $contents{$varname})) {
|
|
$file = $src_dir . $_;
|
|
dsp_add_source_rule(\*DSP, $dsp_name, $group, $file);
|
|
}
|
|
} else {
|
|
$file = $src_dir . $_;
|
|
dsp_add_source_rule(\*DSP, $dsp_name, $group, $file);
|
|
}
|
|
}
|
|
|
|
print DSP "# End Group\r\n";
|
|
}
|
|
#elsif ($key =~ /(.*)_SOURCES/) {
|
|
elsif ($key eq "fgfs_SOURCES") {
|
|
my $group = 'main';
|
|
print DSP "# Begin Group \"$group\"\r\n";
|
|
print DSP "\r\n";
|
|
print DSP "# PROP Default_Filter \"\"\r\n";
|
|
my @files = split(' ', $contents{$key});
|
|
foreach (@files) {
|
|
my $file;
|
|
my $src_dir = $base_dir . $relative_dir . '/';
|
|
$src_dir =~ s/\//\\/g; # fixup DOS path separators
|
|
|
|
dsp_add_source_rule(\*DSP, $dsp_name, $group, $src_dir . $_);
|
|
if (0) {
|
|
my $f = $base_dir . $relative_dir . '/' . $_;
|
|
$f =~ s/\//\\/g;
|
|
print DSP "# Begin Source File\r\n";
|
|
print DSP "\r\n";
|
|
print DSP "SOURCE=$f\r\n";
|
|
print DSP "\r\n";
|
|
print DSP "!IF \"\$(CFG)\" == \"$dsp_name - Win32 Release\"\r\n";
|
|
print DSP "\r\n";
|
|
print DSP "# PROP Intermediate_Dir \"Release\\$group\"\r\n";
|
|
print DSP "\r\n";
|
|
print DSP "!ELSEIF \"\$(CFG)\" == \"$dsp_name - Win32 Debug\"\r\n";
|
|
print DSP "\r\n";
|
|
print DSP "# PROP Intermediate_Dir \"Debug\\$group\"\r\n";
|
|
print DSP "\r\n";
|
|
print DSP "!ENDIF \r\n";
|
|
print DSP "\r\n";
|
|
print DSP "# End Source File\r\n";
|
|
}
|
|
}
|
|
print DSP "# End Group\r\n";
|
|
}
|
|
}
|
|
close(DSP);
|
|
}
|
|
|
|
sub dsp_finish {
|
|
my $dsp_name = shift;
|
|
|
|
open(DSP, ">>$dsp_name" . '.dsp')
|
|
|| die "Can't append to $dsp_name: $!\n";
|
|
|
|
foreach my $r (@extra_sources) {
|
|
print DSP "# Begin Source File\r\n\r\n";
|
|
print DSP "$r\r\n";
|
|
print DSP "# End Source File\r\n";
|
|
}
|
|
print DSP "# End Target\r\n";
|
|
print DSP "# End Project\r\n";
|
|
|
|
close(DSP);
|
|
}
|
|
|
|
# Return directory name of file.
|
|
sub dirname
|
|
{
|
|
my ($file) = @_;
|
|
my ($sub);
|
|
|
|
($sub = $file) =~ s,/+[^/]+$,,g;
|
|
$sub = '.' if $sub eq $file;
|
|
return $sub;
|
|
}
|
|
|