blob: afa02102090bc68333a5e0a9109bb4e54a84ef7b [file] [log] [blame]
#!/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";
}