1#!/usr/bin/perl -w 2# 3# Copyright (C) 2005 Apple Inc. 4# Copyright (C) 2006 Anders Carlsson <andersca@mac.com> 5# 6# This file is part of WebKit 7# 8# This library is free software; you can redistribute it and/or 9# modify it under the terms of the GNU Library General Public 10# License as published by the Free Software Foundation; either 11# version 2 of the License, or (at your option) any later version. 12# 13# This library is distributed in the hope that it will be useful, 14# but WITHOUT ANY WARRANTY; without even the implied warranty of 15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16# Library General Public License for more details. 17# 18# You should have received a copy of the GNU Library General Public License 19# along with this library; see the file COPYING.LIB. If not, write to 20# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21# Boston, MA 02110-1301, USA. 22# 23 24# This script is a temporary hack. 25# Files are generated in the source directory, when they really should go 26# to the DerivedSources directory. 27# This should also eventually be a build rule driven off of .idl files 28# however a build rule only solution is blocked by several radars: 29# <rdar://problems/4251781&4251785> 30 31use strict; 32 33use File::Path; 34use File::Basename; 35use Getopt::Long; 36use Text::ParseWords; 37use Cwd; 38 39use IDLParser; 40use CodeGenerator; 41 42my @idlDirectories; 43my $outputDirectory; 44my $outputHeadersDirectory; 45my $generator; 46my $defines; 47my $filename; 48my $prefix; 49my $preprocessor; 50my $writeDependencies; 51my $verbose; 52my $supplementalDependencyFile; 53my $additionalIdlFiles; 54my $idlAttributesFile; 55 56GetOptions('include=s@' => \@idlDirectories, 57 'outputDir=s' => \$outputDirectory, 58 'outputHeadersDir=s' => \$outputHeadersDirectory, 59 'generator=s' => \$generator, 60 'defines=s' => \$defines, 61 'filename=s' => \$filename, 62 'prefix=s' => \$prefix, 63 'preprocessor=s' => \$preprocessor, 64 'verbose' => \$verbose, 65 'write-dependencies' => \$writeDependencies, 66 'supplementalDependencyFile=s' => \$supplementalDependencyFile, 67 'additionalIdlFiles=s' => \$additionalIdlFiles, 68 'idlAttributesFile=s' => \$idlAttributesFile); 69 70my $targetIdlFile = $ARGV[0]; 71 72die('Must specify input file.') unless defined($targetIdlFile); 73die('Must specify generator') unless defined($generator); 74die('Must specify output directory.') unless defined($outputDirectory); 75 76if (!$outputHeadersDirectory) { 77 $outputHeadersDirectory = $outputDirectory; 78} 79$targetIdlFile = Cwd::realpath($targetIdlFile); 80if ($verbose) { 81 print "$generator: $targetIdlFile\n"; 82} 83my $targetInterfaceName = fileparse(basename($targetIdlFile), ".idl"); 84 85my $idlFound = 0; 86my @supplementedIdlFiles; 87if ($supplementalDependencyFile) { 88 # The format of a supplemental dependency file: 89 # 90 # DOMWindow.idl P.idl Q.idl R.idl 91 # Document.idl S.idl 92 # Event.idl 93 # ... 94 # 95 # The above indicates that DOMWindow.idl is supplemented by P.idl, Q.idl and R.idl, 96 # Document.idl is supplemented by S.idl, and Event.idl is supplemented by no IDLs. 97 # The IDL that supplements another IDL (e.g. P.idl) never appears in the dependency file. 98 open FH, "< $supplementalDependencyFile" or die "Cannot open $supplementalDependencyFile\n"; 99 while (my $line = <FH>) { 100 my ($idlFile, @followingIdlFiles) = split(/\s+/, $line); 101 if ($idlFile and basename($idlFile) eq basename($targetIdlFile)) { 102 $idlFound = 1; 103 @supplementedIdlFiles = sort @followingIdlFiles; 104 } 105 } 106 close FH; 107 108 # $additionalIdlFiles is list of IDL files which should not be included in 109 # DerivedSources*.cpp (i.e. they are not described in the supplemental 110 # dependency file) but should generate .h and .cpp files. 111 if (!$idlFound and $additionalIdlFiles) { 112 my @idlFiles = shellwords($additionalIdlFiles); 113 $idlFound = grep { $_ and basename($_) eq basename($targetIdlFile) } @idlFiles; 114 } 115 116 if (!$idlFound) { 117 my $codeGen = CodeGenerator->new(\@idlDirectories, $generator, $outputDirectory, $outputHeadersDirectory, 0, $preprocessor, $writeDependencies, $verbose); 118 119 # We generate empty .h and .cpp files just to tell build scripts that .h and .cpp files are created. 120 generateEmptyHeaderAndCpp($codeGen->FileNamePrefix(), $targetInterfaceName, $outputHeadersDirectory, $outputDirectory); 121 exit 0; 122 } 123} 124 125# Parse the target IDL file. 126my $targetParser = IDLParser->new(!$verbose); 127my $targetDocument = $targetParser->Parse($targetIdlFile, $defines, $preprocessor); 128 129if ($idlAttributesFile) { 130 my $idlAttributes = loadIDLAttributes($idlAttributesFile); 131 checkIDLAttributes($idlAttributes, $targetDocument, basename($targetIdlFile)); 132} 133 134foreach my $idlFile (@supplementedIdlFiles) { 135 next if $idlFile eq $targetIdlFile; 136 137 my $interfaceName = fileparse(basename($idlFile), ".idl"); 138 my $parser = IDLParser->new(!$verbose); 139 my $document = $parser->Parse($idlFile, $defines, $preprocessor); 140 141 foreach my $interface (@{$document->interfaces}) { 142 if (!$interface->isPartial || $interface->name eq $targetInterfaceName) { 143 my $targetDataNode; 144 foreach my $interface (@{$targetDocument->interfaces}) { 145 if ($interface->name eq $targetInterfaceName) { 146 $targetDataNode = $interface; 147 last; 148 } 149 } 150 die "Not found an interface ${targetInterfaceName} in ${targetInterfaceName}.idl." unless defined $targetDataNode; 151 152 # Support for attributes of partial interfaces. 153 foreach my $attribute (@{$interface->attributes}) { 154 # Record that this attribute is implemented by $interfaceName. 155 $attribute->signature->extendedAttributes->{"ImplementedBy"} = $interfaceName if $interface->isPartial; 156 157 # Add interface-wide extended attributes to each attribute. 158 foreach my $extendedAttributeName (keys %{$interface->extendedAttributes}) { 159 $attribute->signature->extendedAttributes->{$extendedAttributeName} = $interface->extendedAttributes->{$extendedAttributeName}; 160 } 161 push(@{$targetDataNode->attributes}, $attribute); 162 } 163 164 # Support for methods of partial interfaces. 165 foreach my $function (@{$interface->functions}) { 166 # Record that this method is implemented by $interfaceName. 167 $function->signature->extendedAttributes->{"ImplementedBy"} = $interfaceName if $interface->isPartial; 168 169 # Add interface-wide extended attributes to each method. 170 foreach my $extendedAttributeName (keys %{$interface->extendedAttributes}) { 171 $function->signature->extendedAttributes->{$extendedAttributeName} = $interface->extendedAttributes->{$extendedAttributeName}; 172 } 173 push(@{$targetDataNode->functions}, $function); 174 } 175 176 # Support for constants of partial interfaces. 177 foreach my $constant (@{$interface->constants}) { 178 # Record that this constant is implemented by $interfaceName. 179 $constant->extendedAttributes->{"ImplementedBy"} = $interfaceName if $interface->isPartial; 180 181 # Add interface-wide extended attributes to each constant. 182 foreach my $extendedAttributeName (keys %{$interface->extendedAttributes}) { 183 $constant->extendedAttributes->{$extendedAttributeName} = $interface->extendedAttributes->{$extendedAttributeName}; 184 } 185 push(@{$targetDataNode->constants}, $constant); 186 } 187 } else { 188 die "$idlFile is not a supplemental dependency of $targetIdlFile. There maybe a bug in the the supplemental dependency generator (preprocess-idls.pl).\n"; 189 } 190 } 191} 192 193# Generate desired output for the target IDL file. 194my $codeGen = CodeGenerator->new(\@idlDirectories, $generator, $outputDirectory, $outputHeadersDirectory, 0, $preprocessor, $writeDependencies, $verbose, $targetIdlFile); 195$codeGen->ProcessDocument($targetDocument, $defines); 196 197sub generateEmptyHeaderAndCpp 198{ 199 my ($prefix, $targetInterfaceName, $outputHeadersDirectory, $outputDirectory) = @_; 200 201 my $headerName = "${prefix}${targetInterfaceName}.h"; 202 my $cppName = "${prefix}${targetInterfaceName}.cpp"; 203 my $contents = "/* 204 This file is generated just to tell build scripts that $headerName and 205 $cppName are created for ${targetInterfaceName}.idl, and thus 206 prevent the build scripts from trying to generate $headerName and 207 $cppName at every build. This file must not be tried to compile. 208*/ 209"; 210 open FH, "> ${outputHeadersDirectory}/${headerName}" or die "Cannot open $headerName\n"; 211 print FH $contents; 212 close FH; 213 214 open FH, "> ${outputDirectory}/${cppName}" or die "Cannot open $cppName\n"; 215 print FH $contents; 216 close FH; 217} 218 219sub loadIDLAttributes 220{ 221 my $idlAttributesFile = shift; 222 223 my %idlAttributes; 224 open FH, "<", $idlAttributesFile or die "Couldn't open $idlAttributesFile: $!"; 225 while (my $line = <FH>) { 226 chomp $line; 227 next if $line =~ /^\s*#/; 228 next if $line =~ /^\s*$/; 229 230 if ($line =~ /^\s*([^=\s]*)\s*=?\s*(.*)/) { 231 my $name = $1; 232 $idlAttributes{$name} = {}; 233 if ($2) { 234 foreach my $rightValue (split /\|/, $2) { 235 $rightValue =~ s/^\s*|\s*$//g; 236 $rightValue = "VALUE_IS_MISSING" unless $rightValue; 237 $idlAttributes{$name}{$rightValue} = 1; 238 } 239 } else { 240 $idlAttributes{$name}{"VALUE_IS_MISSING"} = 1; 241 } 242 } else { 243 die "The format of " . basename($idlAttributesFile) . " is wrong: line $.\n"; 244 } 245 } 246 close FH; 247 248 return \%idlAttributes; 249} 250 251sub checkIDLAttributes 252{ 253 my $idlAttributes = shift; 254 my $document = shift; 255 my $idlFile = shift; 256 257 foreach my $interface (@{$document->interfaces}) { 258 checkIfIDLAttributesExists($idlAttributes, $interface->extendedAttributes, $idlFile); 259 260 foreach my $attribute (@{$interface->attributes}) { 261 checkIfIDLAttributesExists($idlAttributes, $attribute->signature->extendedAttributes, $idlFile); 262 } 263 264 foreach my $function (@{$interface->functions}) { 265 checkIfIDLAttributesExists($idlAttributes, $function->signature->extendedAttributes, $idlFile); 266 foreach my $parameter (@{$function->parameters}) { 267 checkIfIDLAttributesExists($idlAttributes, $parameter->extendedAttributes, $idlFile); 268 } 269 } 270 } 271} 272 273sub checkIfIDLAttributesExists 274{ 275 my $idlAttributes = shift; 276 my $extendedAttributes = shift; 277 my $idlFile = shift; 278 279 my $error; 280 OUTER: for my $name (keys %$extendedAttributes) { 281 if (!exists $idlAttributes->{$name}) { 282 $error = "Unknown IDL attribute [$name] is found at $idlFile."; 283 last OUTER; 284 } 285 if ($idlAttributes->{$name}{"*"}) { 286 next; 287 } 288 for my $rightValue (split /\s*[|&]\s*/, $extendedAttributes->{$name}) { 289 if (!exists $idlAttributes->{$name}{$rightValue}) { 290 $error = "Unknown IDL attribute [$name=" . $extendedAttributes->{$name} . "] is found at $idlFile."; 291 last OUTER; 292 } 293 } 294 } 295 if ($error) { 296 die "IDL ATTRIBUTE CHECKER ERROR: $error 297If you want to add a new IDL attribute, you need to add it to WebCore/bindings/scripts/IDLAttributes.txt and add explanations to the WebKit IDL document (https://trac.webkit.org/wiki/WebKitIDL). 298"; 299 } 300} 301