1#!/usr/bin/perl
2
3# Copyright (C) 2006, 2007, 2008, 2010, 2011 Apple Inc. All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions
7# are met:
8# 1. Redistributions of source code must retain the above copyright
9#    notice, this list of conditions and the following disclaimer.
10# 2. Redistributions in binary form must reproduce the above copyright
11#    notice, this list of conditions and the following disclaimer in the
12#    documentation and/or other materials provided with the distribution.
13#
14# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24# THE POSSIBILITY OF SUCH DAMAGE.
25
26# "check-for-inappropriate-objc-class-names" script for WebKit Open Source Project
27
28# Intended to be invoked from an Xcode build step to check if a framework
29# defines any Objective-C class whose name does not have one of the prefixes
30# the framework is allowed to use.
31
32use warnings;
33use strict;
34
35use File::Basename;
36
37sub touch($);
38
39my @allowedPrefixes = @ARGV;
40
41# Xcode will automatically link ObjC binaries against libarclite in some cases, which defines a class called __ARCLite__.
42push(@allowedPrefixes, "__ARCLite");
43
44die "No allowed prefixes passed on the command line" if !@allowedPrefixes;
45
46my $arch = $ENV{'CURRENT_ARCH'};
47my $target = $ENV{'TARGET_NAME'};
48my $variant = $ENV{'CURRENT_VARIANT'};
49my $coverageBuild = $ENV{'WEBKIT_COVERAGE_BUILD'};
50
51my $executablePath = "$ENV{'TARGET_BUILD_DIR'}/$ENV{'EXECUTABLE_PATH'}";
52
53my $buildTimestampPath = $ENV{'TARGET_TEMP_DIR'} . "/" . basename($0) . join('-', @allowedPrefixes) . ".timestamp";
54my $buildTimestampAge = -M $buildTimestampPath;
55my $executablePathAge = -M $executablePath;
56my $scriptAge = -M $0;
57
58my $pattern = "^(" . join('|', @allowedPrefixes) . ")";
59
60my $sawError = 0;
61
62if (!defined $executablePathAge || !defined $buildTimestampAge || $executablePathAge < $buildTimestampAge || $scriptAge < $buildTimestampAge) {
63    if (!open NM, "(nm -Ugjp '$executablePath' | sed 's/^/STDOUT:/') 2>&1 |") {
64        print "ERROR: Could not open $executablePath\n";
65        $sawError = 1;
66        next;
67    }
68    my @badNames;
69    while (<NM>) {
70        if (/^STDOUT:/) {
71            next unless /^STDOUT:_OBJC_CLASS_\$_/;
72            chomp;
73            my $className = substr($_, 21);
74            push(@badNames, $className) unless $className =~ /$pattern/;
75        } else {
76            print STDERR if $_ ne "nm: no name list\n";
77        }
78    }
79    close NM;
80
81    if (@badNames) {
82
83        my $shortName = $executablePath;
84        $shortName =~ s/.*\///;
85
86        print "ERROR: $shortName defines one or more Objective-C classes with inappropriate names. ($executablePath)\n";
87        for my $className (@badNames) {
88            print "ERROR: Inappropriate Objective-C class name: $className.\n";
89        }
90
91        if (@allowedPrefixes > 1) {
92            print "ERROR: Objective-C class names in $target must have one of these prefixes: " . join(", ", map('"' . $_ . '"', @allowedPrefixes)) . ".\n";
93        } else {
94            print "ERROR: Objective-C class names in $target must have the prefix \"" . $allowedPrefixes[0] . "\".\n";
95        }
96
97        $sawError = 1;
98    }
99}
100
101if ($sawError and !$coverageBuild) {
102    unlink $executablePath;
103    exit 1;
104}
105
106touch($buildTimestampPath);
107exit 0;
108
109sub touch($)
110{
111    my ($path) = @_;
112    open(TOUCH, ">", $path) or die "$!";
113    close(TOUCH);
114}
115