| #!/usr/bin/env perl | 
 | use strict; | 
 | use File::Find; | 
 | use File::Copy; | 
 | use Digest::MD5; | 
 |  | 
 | my @fileTypes = ("cpp", "c"); | 
 | my %dirFiles; | 
 | my %dirCMake; | 
 |  | 
 | sub GetFiles { | 
 |   my $dir = shift; | 
 |   my $x = $dirFiles{$dir};   | 
 |   if (!defined $x) { | 
 |     $x = []; | 
 |     $dirFiles{$dir} = $x; | 
 |   }   | 
 |   return $x; | 
 | } | 
 |  | 
 | sub ProcessFile { | 
 |   my $file = $_; | 
 |   my $dir = $File::Find::dir; | 
 |   # Record if a CMake file was found. | 
 |   if ($file eq "CMakeLists.txt") { | 
 |     $dirCMake{$dir} = $File::Find::name; | 
 |     return 0; | 
 |   } | 
 |   # Grab the extension of the file. | 
 |   $file =~ /\.([^.]+)$/; | 
 |   my $ext = $1; | 
 |   my $files; | 
 |   foreach my $x (@fileTypes) { | 
 |     if ($ext eq $x) { | 
 |       if (!defined $files) { | 
 |         $files = GetFiles($dir); | 
 |       } | 
 |       push @$files, $file; | 
 |       return 0; | 
 |     } | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | sub EmitCMakeList { | 
 |   my $dir = shift; | 
 |   my $files = $dirFiles{$dir}; | 
 |    | 
 |   if (!defined $files) { | 
 |     return; | 
 |   } | 
 |    | 
 |   foreach my $file (sort @$files) { | 
 |     print OUT "  "; | 
 |     print OUT $file; | 
 |     print OUT "\n"; | 
 |   }   | 
 | } | 
 |  | 
 | sub UpdateCMake { | 
 |   my $cmakeList = shift; | 
 |   my $dir = shift; | 
 |   my $cmakeListNew = $cmakeList . ".new"; | 
 |   open(IN, $cmakeList); | 
 |   open(OUT, ">", $cmakeListNew); | 
 |   my $foundLibrary = 0; | 
 |    | 
 |   while(<IN>) { | 
 |     if (!$foundLibrary) { | 
 |       print OUT $_; | 
 |       if (/^add_clang_library\(/ || /^add_llvm_library\(/ || /^add_llvm_target\(/ | 
 |           || /^add_executable\(/) { | 
 |         $foundLibrary = 1; | 
 |         EmitCMakeList($dir); | 
 |       } | 
 |     } | 
 |     else { | 
 |       if (/\)/) { | 
 |         print OUT $_; | 
 |         $foundLibrary = 0; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   close(IN); | 
 |   close(OUT); | 
 |  | 
 |   open(FILE, $cmakeList) or | 
 |     die("Cannot open $cmakeList when computing digest\n"); | 
 |   binmode FILE; | 
 |   my $digestA = Digest::MD5->new->addfile(*FILE)->hexdigest; | 
 |   close(FILE); | 
 |      | 
 |   open(FILE, $cmakeListNew) or | 
 |     die("Cannot open $cmakeListNew when computing digest\n"); | 
 |   binmode FILE; | 
 |   my $digestB = Digest::MD5->new->addfile(*FILE)->hexdigest; | 
 |   close(FILE); | 
 |    | 
 |   if ($digestA ne $digestB) { | 
 |     move($cmakeListNew, $cmakeList); | 
 |     return 1;     | 
 |   } | 
 |    | 
 |   unlink($cmakeListNew); | 
 |   return 0; | 
 | } | 
 |  | 
 | sub UpdateCMakeFiles { | 
 |   foreach my $dir (sort keys %dirCMake) { | 
 |     if (UpdateCMake($dirCMake{$dir}, $dir)) { | 
 |       print "Updated: $dir\n"; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | find({ wanted => \&ProcessFile, follow => 1 }, '.'); | 
 | UpdateCMakeFiles(); | 
 |  |