#!/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 = ) ) { chomp $line; $nline++; while ( $line =~ /\\$/ ) { if ( defined($cline = ) ) { 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{$generic} = []; } } 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"); $pat = 0; # Not currently processing a pattern rule $nline = 0; $err = 0; while ( defined($line = ) ) { chomp $line; $nline++; while ( $line =~ /\\$/ ) { if ( defined($cline = ) ) { 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*/ ) { foreach $subdir ( split(/\s+/, $') ) { push(@dirlist, "${dir}/${subdir}"); } } 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 DMAKEFRAG "\n"; $pat = 1; } 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 DMAKEFRAG "\n"; $pat = 1; } elsif ( $line =~ /^(\S|\S.*\S)\s*:\s*(|\S|\S.*\S)\s*$/ ) { # Rule of the form foo .. : bar $lhs = $1; $rhs = $2; $tt = ''; $pat = 0; if ( $lhs ne '' ) { foreach $targ ( split(/\s+/, $lhs) ) { if ( defined($Generics{$targ}) ) { push(@{$Generics{$targ}}, "${dir}/${targ}"); print DMAKEFRAG ".PHONY: ${dir}/${targ}\n"; } elsif ( $targ = /%/ ) { $pat = 1; } $tt .= "${dir}/${targ} "; } } print DMAKEFRAG $tt, ":"; if ( $rhs ne '' ) { foreach $deps ( split(/\s+/, $rhs) ) { print DMAKEFRAG " ${dir}/${deps}"; } } print DMAKEFRAG "\n"; } elsif ( $line =~ /^(\s+)(\S.*)$/ ) { if ( $pat ) { print DMAKEFRAG $line, "\n"; } else { 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}: ", join(' ', @{$Generics{$gen}}), "\n"; } # Must be done in reverse order (leaf node directories # before the associated branch node.) while ( defined($frag = pop(@dmakefrags)) ) { print MAKEFILE "-include ${frag}\n"; } close(MAKEFILE);