meta/checkheaders.pl (148 lines of code) (raw):
#!/usr/bin/perl
#
# Copyright (c) 2014 Microsoft Open Technologies, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
# FOR A PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
#
# See the Apache Version 2.0 License for specific language governing
# permissions and limitations under the License.
#
# Microsoft would like to thank the following companies for their review and
# assistance with these files: Intel Corporation, Mellanox Technologies Ltd,
# Dell Products, L.P., Facebook, Inc., Marvell International Ltd.
#
# @file checkheaders.pl
#
# @brief This module defines integration check for 2 header directories
#
BEGIN { push @INC,'.'; }
use strict;
use warnings;
use diagnostics;
use File::Temp qw/ tempfile /;
use Data::Dumper;
use Getopt::Std;
my %options = ();
getopts("s", \%options);
my $optionSkipSingleDefined = 1 if defined $options{s};
use utils;
sub CheckArguments
{
if (scalar @ARGV != 2)
{
print "expected 2 arguments which are SAI/inc directories: dirA dirB\n";
exit 1;
}
}
sub CheckDirExists
{
my $dir = shift;
if (not -d $dir)
{
print "not directory $dir\n";
exit 1;
}
}
CheckArguments;
sub FilterEnums
{
my ($data, $path) = @_;
my @lines = split/[\r\n]+/,$data;
my %enums = ();
my $nr = 0;
for my $line (@lines)
{
$nr++;
next if not $line =~ /^\s*(SAI_\w+)/;
my $key = $1;
$enums{$key}{path} = $path;
$enums{$key}{line} = $line;
$enums{$key}{nr} = $nr;
$enums{$key}{value} = "undefined";
}
return %enums;
}
my $dirA = shift @ARGV;
my $dirB = shift @ARGV;
sub GetEnums
{
my $dir = shift;
CheckDirExists $dir;
my @files = GetHeaderFiles $dir;
my %enums = ();
for my $file (@files)
{
my $data = ReadHeaderFile("$dir/$file");
my %en = FilterEnums($data, "$dir/$file");
%enums = (%enums, %en);
}
return %enums;
}
sub ConstructSource
{
my ($dir, $ref) = @_;
my %enums = %{ $ref };
my $source = "#include <stdio.h>\n";
$source .= "#include \"$dir/sai.h\"\n";
$source .="int main() { ";
for my $en (sort keys %enums)
{
$source .= "printf(\"%d\\n\", $en);\n";
}
$source .= "return 0; }";
return $source;
}
sub GetValues
{
my $dir = shift;
my %enums = GetEnums $dir;
my $source = ConstructSource($dir, \%enums);
my ($fhs, $src) = tempfile( SUFFIX => '.c', UNLINK => 1 );
WriteFile($src, $source);
my ($fhb, $bin) = tempfile( SUFFIX => '.bin', UNLINK => 1 );
system("gcc $src -I. -I '$dir'/../experimental -I '$dir' -o $bin") == 0 or die "gcc failed! $!";
close $fhs;
close $fhb;
my %hash = ();
my @lines = `$bin`;
for my $key (sort keys %enums)
{
my $line = shift @lines;
$enums{$key}{value} = $1 if $line =~ /(\d+)/;
}
return %enums;
}
my %valuesA = GetValues $dirA;
my %valuesB = GetValues $dirB;
File::Temp::cleanup();
sub CheckHash
{
my ($refA, $refB) = @_;
my %A = %{$refA};
my %B = %{$refB};
for my $key (sort keys %A)
{
if (defined $optionSkipSingleDefined)
{
# ignore attributes end, since those will shift
next if $key =~ /^SAI_\w+_ATTR_END$/;
next if $key =~ /^SAI_\w+_ATTR_CUSTOM_RANGE_END$/;
next if $key eq "SAI_IN_DROP_REASON_END";
next if $key eq "SAI_ACL_TABLE_ATTR_FIELD_END";
next if $key eq "SAI_ACL_ENTRY_ATTR_FIELD_END";
next if $key eq "SAI_ACL_ENTRY_ATTR_ACTION_END";
next if $key eq "SAI_OBJECT_TYPE_MAX";
next if $key eq "SAI_API_MAX";
next if $key eq "SAI_PORT_INTERFACE_TYPE_MAX";
next if $key eq "SAI_PORT_BREAKOUT_MODE_TYPE_MAX";
# NOTE: some other attributes/enum with END range could be added
}
if (not defined $B{$key})
{
if (not defined $optionSkipSingleDefined)
{
LogError "enum $key only defined in $A{$key}{path}:$A{$key}{nr}"
}
else
{
LogInfo "enum $key only defined in $A{$key}{path}:$A{$key}{nr}"
}
next;
}
my $valA = $A{$key}{value};
my $valB = $B{$key}{value};
if ($valA ne $valB)
{
my $locA = "$A{$key}{path}:$A{$key}{nr}";
my $locB = "$B{$key}{path}:$B{$key}{nr}";
LogError "value of $key differ: $locA vs $locB => ($valA != $valB)";
}
}
}
CheckHash(\%valuesA, \%valuesB);
CheckHash(\%valuesB, \%valuesA);
ExitOnErrors;
LogInfo "headers $dirA and $dirB MATCH!";