summaryrefslogtreecommitdiffstats
path: root/dmakegen
blob: b6b13b3075765677f5564add71b056ae21b87df8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/perl
# $Id$
#
# dmakegen - a preprocessor for GNU make to make make directory-aware
#

undef %Generics, $Default;


$err = 0;
$nline = 0;
open(DMAKEROOT, "< Dmakeroot") or die "$0: No Dmakeroot file found\n";
while ( defined($line = <DMAKEROOT>) ) {
    chomp $line;  $nline++;
    while ( $line =~ /\\$/ ) {
	if ( defined($cline = <DMAKEROOT>) ) {
	    chomp $cline;  $nline++;
	    $line = substr($line, 0, length($line)-1) + $cline;
	} else {
	    die "$0: Dmakeroot:$nline: unterminated continuation line\n";
	    $err = 1;
	}
    }

    $line =~ s/\#.*$//;		# Remove comments
    $line =~ s/\s*$//;		# Remove trailing whitespace

    if ( $line eq '' ) {
	# Empty line, do nothing
    } elsif ( $line =~ /^GENERIC:\s*/ ) {
	foreach $generic ( split(/\s+/, $') ) {
	    $Generics{$'} = [];
	}
	push(Generics, split(/\s+/, $'));
    } elsif ( $line =~ /^DEFAULT:\s*/ ) {
	$Default = $';
    } else {
	print "$0: Dmakeroot:$nline: unknown directive\n";
	$err = 1;
    }
}
close(DMAKEROOT);
if ( $err ) {
    exit(1);
}

#
# Recurse through various directories and generate Dmakefragment files
#
@dirlist = ('.');
@dmakefrags = ();

while ( defined($dir = pop(@dirlist)) ) {
    open(DMAKEFILE, "< ${dir}/Dmakefile") or die "$0: ${dir}/Dmakefile not found\n";
    open(DMAKEFRAG, "> ${dir}/Dmakefrag") or die "$0: Cannot create ${dir}/Dmakefrag: $!\n";
    push(@dmakefrags, "${dir}/Dmakefrag");

    $nline = 0;  $err = 0;
    while ( defined($line = <DMAKEFILE>) ) {
	chomp $line;  $nline++;
	while ( $line =~ /\\$/ ) {
	    if ( defined($cline = <DMAKEFILE>) ) {
		chomp $cline;  $nline++;
		$line = substr($line, 0, length($line)-1) + $cline;
	    } else {
		die "$0: ${dir}/Dmakefile:$nline: unterminated continuation line\n";
		$err = 1;
	    }
	}

	### FIX: THIS IS BUGGY - NEED TO HANDLE ESCAPES ###
	$line =~ s/\#.*$//;	# Remove comments
	$line =~ s/\s*$//;	# Remove trailing spaces

	if ( $line eq '' ) {
	    # Do nothing
	} elsif ( $line =~ /^SUBDIRS:\s*/ ) {
	    push(@dirlist, split(/\s+/, $'));
	} elsif ( $line =~ /^\.([^.:]+):\s*(.*)$/ ) {
	    # Rule of the form .c:
	    $suffix = $1;
	    $deps = $2;
	    print DMAKEFRAG "${dir}/%: ${dir}/%.${suffix}";
	    if ( $deps ne '' ) {
		foreach $dep ( split(/\s+/, $deps) ) {
		    print DMAKEFRAG " ${dir}/${dep}";
		}
	    }
	    print "\n";
	} elsif ( $line =~ /^\.([^.:])\.([^.:]+):\s*(.*)$/ ) {
	    # Rule of the form .c.o:
	    $suff1 = $1;
	    $suff2 = $2;
	    $deps = $3;
	    print DMAKEFRAG "${dir}/%.${suff2}: ${dir}/%.${suff1}";
	    if ( $deps ne '' ) {
		foreach $dep ( split(/\s+/, $deps) ) {
		    print DMAKEFRAG " ${dir}/${dep}";
		}
	    }
	    print "\n";
	} elsif ( $line =~ /^(\S|\S.*\S)\s*:\s*(\S|\S.*\S)\s*$/ ) {
	    # Rule of the form foo .. : bar
	    $lhs = $1;
	    $rhs = $2;
	    if ( $lhs ne '' ) {
		foreach $targ ( split(/\s+/, $lhs) ) {
		    if ( defined($Generics{$targ}) ) {
			push(@{$Generics{$targ}}, "${dir}/${targ}");
			print DMAKEFRAG ".PHONY: ${dir}/${targ}\n";
		    }
		    print DMAKEFRAG " ${dir}/${targ}";
		}
	    }
	    print DMAKEFRAG " : ";
	    if ( $rhs ne '' ) {
		foreach $deps ( split(/\s+/, $rhs) ) {
		    print DMAKEFRAG " ${dir}/${deps}";
		}
	    }
	    print "\n";
	} elsif ( $line =~ /^(\s+)(\S.*)$/ ) {
	    print DMAKEFRAG "$1cd \"${dir}\" && $2\n";
	} else {
	    # Handle stuff like local variables here
	}
    }
    close(DMAKEFILE);
    close(DMAKEFRAG);
}

#
# Create the Makefile
#
open(MAKEFILE, "> Makefile") or die "$0: Could not create Makefile\n";

print MAKEFILE ".default: ${Default}\n\n";

print MAKEFILE "Makefile:\n\tdmakegen\n\n";

foreach $gen ( keys(%Generics) ) {
    print MAKEFILE ".PHONY: ${gen}\n";
    print MAKEFILE "${gen}: ";
    foreach $subtarg ( @{$Generics{$gen}} ) {
	print MAKEFILE $subtarg, ' ';
    }
    print MAKEFILE "\n";
}

# Must be done in reverse order (leaf node directories
# before the associated branch node.)
while ( defined($frag = pop(@dmakefrags)) ) {
    print "-include ${frag}\n";
}

close(MAKEFILE);