#!/usr/bin/perl # Expands the specialised KDE tags in Makefile.in to (hopefully) valid # make syntax. # When called without file parameters, we work recursively on all Makefile.in # in and below the current subdirectory. When called with file parameters, # only those Makefile.in are changed. # The currently supported tags are # # {program}_METASOURCES # where you have a choice of two styles # {program}_METASOURCES = name1.moc name2.moc ... [\] # {program}_METASOURCES = AUTO # The second style requires other tags as well. # # To install icons : # KDE_ICON = iconname iconname2 ... # KDE_ICON = AUTO # # For documentation : # ... # # and more new tags TBD! # # The concept (and base code) for this program came from automoc, # supplied by the following # # Matthias Ettrich (The originator) # Kalle Dalheimer (The original implementator) # Harri Porten # Alex Zepeda # David Faure # Stephan Kulow # # I've puddled around with automoc and produced something different # 1999-02-01 John Birch # * Rewritten automoc to cater for more than just moc file expansion # Version 0.01 does the same as automoc at this stage. # 1999-02-18 jb # * We must always write a Makefile.in file out even if we fail # because we need the "perl autokmake" in the AUTOMAKE so that a # "make" will regenerate the Makefile.in correctly. # Reworked moc file checking so that missing includes in cpp # will work and includes in cpp when using use_automoc will also # work. # 1999-02-23 jb # * Added POFILE processing and changed the USE_AUTOMOC tag to # AUTO instead. # ... See ChangeLog for more logs use Cwd; use File::Find; use File::Basename; # Prototype the functions sub initialise (); sub processMakefile ($); sub updateMakefile (); sub restoreMakefile (); sub removeLine ($$); sub appendLines ($); sub substituteLine ($$); sub findMocCandidates (); sub pruneMocCandidates ($); sub checkMocCandidates (); sub addMocRules (); sub tag_AUTOMAKE (); sub tag_META_INCLUDES (); sub tag_METASOURCES (); sub tag_POFILES (); sub tag_DOCFILES (); sub tag_LOCALINSTALL(); sub tag_IDLFILES(); sub tag_UIFILES(); sub tag_SUBDIRS(); sub tag_ICON(); sub tag_CLOSURE(); sub tag_DIST(); # Some global globals... $verbose = 0; # a debug flag $thisProg = "$0"; # This programs name $topdir = cwd(); # The current directory @makefiles = (); # Contains all the files we'll process @foreignfiles = (); $start = (times)[0]; # some stats for testing - comment out for release $version = "v0.2"; $errorflag = 0; $cppExt = "(cpp|cc|cxx|C|c\\+\\+)"; $hExt = "(h|H|hh|hxx|hpp|h\\+\\+)"; $progId = "KDE tags expanded automatically by " . basename($thisProg); $automkCall = "\n"; $printname = ""; # used to display the directory the Makefile is in $use_final = 1; # create code for --enable-final $cleantarget = "clean"; $dryrun = 0; $pathoption = 0; while (defined ($ARGV[0])) { $_ = shift; if (/^--version$/) { print STDOUT "\n"; print STDOUT basename($thisProg), " $version\n", "This is really free software, unencumbered by the GPL.\n", "You can do anything you like with it except sueing me.\n", "Copyright 1998 Kalle Dalheimer \n", "Concept, design and unnecessary questions about perl\n", " by Matthias Ettrich \n\n", "Making it useful by Stephan Kulow and\n", "Harri Porten \n", "Updated (Feb-1999), John Birch \n", "Current Maintainer Stephan Kulow\n\n"; exit 0; } elsif (/^--verbose$|^-v$/) { $verbose = 1; # Oh is there a problem...? } elsif (/^-p(.+)$|^--path=(.+)$/) { $thisProg = "$1/".basename($thisProg) if($1); $thisProg = "$2/".basename($thisProg) if($2); warn ("$thisProg doesn't exist\n") if (!(-f $thisProg)); $pathoption=1; } elsif (/^--help$|^-h$/) { print STDOUT "Usage $thisProg [OPTION] ... [dir/Makefile.in]...\n", "\n", "Patches dir/Makefile.in generated from automake\n", "(where dir can be a full or relative directory name)", "\n", " -v, --verbose verbosely list files processed\n", " -h, --help print this help, then exit\n", " --version print version number, then exit\n", " -p, --path= use the path to am_edit if the path\n", " --no-final don't patch for --enable-final\n", " called from is not the one to be used\n"; exit 0; } elsif (/^--no-final$/) { $use_final = 0; $thisProg .= " --no-final"; } elsif (/^-n$/) { $dryrun = 1; } else { # user selects what input files to check # add full path if relative path is given $_ = cwd()."/".$_ if (! /^\//); print "User wants $_\n" if ($verbose); push (@makefiles, $_); } } if ($thisProg =~ /^\// && !$pathoption ) { print STDERR "Illegal full pathname call performed...\n", "The call to \"$thisProg\"\nwould be inserted in some Makefile.in.\n", "Please use option --path.\n"; exit 1; } # Only scan for files when the user hasn't entered data if (!@makefiles) { print STDOUT "Scanning for Makefile.in\n" if ($verbose); find (\&add_makefile, cwd()); #chdir('$topdir'); } else { print STDOUT "Using user enter input files\n" if ($verbose); } foreach $makefile (sort(@makefiles)) { processMakefile ($makefile); last if ($errorflag); } # Just some debug statistics - comment out for release as it uses printf. printf STDOUT "Time %.2f CPU sec\n", (times)[0] - $start if ($verbose); exit $errorflag; # causes make to fail if erroflag is set #----------------------------------------------------------------------------- # In conjunction with the "find" call, this builds the list of input files sub add_makefile () { push (@makefiles, $File::Find::name) if (/Makefile.in$/); } #----------------------------------------------------------------------------- # Processes a single make file # The parameter contains the full path name of the Makefile.in to use sub processMakefile ($) { # some useful globals for the subroutines called here local ($makefile) = @_; local @headerdirs = ('.'); local $haveAutomocTag = 0; local $MakefileData = ""; local $cxxsuffix = "KKK"; local @programs = (); # lists the names of programs and libraries local $program = ""; local %realObjs = (); # lists the objects compiled into $program local %sources = (); # lists the sources used for $program local %finalObjs = (); # lists the objects compiled when final local %realname = (); # the binary name of program variable local %idlfiles = (); # lists the idl files used for $program local %globalmocs = ();# list of all mocfiles (in %mocFiles format) local %important = (); # list of files to be generated asap local $allidls = ""; local $alluis = ""; local $idl_output = "";# lists all idl generated files for cleantarget local $ui_output = "";# lists all uic generated files for cleantarget local %depedmocs = (); local $metasourceTags = 0; local $dep_files = ""; local $dep_finals = ""; local %target_adds = (); # the targets to add local $kdelang = ""; local @cleanfiles = (); local $cleanMoc = ""; local $closure_output = ""; $makefileDir = dirname($makefile); chdir ($makefileDir); $printname = $makefile; $printname =~ s/^\Q$topdir\E\///; $makefile = basename($makefile); print STDOUT "Processing makefile $printname\n" if ($verbose); # Setup and see if we need to do this. return if (!initialise()); tag_AUTOMAKE (); # Allows a "make" to redo the Makefile.in tag_META_INCLUDES (); # Supplies directories for src locations foreach $program (@programs) { $sources_changed{$program} = 0; $depedmocs{$program} = ""; $important{$program} = ""; tag_IDLFILES(); # Sorts out idl rules tag_CLOSURE(); tag_METASOURCES (); # Sorts out the moc rules tag_UIFILES(); # Sorts out ui rules if ($sources_changed{$program}) { my $lookup = "$program" . '_SOURCES\s*=\s*(.*)'; substituteLine($lookup, "$program\_SOURCES=" . $sources{$program}); } if ($important{$program}) { local %source_dict = (); for $source (split(/[\034\s]+/, $sources{$program})) { $source_dict{$source} = 1; } for $source (@cleanfiles) { $source_dict{$source} = 0; } for $source (keys %source_dict) { next if (!$source); if ($source_dict{$source}) { # sanity check if (! -f $source) { print STDERR "Error: $source is listed in a _SOURCE line in $printname, but doesn't exist yet. Put it in DISTCLEANFILES!\n"; } else { $target_adds{"\$(srcdir)/$source"} .= $important{$program}; } } } } } if ($cleanMoc) { # Always add dist clean tag # Add extra *.moc.cpp files created for USE_AUTOMOC because they # aren't included in the normal *.moc clean rules. appendLines ("$cleantarget-metasources:\n\t-rm -f $cleanMoc\n"); $target_adds{"$cleantarget-am"} .= "$cleantarget-metasources "; } tag_DIST(); if ($idl_output) { appendLines ("$cleantarget-idl:\n\t-rm -f $idl_output\n"); $target_adds{"$cleantarget-am"} .= "$cleantarget-idl "; } if ($ui_output) { appendLines ("$cleantarget-ui:\n\t-rm -f $ui_output\n"); $target_adds{"$cleantarget-am"} .= "$cleantarget-ui "; } if ($closure_output) { appendLines ("$cleantarget-closures:\n\t-rm -f $closure_output\n"); $target_adds{"$cleantarget-am"} .= "$cleantarget-closures "; } if ($MakefileData =~ /\nKDE_LANG\s*=\s*(\S*)\s*\n/) { $kdelang = '$(KDE_LANG)' } else { $kdelang = ''; } tag_POFILES (); # language rules for po directory tag_DOCFILES (); # language rules for doc directories tag_LOCALINSTALL(); # add $(DESTDIR) before all kde_ dirs tag_ICON(); tag_SUBDIRS(); my $tmp = "force-reedit:\n"; $tmp .= "\t$automkCall\n\tcd \$(top_srcdir) && perl $thisProg $printname\n\n"; appendLines($tmp); make_meta_classes(); tag_FINAL() if (!$kdeopts{"nofinal"}); my $final_lines = "final:\n\t\$(MAKE) "; my $nofinal_lines = "no-final:\n\t\$(MAKE) "; foreach $program (@programs) { my $lookup = "$program\_OBJECTS.*=[^\n]*"; my $new = ""; my @list = split(/[\034\s]+/, $realObjs{$program}); if (!$kdeopts{"nofinal"} && @list > 1 && $finalObjs{$program}) { $new .= "$program\_final\_OBJECTS = " . $finalObjs{$program}; $new .= "\n$program\_nofinal\_OBJECTS = " . $realObjs{$program}; $new .= "\n\@KDE_USE_FINAL_FALSE\@$program\_OBJECTS = \$($program\_nofinal\_OBJECTS)"; $new .= "\n\@KDE_USE_FINAL_TRUE\@$program\_OBJECTS = \$($program\_final\_OBJECTS)"; $final_lines .= "$program\_OBJECTS=\"\$($program\_final_OBJECTS)\" "; $nofinal_lines .= "$program\_OBJECTS=\"\$($program\_nofinal\_OBJECTS)\" "; } else { $new = "$program\_OBJECTS = " . $realObjs{$program}; } substituteLine ($lookup, $new); } appendLines($final_lines . "all-am"); appendLines($nofinal_lines . "all-am"); my $lookup = 'DEP_FILES\s*=([^\n]*)'; if ($MakefileData =~ /\n$lookup\n/o) { $depfiles = $1; if ($dep_finals) { $lines = "\@KDE_USE_FINAL_TRUE\@DEP_FILES = $dep_files $dep_finals \034\t$depfiles\n"; $lines .= "\@KDE_USE_FINAL_FALSE\@DEP_FILES = $dep_files $depfiles\n"; } else { $lines = "DEP_FILES = $dep_files $depfiles\n"; } substituteLine($lookup, $lines); } my $cvs_lines = "cvs-clean:\n"; $cvs_lines .= "\t\$(MAKE) -f \$(top_srcdir)/admin/Makefile.common cvs-clean\n"; appendLines($cvs_lines); $cvs_lines = "kde-rpo-clean:\n"; $cvs_lines .= "\t-rm -f *.rpo\n"; appendLines($cvs_lines); $target_adds{"clean"} .= "kde-rpo-clean "; # some strange people like to do a install-exec, and expect that also # all modules are installed. automake doesn't know this, so we need to move # this here from install-data to install-exec. if ($MakefileData =~ m/\nkde_module_LTLIBRARIES\s*=/) { $target_adds{"install-exec-am"} .= "install-kde_moduleLTLIBRARIES"; my $lookup = "install-data-am:\s*(.*)"; if ($MakefileData =~ /\n$lookup\n/) { my $newdeps = $1; $newdeps =~ s/\s*install-kde_moduleLTLIBRARIES\s*/ /g; substituteLine($lookup, "install-data-am: " . $newdeps); } } my $lines = ""; foreach $add (keys %target_adds) { my $lookup = quotemeta($add) . ":\s*(.*)"; if ($MakefileData =~ /\n$lookup\n/) { substituteLine($lookup, "$add: " . $target_adds{$add} . $1); } else { $lines .= "$add: " . $target_adds{$add} . "\n"; } } if ($lines) { appendLines($lines); } my $found = 1; while ($found) { if ($MakefileData =~ m/\n(.*)\$\(CXXFLAGS\)(.*)\n/) { my $vor = $1; # "vor" means before in German my $nach = $2; # "nach" means after in German my $lookup = quotemeta("$1\$(CXXFLAGS)$2"); my $replacement = "$1\$(KCXXFLAGS)$2"; $MakefileData =~ s/$lookup/$replacement/; $lookup =~ s/\\\$\\\(CXXFLAGS\\\)/\\\$\\\(KCXXFLAGS\\\)/; $replacement = "$vor\$(KCXXFLAGS) \$(KDE_CXXFLAGS)$nach"; substituteLine($lookup, $replacement); } else { $found = 0; } } $lookup = '(\n[^#].*\$\(LIBTOOL\) --mode=link) (\$\(CXXLD\).*\$\(KCXXFLAGS\))'; if ($MakefileData =~ m/$lookup/ ) { $MakefileData =~ s/$lookup/$1 --tag=CXX $2/; } $lookup = '(\n[^#].*\$\(LIBTOOL\) --mode=compile) (\$\(CXX\).*\$\(KCXXFLAGS\))'; if ($MakefileData =~ m/$lookup/ ) { $MakefileData =~ s/$lookup/$1 --tag=CXX $2/; } $MakefileData =~ s/\$\(KCXXFLAGS\)/\$\(CXXFLAGS\)/g; $lookup = '(.*)cp -pr \$\$/\$\$file \$\(distdir\)/\$\$file(.*)'; if ($MakefileData =~ m/\n$lookup\n/) { substituteLine($lookup, "$1cp -pr \$\$d/\$\$file \$(distdir)/\$\$file$2"); } # Always update the Makefile.in updateMakefile (); return; } #----------------------------------------------------------------------------- # Check to see whether we should process this make file. # This is where we look for tags that we need to process. # A small amount of initialising on the tags is also done here. # And of course we open and/or create the needed make files. sub initialise () { if (! -r "Makefile.am") { print STDOUT "found Makefile.in without Makefile.am\n" if ($verbose); return 0; } # Checking for files to process... open (FILEIN, $makefile) || die "Could not open $makefileDir/$makefile: $!\n"; # Read the file # stat(FILEIN)[7] might look more elegant, but is slower as it # requires stat'ing the file seek(FILEIN, 0, 2); my $fsize = tell(FILEIN); seek(FILEIN, 0, 0); read FILEIN, $MakefileData, $fsize; close FILEIN; print "DOS CRLF within $makefileDir/$makefile!\n" if($MakefileData =~ y/\r//d); # Remove the line continuations, but keep them marked # Note: we lose the trailing spaces but that's ok. $MakefileData =~ s/\\\s*\n/\034/g; # If we've processed the file before... restoreMakefile () if ($MakefileData =~ /$progId/); foreach $dir (@foreignfiles) { if (substr($makefileDir,0,length($dir)) eq $dir) { return 0; } } %kdeopts = (); $kdeopts{"foreign"} = 0; $kdeopts{"qtonly"} = 0; $kdeopts{"nofinal"} = !$use_final; # default if ($MakefileData =~ /\nKDE_OPTIONS\s*=\s*([^\n]*)\n/) { local @kde_options = split(/[\s\034]/, $1); if (grep(/^foreign$/, @kde_options)) { push(@foreignfiles, $makefileDir . "/"); return 0; # don't touch me } for $opt (@kde_options) { if (!defined $kdeopts{$opt}) { print STDERR "Warning: unknown option $opt in $printname\n"; } else { $kdeopts{$opt} = 1; } } } # Look for the tags that mean we should process this file. $metasourceTags = 0; $metasourceTags++ while ($MakefileData =~ /\n[^=\#]*METASOURCES\s*=/g); my $pofileTag = 0; $pofileTag++ while ($MakefileData =~ /\nPOFILES\s*=/g); if ($pofileTag > 1) { print STDERR "Error: Only one POFILES tag allowed\n"; $errorflag = 1; } while ($MakefileData =~ /\n\.SUFFIXES:([^\n]+)\n/g) { my @list=split(' ', $1); foreach $ext (@list) { if ($ext =~ /^\.$cppExt$/) { $cxxsuffix = $ext; $cxxsuffix =~ s/\.//g; print STDOUT "will use suffix $cxxsuffix\n" if ($verbose); last; } } } while ($MakefileData =~ /\n(\S*)_OBJECTS\s*=[ \t\034]*([^\n]*)\n/g) { my $program = $1; my $objs = $2; # safe them my $ocv = 0; my @objlist = split(/[\s\034]+/, $objs); foreach $obj (@objlist) { if ($obj =~ /\$\((\S+)\)/ ) { my $variable = $1; if ($variable !~ 'OBJEXT') { $ocv = 1; } } } next if ($ocv); $program =~ s/^am_// if ($program =~ /^am_/); print STDOUT "found program $program\n" if ($verbose); push(@programs, $program); $realObjs{$program} = $objs; if ($MakefileData =~ /\n$program\_SOURCES\s*=\s*(.*)\n/) { $sources{$program} = $1; } else { $sources{$program} = ""; print STDERR "found program with no _SOURCES: $program\n"; } my $realprogram = $program; $realprogram =~ s/_/./g; # unmask to regexp if ($MakefileData =~ /\n($realprogram)(\$\(EXEEXT\)?)?:.*\$\($program\_OBJECTS\)/) { $realname{$program} = $1; } else { # not standard Makefile - nothing to worry about $realname{$program} = ""; } } my $lookup = '\nDEPDIR\s*=.*'; if ($MakefileData !~ /($lookup)\n/o) { $lookup = '\nbindir\s*=.*'; if ($MakefileData =~ /($lookup)\n/) { substituteLine ($lookup, "DEPDIR = .deps\n$1"); } } else { print STDERR "$printname defines DEPDIR. This means you're using automake > 1.4 - this is not supported!\n"; } my @marks = ('MAINTAINERCLEANFILES', 'CLEANFILES', 'DISTCLEANFILES'); foreach $mark (@marks) { while ($MakefileData =~ /\n($mark)\s*=\s*([^\n]*)/g) { foreach $file (split('[\034\s]', $2)) { $file =~ s/\.\///; push(@cleanfiles, $file); } } } my $localTag = 0; $localTag++ if ($MakefileData =~ /\ninstall-\S+-local:/); return (!$errorflag); } #----------------------------------------------------------------------------- # Gets the list of user defined directories - relative to $srcdir - where # header files could be located. sub tag_META_INCLUDES () { my $lookup = '[^=\n]*META_INCLUDES\s*=\s*(.*)'; return 1 if ($MakefileData !~ /($lookup)\n/o); print STDOUT "META_INCLUDE processing <$1>\n" if ($verbose); my $headerStr = $2; removeLine ($lookup, $1); $headerStr =~ tr/\034/ /; my @headerlist = split(' ', $headerStr); foreach $dir (@headerlist) { $dir =~ s#\$\(srcdir\)#.#; if (! -d $dir) { print STDERR "Warning: $dir can't be found. ", "Must be a relative path to \$(srcdir)\n"; } else { push (@headerdirs, $dir); } } return 0; } #----------------------------------------------------------------------------- sub tag_FINAL() { my @final_names = (); foreach $program (@programs) { if ($sources{$program} =~ /\(/) { print STDOUT "found ( in $program\_SOURCES. skipping\n" if ($verbose); next; } my $mocsources = ""; my @progsources = split(/[\s\034]+/, $sources{$program}); my %sourcelist = (); foreach $source (@progsources) { my $suffix = $source; $suffix =~ s/^.*\.([^\.]+)$/$1/; if (defined($sourcelist{$suffix})) { $sourcelist{$suffix} .= " " . $source; } else { $sourcelist{$suffix} .= $source; } } foreach $suffix (keys %sourcelist) { # See if this file contains c++ code. (ie Just check the files suffix against my $suffix_is_cxx = 0; if($suffix =~ /($cppExt)$/) { $cxx_suffix = $1; $suffix_is_cxx = 1; } my $mocfiles_in = ($suffix eq $cxxsuffix) && defined($depedmocs{$program}); my @sourcelist = split(/[\s\034]+/, $sourcelist{$suffix}); if ((@sourcelist == 1 && !$mocfiles_in) || $suffix_is_cxx != 1 ) { # we support IDL on our own if ($suffix =~ /^skel$/ || $suffix =~ /^stub/ || $suffix =~ /^h$/ || $suffix =~ /^ui$/ ) { next; } foreach $file (@sourcelist) { $file =~ s/\Q$suffix\E$//; $finalObjs{$program} .= $file; if ($program =~ /_la$/) { $finalObjs{$program} .= "lo "; } else { $finalObjs{$program} .= "o "; } } next; # suffix } my $source_deps = ""; foreach $source (@sourcelist) { if (-f $source) { $source_deps .= "\$(srcdir)/$source "; } else { $source_deps .= "$source "; } } $handling = "$program.all_$suffix.$suffix: \$(srcdir)/Makefile.in " . $source_deps . " "; if ($mocfiles_in) { $handling .= $depedmocs{$program}; foreach $mocfile (split(' ', $depedmocs{$program})) { if ($mocfile =~ m/\.$suffix$/) { $mocsources .= " " . $mocfile; } } } $handling .= "\n"; $handling .= "\t\@echo 'creating $program.all_$suffix.$suffix ...'; \\\n"; $handling .= "\trm -f $program.all_$suffix.files $program.all_$suffix.final; \\\n"; $handling .= "\techo \"#define KDE_USE_FINAL 1\" >> $program.all_$suffix.final; \\\n"; $handling .= "\tfor file in " . $sourcelist{$suffix} . " $mocsources; do \\\n"; $handling .= "\t echo \"#include \\\"\$\$file\\\"\" >> $program.all_$suffix.files; \\\n"; $handling .= "\t test ! -f \$\(srcdir\)/\$\$file || egrep '^#pragma +implementation' \$\(srcdir\)/\$\$file >> $program.all_$suffix.final; \\\n"; $handling .= "\tdone; \\\n"; $handling .= "\tcat $program.all_$suffix.final $program.all_$suffix.files > $program.all_$suffix.$suffix; \\\n"; $handling .= "\trm -f $program.all_$suffix.final $program.all_$suffix.files\n"; appendLines($handling); push(@final_names, "$program.all_$suffix.$suffix"); $finalObjs{$program} .= "$program.all_$suffix."; if ($program =~ /_la$/) { $finalObjs{$program} .= "lo "; } else { $finalObjs{$program} .= "o "; } } } if (!$kdeopts{"nofinal"} && @final_names >= 1) { # add clean-final target my $lines = "$cleantarget-final:\n"; $lines .= "\t-rm -f " . join(' ', @final_names) . "\n" if (@final_names); appendLines($lines); $target_adds{"$cleantarget-am"} .= "$cleantarget-final "; foreach $finalfile (@final_names) { $finalfile =~ s/\.[^.]*$/.P/; $dep_finals .= " \$(DEPDIR)/$finalfile"; } } } # Organises the list of headers that we'll use to produce moc files # from. sub tag_METASOURCES () { local @newObs = (); # here we add to create object files local @deped = (); # here we add to create moc files local $mocExt = ".moc"; local %mocFiles = (); my $line = ""; my $postEqual = ""; my $lookup; my $found = ""; if ($metasourceTags > 1) { $lookup = $program . '_METASOURCES\s*=\s*(.*)'; return 1 if ($MakefileData !~ /\n($lookup)\n/); $found = $1; } else { $lookup = $program . '_METASOURCES\s*=\s*(.*)'; if ($MakefileData !~ /\n($lookup)\n/) { $lookup = 'METASOURCES\s*=\s*(.*)'; return 1 if ($MakefileData !~ /\n($lookup)\n/o); $found = $1; $metasourceTags = 0; # we can use the general target only once } else { $found = $1; } } print STDOUT "METASOURCE processing <$found>)\n" if ($verbose); $postEqual = $found; $postEqual =~ s/[^=]*=//; removeLine ($lookup, $found); # Always find the header files that could be used to "moc" return 1 if (findMocCandidates ()); if ($postEqual =~ /AUTO\s*(\S*)|USE_AUTOMOC\s*(\S*)/) { print STDERR "$printname: the argument for AUTO|USE_AUTOMOC is obsolete" if ($+); $mocExt = ".moc.$cxxsuffix"; $haveAutomocTag = 1; } else { # Not automoc so read the list of files supplied which # should be .moc files. $postEqual =~ tr/\034/ /; # prune out extra headers - This also checks to make sure that # the list is valid. pruneMocCandidates ($postEqual); } checkMocCandidates (); if (@newObs) { my $ext = ($program =~ /_la$/) ? ".moc.lo " : ".moc.o "; $realObjs{$program} .= "\034" . join ($ext, @newObs) . $ext; $depedmocs{$program} = join (".moc.$cxxsuffix " , @newObs) . ".moc.$cxxsuffix"; foreach $file (@newObs) { $dep_files .= " \$(DEPDIR)/$file.moc.P"; } } if (@deped) { $depedmocs{$program} .= " "; $depedmocs{$program} .= join('.moc ', @deped) . ".moc"; $depedmocs{$program} .= " "; } addMocRules (); @globalmocs{keys %mocFiles}=values %mocFiles; } #----------------------------------------------------------------------------- # Returns 0 if the line was processed - 1 otherwise. # Errors are logged in the global $errorflags sub tag_AUTOMAKE () { my $lookup = '.*cd \$\(top_srcdir\)\s+&&\s+\$\(AUTOMAKE\)(.*)'; return 1 if ($MakefileData !~ /\n($lookup)\n/); print STDOUT "AUTOMAKE processing <$1>\n" if ($verbose); my $newLine = $1."\n\tcd \$(top_srcdir) && perl $thisProg $printname"; substituteLine ($lookup, $newLine); $automkCall = $1; return 0; } #----------------------------------------------------------------------------- sub handle_TOPLEVEL() { my $pofiles = ""; my @restfiles = (); opendir (THISDIR, "."); foreach $entry (readdir(THISDIR)) { next if (-d $entry); next if ($entry eq "CVS" || $entry =~ /^\./ || $entry =~ /^Makefile/ || $entry =~ /~$/ || $entry =~ /^\#.*\#$/ || $entry =~ /.gmo$/); if ($entry =~ /\.po$/) { next; } push(@restfiles, $entry); } closedir (THISDIR); if (@restfiles) { $target_adds{"install-data-am"} .= "install-nls-files "; $lines = "install-nls-files:\n"; $lines .= "\t\$(mkinstalldirs) \$(DESTDIR)\$(kde_locale)/$kdelang\n"; for $file (@restfiles) { $lines .= "\t\$(INSTALL_DATA) \$\(srcdir\)/$file \$(DESTDIR)\$(kde_locale)/$kdelang/$file\n"; } $target_adds{"uninstall"} .= "uninstall-nls-files "; $lines .= "uninstall-nls-files:\n"; for $file (@restfiles) { $lines .= "\t-rm -f \$(DESTDIR)\$(kde_locale)/$kdelang/$file\n"; } appendLines($lines); } return 0; } #----------------------------------------------------------------------------- sub tag_SUBDIRS () { if ($MakefileData !~ /\nSUBDIRS\s*=\s*\$\(AUTODIRS\)\s*\n/) { return 1; } my $subdirs; opendir (THISDIR, "."); foreach $entry (readdir(THISDIR)) { next if ($entry eq "CVS" || $entry =~ /^\./); if (-d $entry && -f $entry . "/Makefile.am") { $subdirs .= " $entry"; next; } } closedir (THISDIR); my $lines = "SUBDIRS =$subdirs\n"; substituteLine('SUBDIRS\s*=.*', $lines); return 0; } sub tag_IDLFILES () { my @psources = split(/[\034\s]+/, $sources{$program}); my $dep_lines = ""; my @cppFiles = (); foreach $source (@psources) { my $skel = ($source =~ m/\.skel$/); if ($source =~ m/\.stub$/ || $skel) { my $qs = quotemeta($source); $sources{$program} =~ s/$qs//; $sources_changed{$program} = 1; print STDOUT "adding IDL file $source\n" if ($verbose); $source =~ s/\.(stub|skel)$//; my $sourcename; if ($skel) { $sourcename = "$source\_skel"; } else { $sourcename = "$source\_stub"; } my $sourcedir = ''; if (-f "$makefileDir/$source.h") { $sourcedir = '$(srcdir)/'; } else { if ($MakefileData =~ /\n$source\_DIR\s*=\s*(\S+)\n/) { $sourcedir = $1; $sourcedir .= "/" if ($sourcedir !~ /\/$/); } } if ($allidls !~ /$source\_kidl/) { $dep_lines .= "$source.kidl: $sourcedir$source.h \$(DCOPIDL_DEPENDENCIES)\n"; $dep_lines .= "\t\$(DCOPIDL) $sourcedir$source.h > $source.kidl || ( rm -f $source.kidl ; /bin/false )\n"; $allidls .= $source . "_kidl "; } if ($allidls !~ /$sourcename/) { if ($skel) { $dep_lines .= "$sourcename.$cxxsuffix: $source.kidl\n"; $dep_lines .= "\t\$(DCOPIDL2CPP) --c++-suffix $cxxsuffix --no-stub $source.kidl\n"; } else { $target_adds{"$sourcename.$cxxsuffix"} .= "$sourcename.h "; $dep_lines .= "$sourcename.h: $source.kidl\n"; $dep_lines .= "\t\$(DCOPIDL2CPP) --c++-suffix $cxxsuffix --no-skel $source.kidl\n"; } $allidls .= $sourcename . " "; } $idlfiles{$program} .= $sourcename . " "; if ($program =~ /_la$/) { $realObjs{$program} .= " $sourcename.lo"; } else { $realObjs{$program} .= " $sourcename.\$(OBJEXT)"; } $sources{$program} .= " $sourcename.$cxxsuffix"; $sources_changed{$program} = 1; $important{$program} .= "$sourcename.h " if (!$skel); $idl_output .= "\\\n\t$sourcename.$cxxsuffix $sourcename.h $source.kidl "; push(@cleanfiles, "$sourcename.$cxxsuffix"); push(@cleanfiles, "$sourcename.h"); push(@cleanfiles, "$sourcename.kidl"); $dep_files .= " \$(DEPDIR)/$sourcename.P"; } } if ($dep_lines) { appendLines($dep_lines); } if (0) { my $lookup = "($program)"; $lookup .= '(|\$\(EXEEXT\))'; $lookup =~ s/\_/./g; $lookup .= ":(.*..$program\_OBJECTS..*)"; # $lookup = quotemeta($lookup); if ($MakefileData =~ /\n$lookup\n/) { my $line = "$1$2: "; foreach $file (split(' ', $idlfiles{$program})) { $line .= "$file.$cxxsuffix "; } $line .= $3; substituteLine($lookup, $line); } else { print STDERR "no built dependency found $lookup\n"; } } } sub tag_UIFILES () { my @psources = split(/[\034\s]+/, $sources{$program}); my $dep_lines = ""; my @depFiles = (); foreach $source (@psources) { if ($source =~ m/\.ui$/) { print STDERR "adding UI file $source\n" if ($verbose); my $qs = quotemeta($source); $sources{$program} =~ s/$qs//; $sources_changed{$program} = 1; $source =~ s/\.ui$//; my $sourcedir = ''; if (-f "$makefileDir/$source.ui") { $sourcedir = '$(srcdir)/'; } if ($alluis !~ /$source/) { $dep_lines .= "$source.$cxxsuffix: $sourcedir$source.ui $source.h $source.moc\n"; $dep_lines .= "\trm -f $source.$cxxsuffix\n"; if (!$kdeopts{"qtonly"}) { $dep_lines .= "\techo '#include ' > $source.$cxxsuffix\n"; $dep_lines .= "\t\$(UIC) -tr i18n -i $source.h $sourcedir$source.ui | sed -e \"s,i18n( \\\"\\\" ),QString::null,g\" >> $source.$cxxsuffix || rm -f $source.$cxxsuffix\n"; } else { $dep_lines .= "\t\$(UIC) -i $source.h $sourcedir$source.ui > $source.$cxxsuffix || rm -f $source.$cxxsuffix\n"; } $dep_lines .= "\techo '#include \"$source.moc\"' >> $source.$cxxsuffix\n\n"; $dep_lines .= "$source.h: $sourcedir$source.ui\n"; $dep_lines .= "\t\$(UIC) -o $source.h $sourcedir$source.ui\n\n"; $dep_lines .= "$source.moc: $source.h\n"; $dep_lines .= "\t\$(MOC) $source.h -o $source.moc\n"; $alluis .= "$source "; $depedmocs{$program} .= " $source.moc"; $globalmocs{$source} = "\035$source.h\035$source.cpp"; } if ($program =~ /_la$/) { $realObjs{$program} .= " $source.lo"; } else { $realObjs{$program} .= " $source.\$(OBJEXT)"; } $sources{$program} .= " $source.$cxxsuffix"; $sources_changed{$program} = 1; $important{$program} .= "$source.h "; $ui_output .= "\\\n\t$source.$cxxsuffix $source.h $source.moc "; push(@cleanfiles, "$source.$cxxsuffix"); push(@cleanfiles, "source.h"); push(@cleanfiles, "$source.moc"); $dep_files .= " \$(DEPDIR)/$source.P"; } } if ($dep_lines) { appendLines($dep_lines); } } sub tag_ICON() { my $lookup = '([^\s]*)_ICON\s*=\s*([^\n]*)'; my $install = ""; my $uninstall = ""; while ($MakefileData =~ /\n$lookup/og) { my $destdir; if ($1 eq "KDE") { $destdir = "kde_icondir"; } else { $destdir = $1 . "dir"; } my $iconauto = ($2 =~ /AUTO\s*$/); my @appnames = (); if ( ! $iconauto ) { my @_appnames = split(" ", $2); print STDOUT "KDE_ICON processing <@_appnames>\n" if ($verbose); foreach $appname (@_appnames) { push(@appnames, quotemeta($appname)); } } else { print STDOUT "KDE_ICON processing \n" if ($verbose); } my @files = (); opendir (THISDIR, "."); foreach $entry (readdir(THISDIR)) { next if ($entry eq "CVS" || $entry =~ /^\./ || $entry =~ /^Makefile/ || $entry =~ /~$/ || $entry =~ /^\#.*\#$/); next if (! -f $entry); if ( $iconauto ) { push(@files, $entry) if ($entry =~ /\.xpm/ || $entry =~ /\.png/); } else { foreach $appname (@appnames) { push(@files, $entry) if ($entry =~ /-$appname\.xpm/ || $entry =~ /-$appname\.png/); } } } closedir (THISDIR); my %directories = (); foreach $file (@files) { my $newfile = $file; my $prefix = $file; $prefix =~ s/\.(png|xpm)$//; my $appname = $prefix; $appname =~ s/^[^-]+-// if ($appname =~ /-/) ; $appname =~ s/^[^-]+-// if ($appname =~ /-/) ; $appname = quotemeta($appname); $prefix =~ s/$appname$//; $prefix =~ s/-$//; $prefix = 'lo16-app' if ($prefix eq 'mini'); $prefix = 'lo32-app' if ($prefix eq 'lo'); $prefix = 'hi48-app' if ($prefix eq 'large'); $prefix .= '-app' if ($prefix =~ m/^...$/); my $type = $prefix; $type =~ s/^.*-([^-]+)$/$1/; $prefix =~ s/^(.*)-[^-]+$/$1/; my %type_hash = ( 'action' => 'actions', 'app' => 'apps', 'device' => 'devices', 'filesys' => 'filesystems', 'mime' => 'mimetypes' ); if (! defined $type_hash{$type} ) { print STDERR "unknown icon type $type in $printname ($file)\n"; next; } my %dir_hash = ( 'los' => 'locolor/16x16', 'lom' => 'locolor/32x32', 'him' => 'hicolor/32x32', 'hil' => 'hicolor/48x48', 'lo16' => 'locolor/16x16', 'lo22' => 'locolor/22x22', 'lo32' => 'locolor/32x32', 'hi16' => 'hicolor/16x16', 'hi22' => 'hicolor/22x22', 'hi32' => 'hicolor/32x32', 'hi48' => 'hicolor/48x48', 'hi64' => 'hicolor/64x64', 'hisc' => 'hicolor/scalable' ); $newfile =~ s@.*-($appname\.(png|xpm?))@$1@; if (! defined $dir_hash{$prefix}) { print STDERR "unknown icon prefix $prefix in $printname\n"; next; } my $dir = $dir_hash{$prefix} . "/" . $type_hash{$type}; if ($newfile =~ /-[^\.]/) { my $tmp = $newfile; $tmp =~ s/^([^-]+)-.*$/$1/; $dir = $dir . "/" . $tmp; $newfile =~ s/^[^-]+-//; } if (!defined $directories{$dir}) { $install .= "\t\$(mkinstalldirs) \$(DESTDIR)\$($destdir)/$dir\n"; $directories{$dir} = 1; } $install .= "\t\$(INSTALL_DATA) \$(srcdir)/$file \$(DESTDIR)\$($destdir)/$dir/$newfile\n"; $uninstall .= "\t-rm -f \$(DESTDIR)\$($destdir)/$dir/$newfile\n"; } } if (length($install)) { $target_adds{"install-data-am"} .= "install-kde-icons "; $target_adds{"uninstall-am"} .= "uninstall-kde-icons "; appendLines("install-kde-icons:\n" . $install . "\nuninstall-kde-icons:\n" . $uninstall); } } sub handle_POFILES($$) { my @pofiles = split(" ", $_[0]); my $lang = $_[1]; # Build rules for creating the gmo files my $tmp = ""; my $allgmofiles = ""; my $pofileLine = "POFILES ="; foreach $pofile (@pofiles) { $pofile =~ /(.*)\.[^\.]*$/; # Find name minus extension $tmp .= "$1.gmo: $pofile\n"; $tmp .= "\trm -f $1.gmo; \$(GMSGFMT) -o $1.gmo \$(srcdir)/$pofile\n"; $tmp .= "\ttest ! -f $1.gmo || touch $1.gmo\n"; $allgmofiles .= " $1.gmo"; $pofileLine .= " $1.po"; } appendLines ($tmp); my $lookup = 'POFILES\s*=([^\n]*)'; if ($MakefileData !~ /\n$lookup/o) { appendLines("$pofileLine\nGMOFILES =$allgmofiles"); } else { substituteLine ($lookup, "$pofileLine\nGMOFILES =$allgmofiles"); } if ($allgmofiles) { # Add the "clean" rule so that the maintainer-clean does something appendLines ("clean-nls:\n\t-rm -f $allgmofiles\n"); $target_adds{"maintainer-clean"} .= "clean-nls "; $lookup = 'DISTFILES\s*=\s*(.*)'; if ($MakefileData =~ /\n$lookup\n/o) { $tmp = "DISTFILES = \$(GMOFILES) \$(POFILES) $1"; substituteLine ($lookup, $tmp); } } $target_adds{"install-data-am"} .= "install-nls "; $tmp = "install-nls:\n"; if ($lang) { $tmp .= "\t\$(mkinstalldirs) \$(DESTDIR)\$(kde_locale)/$lang/LC_MESSAGES\n"; } $tmp .= "\t\@for base in "; foreach $pofile (@pofiles) { $pofile =~ /(.*)\.[^\.]*$/; # Find name minus extension $tmp .= "$1 "; } $tmp .= "; do \\\n"; if ($lang) { $tmp .= "\t echo \$(INSTALL_DATA) \$\$base.gmo \$(DESTDIR)\$(kde_locale)/$lang/LC_MESSAGES/\$\$base.mo ;\\\n"; $tmp .= "\t test ! -f \$\$base.gmo || \$(INSTALL_DATA) \$\$base.gmo \$(DESTDIR)\$(kde_locale)/$lang/LC_MESSAGES/\$\$base.mo ;\\\n" } else { $tmp .= "\t echo \$(INSTALL_DATA) \$\$base.gmo \$(DESTDIR)\$(kde_locale)/\$\$base/LC_MESSAGES/\$(PACKAGE).mo ;\\\n"; $tmp .= "\t \$(mkinstalldirs) \$(DESTDIR)\$(kde_locale)/\$\$base/LC_MESSAGES ; \\\n"; $tmp .= "\t test ! -f \$\$base.gmo || \$(INSTALL_DATA) \$\$base.gmo \$(DESTDIR)\$(kde_locale)/\$\$base/LC_MESSAGES/\$(PACKAGE).mo ;\\\n"; } $tmp .= "\tdone\n\n"; appendLines ($tmp); $target_adds{"uninstall"} .= "uninstall-nls "; $tmp = "uninstall-nls:\n"; foreach $pofile (@pofiles) { $pofile =~ /(.*)\.[^\.]*$/; # Find name minus extension if ($lang) { $tmp .= "\trm -f \$(DESTDIR)\$(kde_locale)/$lang/LC_MESSAGES/$1.mo\n"; } else { $tmp .= "\trm -f \$(DESTDIR)\$(kde_locale)/$1/LC_MESSAGES/\$(PACKAGE).mo\n"; } } appendLines($tmp); $target_adds{"all"} .= "all-nls "; $tmp = "all-nls: \$(GMOFILES)\n"; appendLines($tmp); $target_adds{"distdir"} .= "distdir-nls "; $tmp = "distdir-nls:\$(GMOFILES)\n"; $tmp .= "\tfor file in \$(POFILES); do \\\n"; $tmp .= "\t cp \$(srcdir)/\$\$file \$(distdir); \\\n"; $tmp .= "\tdone\n"; $tmp .= "\tfor file in \$(GMOFILES); do \\\n"; $tmp .= "\t cp \$(srcdir)/\$\$file \$(distdir); \\\n"; $tmp .= "\tdone\n"; appendLines ($tmp); if (!$lang) { appendLines("merge:\n\t\$(MAKE) -f \$(top_srcdir)/admin/Makefile.common package-merge POFILES=\"\${POFILES}\" PACKAGE=\${PACKAGE}\n\n"); } } #----------------------------------------------------------------------------- # Returns 0 if the line was processed - 1 otherwise. # Errors are logged in the global $errorflags sub tag_POFILES () { my $lookup = 'POFILES\s*=([^\n]*)'; return 1 if ($MakefileData !~ /\n$lookup/o); print STDOUT "POFILES processing <$1>\n" if ($verbose); my $tmp = $1; # make sure these are all gone. if ($MakefileData =~ /\n\.po\.gmo:\n/) { print STDERR "Warning: Found old .po.gmo rules in $printname. New po rules not added\n"; return 1; } # Either find the pofiles in the directory (AUTO) or use # only the specified po files. my $pofiles = ""; if ($tmp =~ /^\s*AUTO\s*$/) { opendir (THISDIR, "."); next if ($entry eq "CVS" || $entry =~ /^\./ || $entry =~ /^Makefile/ || $entry =~ /~$/ || $entry =~ /^#.*#$/); $pofiles = join(" ", grep(/\.po$/, readdir(THISDIR))); closedir (THISDIR); print STDOUT "pofiles found = $pofiles\n" if ($verbose); if (-f "charset" && -f "kdelibs.po") { handle_TOPLEVEL(); } } else { $tmp =~ s/\034/ /g; $pofiles = $tmp; } return 1 if (!$pofiles); # Nothing to do handle_POFILES($pofiles, $kdelang); return 0; } sub helper_LOCALINSTALL($) { my $lookup = "\n" . $_[0] . ":"; if ($MakefileData =~ /($lookup)/) { my $install = $MakefileData; $install =~ s/\n/\035/g; $install =~ s/.*\035$_[0]:[^\035]*\035//; my $emptyline = 0; while (! $emptyline) { if ($install =~ /([^\035]*)\035(.*)/) { local $line = $1; $install = $2; if ($line !~ /^\s*$/ && $line !~ /^(\@.*\@)*\t/) { $emptyline = 1; } else { replaceDestDir($line); } } else { $emptyline = 1; } } } } sub tag_LOCALINSTALL () { helper_LOCALINSTALL('install-exec-local'); helper_LOCALINSTALL('install-data-local'); helper_LOCALINSTALL('uninstall-local'); return 0; } sub replaceDestDir($) { local $line = $_[0]; if ( $line =~ /^\s*(\@.*\@)*\s*\$\(mkinstalldirs\)/ || $line =~ /^\s*(\@.*\@)*\s*\$\(INSTALL\S*\)/ || $line =~ /^\s*(\@.*\@)*\s*(-?rm.*) \S*$/) { $line =~ s/^(.*) ([^\s]*)\s*$/$1 \$(DESTDIR)$2/ if ($line !~ /\$\(DESTDIR\)/); } if ($line ne $_[0]) { $_[0] = quotemeta $_[0]; substituteLine($_[0], $line); } } #--------------------------------------------------------------------------- sub tag_CLOSURE () { return if ($program !~ /_la$/); my $lookup = quotemeta($realname{$program}) . ":.*?\n\t.*?\\((.*?)\\) .*\n"; $MakefileData =~ m/$lookup/; return if ($1 !~ /CXXLINK/); if ($MakefileData !~ /\n$program\_LDFLAGS\s*=.*-no-undefined/ && $MakefileData !~ /\n$program\_LDFLAGS\s*=.*KDE_PLUGIN/ ) { print STDERR "Report: $program contains undefined in $printname\n" if ($program =~ /^lib/ && $dryrun); return; } my $closure = $realname{$program} . ".closure"; my $lines = "$closure: \$($program\_OBJECTS) \$($program\_DEPENDENCIES)\n"; $lines .= "\t\@echo \"int main() {return 0;}\" > $program\_closure.$cxxsuffix\n"; $lines .= "\t\@\$\(LTCXXCOMPILE\) -c $program\_closure.$cxxsuffix\n"; $lines .= "\t\@\$\(CXXLINK\) $program\_closure.lo \$($program\_LDFLAGS) \$($program\_OBJECTS) \$($program\_LIBADD) \$(LIBS)\n"; $lines .= "\t\@rm -f $program\_closure.* $closure\n"; $lines .= "\t\@echo \"timestamp\" > $closure\n"; $lines .= "\n"; appendLines($lines); $lookup = $realname{$program} . ": (.*)"; if ($MakefileData =~ /\n$lookup\n/) { $lines = "\@KDE_USE_CLOSURE_TRUE@". $realname{$program} . ": $closure $1"; $lines .= "\n\@KDE_USE_CLOSURE_FALSE@" . $realname{$program} . ": $1"; substituteLine($lookup, $lines); } $closure_output .= " $closure"; } sub tag_DIST () { my %foundfiles = (); opendir (THISDIR, "."); foreach $entry (readdir(THISDIR)) { next if ($entry eq "CVS" || $entry =~ /^\./ || $entry =~ /^Makefile$$/ || $entry =~ /~$/ || $entry =~ /^\#.*\#$/); next if (! -f $entry); next if ($entry =~ /\.moc/ || $entry =~ /\.lo$/ || $entry =~ /\.la$/ || $entry =~ /\.o/); $foundfiles{$entry} = 1; } closedir (THISDIR); my @marks = ("EXTRA_DIST", "DIST_COMMON", '\S*_SOURCES', '\S*_HEADERS', 'MAINTAINERCLEANFILES', 'CLEANFILES', 'DISTCLEANFILES', '\S*_OBJECTS'); foreach $mark (@marks) { while ($MakefileData =~ /\n($mark)\s*=\s*([^\n]*)/g) { foreach $file (split('[\034\s]', $2)) { $file =~ s/\.\///; $foundfiles{$file} = 0 if (defined $foundfiles{$file}); } } } my @files = ("Makefile", "config.cache", "config.log", "stamp-h", "stamp-h1", "stamp-h1", "config.h", "Makefile", "config.status", "config.h", "libtool"); foreach $file (@files) { $foundfiles{$file} = 0 if (defined $foundfiles{$file}); } my $KDE_DIST = ""; foreach $file (keys %foundfiles) { if ($foundfiles{$file} == 1) { $KDE_DIST .= "$file "; } } if ($KDE_DIST) { print "KDE_DIST $printname $KDE_DIST\n" if ($verbose); my $lookup = "DISTFILES *=(.*)"; if ($MakefileData =~ /\n$lookup\n/o) { substituteLine($lookup, "KDE_DIST=$KDE_DIST\n\nDISTFILES=$1 \$(KDE_DIST)\n"); } } } #----------------------------------------------------------------------------- # Returns 0 if the line was processed - 1 otherwise. # Errors are logged in the global $errorflags sub tag_DOCFILES () { # if ($MakefileData =~ /\nSUBDIRS\s*=/) { # subdirs # $MakefileData =~ /\n(.*-recursive:\s*)\n/; # my $orig_rules = $1; # my $rules = $orig_rules; # $rules =~ s/:\s*$//; # substituteLine($orig_rules, "$rules docs-recursive:"); # appendLines("docs: docs-recursive docs-am\n"); # } else { # appendLines("docs: docs-am\n"); # } $target_adds{"all"} .= "docs-am "; my $lookup = 'KDE_DOCS\s*=\s*([^\n]*)'; goto nodocs if ($MakefileData !~ /\n$lookup/o); print STDOUT "KDE_DOCS processing <$1>\n" if ($verbose); my $tmp = $1; # Either find the files in the directory (AUTO) or use # only the specified po files. my $files = ""; my $appname = $tmp; $appname =~ s/^(\S*)\s*.*$/$1/; if ($appname =~ /AUTO/) { $appname = basename($makefileDir); if ("$appname" eq "en") { print STDERR "Error: KDE_DOCS = AUTO relies on the directory name. Yours is 'en' - you most likely want something else, e.g. KDE_DOCS = myapp\n"; exit(1); } } if ($tmp !~ / - /) { opendir (THISDIR, "."); foreach $entry (readdir(THISDIR)) { next if ($entry eq "CVS" || $entry =~ /^\./ || $entry =~ /^Makefile/ || $entry =~ /~$/ || $entry =~ /^\#.*\#$/); next if (! -f $entry); $files .= "$entry "; } closedir (THISDIR); print STDOUT "docfiles found = $files\n" if ($verbose); } else { $tmp =~ s/\034/ /g; $tmp =~ s/^\S*\s*-\s*//; $files = $tmp; } goto nodocs if (!$files); # Nothing to do if ($files =~ /(^| )index\.docbook($| )/) { my $lines = ""; my $lookup = 'MEINPROC\s*='; if ($MakefileData !~ /\n($lookup)/) { $lines = "MEINPROC=/\$(kde_bindir)/meinproc\n"; } $lookup = 'KDE_XSL_STYLESHEET\s*='; if ($MakefileData !~ /\n($lookup)/) { $lines .= "KDE_XSL_STYLESHEET=/\$(kde_datadir)/ksgmltools2/customization/kde-chunk.xsl\n"; } $lookup = '\nindex.cache.bz2:'; if ($MakefileData !~ /\n($lookup)/) { $lines .= "index.cache.bz2: \$(srcdir)/index.docbook \$(KDE_XSL_STYLESHEET) $files\n"; $lines .= "\t\@if test -n \"\$(MEINPROC)\"; then echo \$(MEINPROC) --check --cache index.cache.bz2 \$(srcdir)/index.docbook; \$(MEINPROC) --check --cache index.cache.bz2 \$(srcdir)/index.docbook; fi\n"; $lines .= "\n"; } $lines .= "docs-am: index.cache.bz2\n"; $lines .= "\n"; $lines .= "install-docs: docs-am install-nls\n"; $lines .= "\t\$(mkinstalldirs) \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname\n"; $lines .= "\t\@if test -f index.cache.bz2; then \\\n"; $lines .= "\techo \$(INSTALL_DATA) index.cache.bz2 \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/; \\\n"; $lines .= "\t\$(INSTALL_DATA) index.cache.bz2 \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/; \\\n"; $lines .= "\tfi\n"; $lines .= "\t-rm -f \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/common\n"; $lines .= "\t\$(LN_S) \$(kde_libs_htmldir)/$kdelang/common \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/common\n"; $lines .= "\n"; $lines .= "uninstall-docs:\n"; $lines .= "\t-rm -rf \$(kde_htmldir)/$kdelang/$appname\n"; $lines .= "\n"; $lines .= "clean-docs:\n"; $lines .= "\t-rm -f index.cache.bz2\n"; $lines .= "\n"; $target_adds{"install-data-am"} .= "install-docs "; $target_adds{"uninstall"} .= "uninstall-docs "; $target_adds{"clean-am"} .= "clean-docs "; appendLines ($lines); } else { appendLines("docs-am: $files\n"); } $target_adds{"install-data-am"} .= "install-nls"; $target_adds{"uninstall"} .= "uninstall-nls "; $tmp = "install-nls:\n"; $tmp .= "\t\$(mkinstalldirs) \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname\n"; $tmp .= "\t\@for base in $files; do \\\n"; $tmp .= "\t echo \$(INSTALL_DATA) \$\$base \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/\$\$base ;\\\n"; $tmp .= "\t \$(INSTALL_DATA) \$(srcdir)/\$\$base \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/\$\$base ;\\\n"; $tmp .= "\tdone\n"; if ($appname eq 'common') { $tmp .= "\t\@echo \"merging common and language specific dir\" ;\\\n"; $tmp .= "\tif test ! -e \$(kde_htmldir)/en/common/kde-common.css; then echo 'no english docs found in \$(kde_htmldir)/en/common/'; exit 1; fi \n"; $tmp .= "\t\@com_files=`cd \$(kde_htmldir)/en/common && echo *` ;\\\n"; $tmp .= "\tcd \$(DESTDIR)\$(kde_htmldir)/$kdelang/common ;\\\n"; $tmp .= "\tif test -n \"\$\$com_files\"; then for p in \$\$com_files ; do \\\n"; $tmp .= "\t case \" $files \" in \\\n"; $tmp .= "\t *\" \$\$p \"*) ;; \\\n"; $tmp .= "\t *) test ! -e \$\$p && echo \$(LN_S) ../../en/common/\$\$p \$(DESTDIR)\$(kde_htmldir)/$kdelang/common/\$\$p && \$(LN_S) ../../en/common/\$\$p \$\$p ;; \\\n"; $tmp .= "\t esac ; \\\n"; $tmp .= "\tdone ; fi ; true\n"; } $tmp .= "\n"; $tmp .= "uninstall-nls:\n"; $tmp .= "\tfor base in $files; do \\\n"; $tmp .= "\t rm -f \$(DESTDIR)\$(kde_htmldir)/$kdelang/$appname/\$\$base ;\\\n"; $tmp .= "\tdone\n\n"; appendLines ($tmp); $target_adds{"distdir"} .= "distdir-nls "; $tmp = "distdir-nls:\n"; $tmp .= "\tfor file in $files; do \\\n"; $tmp .= "\t cp \$(srcdir)/\$\$file \$(distdir); \\\n"; $tmp .= "\tdone\n"; appendLines ($tmp); return 0; nodocs: appendLines("docs-am:\n"); return 1; } #----------------------------------------------------------------------------- # Find headers in any of the source directories specified previously, that # are candidates for "moc-ing". sub findMocCandidates () { my @list = (); foreach $dir (@headerdirs) { opendir (SRCDIR, "$dir"); @hFiles = grep { /.+\.$hExt$/o } readdir(SRCDIR); closedir SRCDIR; foreach $hf (@hFiles) { open (HFIN, "$dir/$hf") || die "Could not open $dir/$hf: $!\n"; my $hfsize = 0; seek(HFIN, 0, 2); $hfsize = tell(HFIN); seek(HFIN, 0, 0); read HFIN, $hfData, $hfsize; close HFIN; # push (@list, $hf) if(index($hfData, "Q_OBJECT") >= 0); ### fast but doesn't handle //Q_OBJECT if ( $hfData =~ /{([^}]*)Q_OBJECT/s ) { ## handle " { friend class blah; Q_OBJECT " push (@list, $hf) unless $1 =~ m://[^\n]*Q_OBJECT[^\n]*$:s; ## handle "// Q_OBJECT" } } # The assoc array of root of headerfile and header filename foreach $hFile (@list) { $hFile =~ /(.*)\.[^\.]*$/; # Find name minus extension if ($mocFiles{$1}) { print STDERR "Warning: Multiple header files found for $1\n"; next; # Use the first one } $mocFiles{$1} = "$dir\035$hFile"; # Add relative dir } } return 0; } #----------------------------------------------------------------------------- # The programmer has specified a moc list. Prune out the moc candidates # list that we found based on looking at the header files. This generates # a warning if the programmer gets the list wrong, but this doesn't have # to be fatal here. sub pruneMocCandidates ($) { my %prunedMoc = (); local @mocList = split(' ', @_[0]); foreach $mocname (@mocList) { $mocname =~ s/\.moc$//; if ($mocFiles{$mocname}) { $prunedMoc{$mocname} = $mocFiles{$mocname}; } else { my $print = $makefileDir; $print =~ s/^\Q$topdir\E\\//; # They specified a moc file but we can't find a header that # will generate this moc file. That's possible fatal! print STDERR "Warning: No moc-able header file for $print/$mocname\n"; } } undef %mocFiles; %mocFiles = %prunedMoc; } #----------------------------------------------------------------------------- # Finds the cpp files (If they exist). # The cpp files get appended to the header file separated by \035 sub checkMocCandidates () { my @cppFiles; my $cpp2moc; # which c++ file includes which .moc files my $moc2cpp; # which moc file is included by which c++ files return unless (keys %mocFiles); opendir(THISDIR, ".") || return; @cppFiles = grep { /.+\.$cppExt$/o && !/.+\.moc\.$cppExt$/o && !/.+\.all_$cppExt\.$cppExt$/o } readdir(THISDIR); closedir THISDIR; return unless (@cppFiles); my $files = join (" ", @cppFiles); $cpp2moc = {}; $moc2cpp = {}; foreach $cxxf (@cppFiles) { open (CXXFIN, $cxxf) || die "Could not open $cxxf: $!\n"; seek(CXXFIN, 0, 2); my $cxxfsize = tell(CXXFIN); seek(CXXFIN, 0, 0); read CXXFIN, $cxxfData, $cxxfsize; close CXXFIN; while(($cxxfData =~ m/^[ \t]*\#include\s*[<\"](.*\.moc)[>\"]/gm)) { $cpp2moc->{$cxxf}->{$1} = 1; $moc2cpp->{$1}->{$cxxf} = 1; } } foreach my $mocFile (keys (%mocFiles)) { @cppFiles = keys %{$moc2cpp->{"$mocFile.moc"}}; if (@cppFiles == 1) { $mocFiles{$mocFile} .= "\035" . $cppFiles[0]; push(@deped, $mocFile); } elsif (@cppFiles == 0) { push (@newObs, $mocFile); # Produce new object file next if ($haveAutomocTag); # This is expected... # But this is an error we can deal with - let them know print STDERR "Warning: No c++ file that includes $mocFile.moc\n"; } else { # We can't decide which file to use, so it's fatal. Although as a # guess we could use the mocFile.cpp file if it's in the list??? print STDERR "Error: Multiple c++ files that include $mocFile.moc\n"; print STDERR "\t",join ("\t", @cppFiles),"\n"; $errorflag = 1; delete $mocFiles{$mocFile}; # Let's continue and see what happens - They have been told! } } } #----------------------------------------------------------------------------- # Add the rules for generating moc source from header files # For Automoc output *.moc.cpp but normally we'll output *.moc # (We must compile *.moc.cpp separately. *.moc files are included # in the appropriate *.cpp file by the programmer) sub addMocRules () { my $cppFile; my $hFile; foreach $mocFile (keys (%mocFiles)) { undef $cppFile; ($dir, $hFile, $cppFile) = split ("\035", $mocFiles{$mocFile}, 3); $dir =~ s#^\.#\$(srcdir)#; if (defined ($cppFile)) { $target_adds{"\$(srcdir)/$cppFile"} .= "$mocFile.moc "; appendLines ("$mocFile.moc: $dir/$hFile\n\t\$(MOC) $dir/$hFile -o $mocFile.moc\n"); $cleanMoc .= " $mocFile.moc"; } else { appendLines ("$mocFile$mocExt: $dir/$hFile\n\t\$(MOC) $dir/$hFile -o $mocFile$mocExt\n"); $cleanMoc .= " $mocFile$mocExt"; } } } sub make_meta_classes () { return if ($kdeopts{"qtonly"}); my $cppFile; my $hFile; my $moc_class_headers = ""; foreach $program (@programs) { my $mocs = ""; my @progsources = split(/[\s\034]+/, $sources{$program}); my @depmocs = split(' ', $depedmocs{$program}); my %shash = (), %mhash = (); @shash{@progsources} = 1; # we are only interested in the existence @mhash{@depmocs} = 1; print STDOUT "program=$program\n" if ($verbose); print STDOUT "psources=[".join(' ', keys %shash)."]\n" if ($verbose); print STDOUT "depmocs=[".join(' ', keys %mhash)."]\n" if ($verbose); print STDOUT "globalmocs=[".join(' ', keys(%globalmocs))."]\n" if ($verbose); foreach my $mocFile (keys (%globalmocs)) { undef $cppFile; ($dir, $hFile, $cppFile) = split ("\035", $globalmocs{$mocFile}, 3); $dir =~ s#^\.#\$(srcdir)#; if (defined ($cppFile)) { $mocs .= " $mocFile.moc" if exists $shash{$cppFile}; } else { # Bah. This is the case, if no C++ file includes the .moc # file. We make a .moc.cpp file for that. Unfortunately this # is not included in the %sources hash, but rather is mentioned # in %depedmocs. If the user wants to use AUTO he can't just # use an unspecific METAINCLUDES. Instead he must use # program_METAINCLUDES. Anyway, it's not working real nicely. # E.g. Its not clear what happens if user specifies two # METAINCLUDES=AUTO in the same Makefile.am. $mocs .= " $mocFile.moc.$cxxsuffix" if exists $mhash{$mocFile.".moc.$cxxsuffix"}; } } if ($mocs) { print STDOUT "==> mocs=[".$mocs."]\n" if ($verbose); my $sourcename = $program."_meta_unload"; my $ext = ($program =~ /_la$/) ? ".lo" : ".o"; my $srcfile = $sourcename.".$cxxsuffix"; my $objfile = $sourcename.$ext; $moc_class_headers .= " $srcfile"; my $appl; $appl = "$srcfile: $mocs\n"; $appl .= "\t\@echo 'creating $srcfile'\n"; $appl .= "\t\@-rm -f $srcfile\n"; $appl .= "\t\@echo 'static const char * _metalist_$program\[\] = {' > $srcfile\n"; $appl .= "\t\@cat $mocs | grep 'char.*className' | "; $appl .= "sed -e 's/.*[^A-Za-z0-9_:]\\([A-Za-z0-9_:]*\\)::className.*\$\$/\\\"\\1\\\",/' | sort | uniq >> $srcfile\n"; $appl .= "\t\@echo '0};' >> $srcfile\n"; $appl .= "\t\@echo '#include ' >> $srcfile\n"; $appl .= "\t\@echo '_UNLOAD($program)' >> $srcfile\n"; $appl .= "\n"; $realObjs{$program} .= " \034" . $objfile . " "; $sources{$program} .= " $srcfile"; $sources_changed{$program} = 1; $dep_files .= " \$(DEPDIR)/$sourcename.P"; appendLines ($appl); } print STDOUT "\n" if $verbose; } if ($moc_class_headers) { appendLines ("$cleantarget-moc-classes:\n\t-rm -f $moc_class_headers\n"); $target_adds{"$cleantarget-am"} .= "$cleantarget-moc-classes "; } } #----------------------------------------------------------------------------- sub updateMakefile () { return if ($dryrun); open (FILEOUT, "> $makefile") || die "Could not create $makefile: $!\n"; print FILEOUT "\# $progId - " . '$Revision$ ' . "\n"; $MakefileData =~ s/\034/\\\n/g; # Restore continuation lines print FILEOUT $MakefileData; close FILEOUT; } #----------------------------------------------------------------------------- # The given line needs to be removed from the makefile # Do this by adding the special "removed line" comment at the line start. sub removeLine ($$) { my ($lookup, $old) = @_; $old =~ s/\034/\\\n#>- /g; # Fix continuation lines $MakefileData =~ s/\n$lookup/\n#>\- $old/; } #----------------------------------------------------------------------------- # Replaces the old line with the new line # old line(s) are retained but tagged as removed. The new line(s) have the # "added" tag placed before it. sub substituteLine ($$) { my ($lookup, $new) = @_; if ($MakefileData =~ /\n($lookup)/) { $old = $1; $old =~ s/\034/\\\n#>\- /g; # Fix continuation lines $new =~ s/\034/\\\n/g; my $newCount = ($new =~ tr/\n//) + 1; $MakefileData =~ s/\n$lookup/\n#>- $old\n#>\+ $newCount\n$new/; } else { print STDERR "Warning: substitution of \"$lookup\" in $printname failed\n"; } } #----------------------------------------------------------------------------- # Slap new lines on the back of the file. sub appendLines ($) { my ($new) = @_; $new =~ s/\034/\\\n/g; # Fix continuation lines my $newCount = ($new =~ tr/\n//) + 1; $MakefileData .= "\n#>\+ $newCount\n$new"; } #----------------------------------------------------------------------------- # Restore the Makefile.in to the state it was before we fiddled with it sub restoreMakefile () { $MakefileData =~ s/# $progId[^\n\034]*[\n\034]*//g; # Restore removed lines $MakefileData =~ s/([\n\034])#>\- /$1/g; # Remove added lines while ($MakefileData =~ /[\n\034]#>\+ ([^\n\034]*)/) { my $newCount = $1; my $removeLines = ""; while ($newCount--) { $removeLines .= "[^\n\034]*([\n\034]|)"; } $MakefileData =~ s/[\n\034]#>\+.*[\n\034]$removeLines/\n/; } } #-----------------------------------------------------------------------------