| #!/usr/bin/env perl |
| # |
| # Copyright (C) 2016 Sony Interactive Entertainment Inc. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions |
| # are met: |
| # 1. Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # |
| # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY |
| # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| # |
| |
| use strict; |
| use warnings; |
| use FindBin; |
| use lib $FindBin::Bin; |
| |
| use File::Basename; |
| use File::Spec; |
| use File::Find; |
| use Getopt::Long; |
| |
| my $perl = $^X; |
| my $scriptDir = $FindBin::Bin; |
| my @idlDirectories; |
| my $outputDirectory; |
| my $idlFilesList; |
| my $generator; |
| my @generatorDependency; |
| my $defines; |
| my $preprocessor; |
| my $supplementalDependencyFile; |
| my @ppExtraOutput; |
| my @ppExtraArgs; |
| my $numOfJobs = 1; |
| my $idlAttributesFile; |
| my $showProgress; |
| |
| GetOptions('include=s@' => \@idlDirectories, |
| 'outputDir=s' => \$outputDirectory, |
| 'idlFilesList=s' => \$idlFilesList, |
| 'generator=s' => \$generator, |
| 'generatorDependency=s@' => \@generatorDependency, |
| 'defines=s' => \$defines, |
| 'preprocessor=s' => \$preprocessor, |
| 'supplementalDependencyFile=s' => \$supplementalDependencyFile, |
| 'ppExtraOutput=s@' => \@ppExtraOutput, |
| 'ppExtraArgs=s@' => \@ppExtraArgs, |
| 'idlAttributesFile=s' => \$idlAttributesFile, |
| 'numOfJobs=i' => \$numOfJobs, |
| 'showProgress' => \$showProgress); |
| |
| $| = 1; |
| my @idlFiles; |
| open(my $fh, '<', $idlFilesList) or die "Cannot open $idlFilesList"; |
| @idlFiles = map { CygwinPathIfNeeded(s/\r?\n?$//r) } <$fh>; |
| close($fh) or die; |
| |
| my %oldSupplements; |
| my %newSupplements; |
| if ($supplementalDependencyFile) { |
| my @output = ($supplementalDependencyFile, @ppExtraOutput); |
| my @deps = ($idlFilesList, @idlFiles, @generatorDependency); |
| if (needsUpdate(\@output, \@deps)) { |
| readSupplementalDependencyFile($supplementalDependencyFile, \%oldSupplements) if -e $supplementalDependencyFile; |
| my @args = (File::Spec->catfile($scriptDir, 'preprocess-idls.pl'), |
| '--defines', $defines, |
| '--idlFilesList', $idlFilesList, |
| '--supplementalDependencyFile', $supplementalDependencyFile, |
| @ppExtraArgs); |
| printProgress("Preprocess IDL"); |
| executeCommand($perl, @args) == 0 or die; |
| } |
| readSupplementalDependencyFile($supplementalDependencyFile, \%newSupplements); |
| } |
| |
| my @args = (File::Spec->catfile($scriptDir, 'generate-bindings.pl'), |
| '--defines', $defines, |
| '--generator', $generator, |
| '--outputDir', $outputDirectory, |
| '--preprocessor', $preprocessor, |
| '--idlAttributesFile', $idlAttributesFile, |
| '--write-dependencies'); |
| push @args, map { ('--include', $_) } @idlDirectories; |
| push @args, '--supplementalDependencyFile', $supplementalDependencyFile if $supplementalDependencyFile; |
| |
| my %directoryCache; |
| buildDirectoryCache(); |
| |
| my @idlFilesToUpdate = grep &{sub { |
| if (defined($oldSupplements{$_}) |
| && @{$oldSupplements{$_}} ne @{$newSupplements{$_} or []}) { |
| # Re-process the IDL file if its supplemental dependencies were added or removed |
| return 1; |
| } |
| my ($filename, $dirs, $suffix) = fileparse($_, '.idl'); |
| my $sourceFile = File::Spec->catfile($outputDirectory, "JS$filename.cpp"); |
| my $headerFile = File::Spec->catfile($outputDirectory, "JS$filename.h"); |
| my $depFile = File::Spec->catfile($outputDirectory, "JS$filename.dep"); |
| my @output = ($sourceFile, $headerFile); |
| my @deps = ($_, |
| $idlAttributesFile, |
| @generatorDependency, |
| @{$newSupplements{$_} or []}, |
| implicitDependencies($depFile)); |
| needsUpdate(\@output, \@deps); |
| }}, @idlFiles; |
| |
| my $abort = 0; |
| my $totalCount = @idlFilesToUpdate; |
| my $currentCount = 0; |
| |
| spawnGenerateBindingsIfNeeded() for (1 .. $numOfJobs); |
| while (waitpid(-1, 0) != -1) { |
| if ($?) { |
| $abort = 1; |
| } |
| spawnGenerateBindingsIfNeeded(); |
| } |
| exit $abort; |
| |
| sub needsUpdate |
| { |
| my ($objects, $depends) = @_; |
| my $oldestObjectTime; |
| for (@$objects) { |
| return 1 if !-f; |
| my $m = mtime($_); |
| if (!defined $oldestObjectTime || $m < $oldestObjectTime) { |
| $oldestObjectTime = $m; |
| } |
| } |
| for (@$depends) { |
| die "Missing required dependency: $_" if !-f; |
| my $m = mtime($_); |
| if ($oldestObjectTime < $m) { |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| sub mtime |
| { |
| my ($file) = @_; |
| return (stat $file)[9]; |
| } |
| |
| sub spawnGenerateBindingsIfNeeded |
| { |
| return if $abort; |
| return unless @idlFilesToUpdate; |
| my $batchCount = 30; |
| # my $batchCount = int(($totalCount - $currentCount) / $numOfJobs) || 1; |
| my @files = splice(@idlFilesToUpdate, 0, $batchCount); |
| for (@files) { |
| $currentCount++; |
| my $basename = basename($_); |
| printProgress("[$currentCount/$totalCount] $basename"); |
| } |
| my $pid = spawnCommand($perl, @args, @files); |
| $abort = 1 unless defined $pid; |
| } |
| |
| sub buildDirectoryCache |
| { |
| my $wanted = sub { |
| $directoryCache{$_} = $File::Find::name; |
| $File::Find::prune = 1 unless ~/\./; |
| }; |
| find($wanted, @idlDirectories); |
| } |
| |
| sub implicitDependencies |
| { |
| my ($depFile) = @_; |
| return () unless -f $depFile; |
| open(my $fh, '<', $depFile) or die "Cannot open $depFile"; |
| my $firstLine = <$fh>; |
| close($fh) or die; |
| my (undef, $deps) = split(/ : /, $firstLine); |
| my @deps = split(/\s+/, $deps); |
| return map { $directoryCache{$_} or () } @deps; |
| } |
| |
| sub executeCommand |
| { |
| if ($^O eq 'MSWin32') { |
| return system(quoteCommand(@_)); |
| } |
| return system(@_); |
| } |
| |
| sub spawnCommand |
| { |
| my $pid = fork(); |
| if ($pid == 0) { |
| @_ = quoteCommand(@_) if ($^O eq 'MSWin32'); |
| exec(@_); |
| die "Cannot exec"; |
| } |
| return $pid; |
| } |
| |
| sub quoteCommand |
| { |
| return map { |
| '"' . s/([\\\"])/\\$1/gr . '"'; |
| } @_; |
| } |
| |
| sub CygwinPathIfNeeded |
| { |
| my $path = shift; |
| return Cygwin::win_to_posix_path($path) if ($^O eq 'cygwin'); |
| return $path; |
| } |
| |
| sub readSupplementalDependencyFile |
| { |
| my $filename = shift; |
| my $supplements = shift; |
| open(my $fh, '<', $filename) or die "Cannot open $filename"; |
| while (<$fh>) { |
| my ($idlFile, @followingIdlFiles) = split(/\s+/); |
| $supplements->{$idlFile} = [sort @followingIdlFiles]; |
| } |
| close($fh) or die; |
| } |
| |
| sub printProgress |
| { |
| return unless $showProgress; |
| my $msg = shift; |
| print "$msg\n"; |
| } |