#!/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{$'} = []; } 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 = ) ) { 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*/ ) { 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);