1#!/usr/bin/env perl 2#*************************************************************************** 3# _ _ ____ _ 4# Project ___| | | | _ \| | 5# / __| | | | |_) | | 6# | (__| |_| | _ <| |___ 7# \___|\___/|_| \_\_____| 8# 9# Copyright (C) 2010 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. 10# 11# This software is licensed as described in the file COPYING, which 12# you should have received as part of this distribution. The terms 13# are also available at https://curl.haxx.se/docs/copyright.html. 14# 15# You may opt to use, copy, modify, merge, publish, distribute and/or sell 16# copies of the Software, and permit persons to whom the Software is 17# furnished to do so, under the terms of the COPYING file. 18# 19# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 20# KIND, either express or implied. 21# 22########################################################################### 23# 24# This script grew out of help from Przemyslaw Iskra and Balint Szilakszi 25# a late evening in the #curl IRC channel on freenode. 26# 27 28use strict; 29use warnings; 30use vars qw($Cpreprocessor); 31 32# 33# configurehelp perl module is generated by configure script 34# 35my $rc = eval { 36 require configurehelp; 37 configurehelp->import(qw( 38 $Cpreprocessor 39 )); 40 1; 41}; 42# Set default values if configure has not generated a configurehelp.pm file. 43# This is the case with cmake. 44if (!$rc) { 45 $Cpreprocessor = 'cpp'; 46} 47 48# we may get the dir root pointed out 49my $root=$ARGV[0] || "."; 50 51# need an include directory when building out-of-tree 52my $i = ($ARGV[1]) ? "-I$ARGV[1] " : ''; 53 54my $h = "$root/include/curl/curl.h"; 55my $mh = "$root/include/curl/multi.h"; 56my $ua = "$root/include/curl/urlapi.h"; 57 58my $verbose=0; 59my $summary=0; 60my $misses=0; 61 62my @syms; 63my %doc; 64my %rem; 65 66open H_IN, "-|", "$Cpreprocessor $i$h" || die "Cannot preprocess curl.h"; 67while ( <H_IN> ) { 68 if ( /enum\s+(\S+\s+)?{/ .. /}/ ) { 69 s/^\s+//; 70 next unless /^CURL/; 71 chomp; 72 s/[,\s].*//; 73 push @syms, $_; 74 } 75} 76close H_IN || die "Error preprocessing curl.h"; 77 78sub scanheader { 79 my ($f)=@_; 80 open H, "<$f"; 81 while(<H>) { 82 if (/^#define (CURL[A-Za-z0-9_]*)/) { 83 push @syms, $1; 84 } 85 } 86 close H; 87} 88 89scanheader($h); 90scanheader($mh); 91scanheader($ua); 92 93open S, "<$root/docs/libcurl/symbols-in-versions"; 94while(<S>) { 95 if(/(^CURL[^ \n]*) *(.*)/) { 96 my ($sym, $rest)=($1, $2); 97 if($doc{$sym}) { 98 print "Detected duplicate symbol: $sym\n"; 99 $misses++; 100 next; 101 } 102 $doc{$sym}=$sym; 103 my @a=split(/ +/, $rest); 104 if($a[2]) { 105 # this symbol is documented to have been present the last time 106 # in this release 107 $rem{$sym}=$a[2]; 108 } 109 } 110} 111close S; 112 113my $ignored=0; 114for my $e (sort @syms) { 115 # OBSOLETE - names that are just placeholders for a position where we 116 # previously had a name, that is now removed. The OBSOLETE names should 117 # never be used for anything. 118 # 119 # CURL_EXTERN - is a define used for libcurl functions that are external, 120 # public. No app or other code should ever use it. 121 # 122 # CURLINC_ - defines for header dual-include prevention, ignore those. 123 # 124 # *_LAST and *_LASTENTRY are just prefix for the placeholders used for the 125 # last entry in many enum series. 126 # 127 128 if($e =~ /(OBSOLETE|^CURL_EXTERN|^CURLINC_|_LAST\z|_LASTENTRY\z)/) { 129 $ignored++; 130 next; 131 } 132 if($doc{$e}) { 133 if($verbose) { 134 print $e."\n"; 135 } 136 $doc{$e}="used"; 137 next; 138 } 139 else { 140 print $e."\n"; 141 $misses++; 142 } 143} 144 145# 146# now scan through all symbols that were present in the symbols-in-versions 147# but not in the headers 148# 149# If the symbols were marked 'removed' in symbols-in-versions we don't output 150# anything about it since that is perfectly fine. 151# 152 153my $anyremoved; 154 155for my $e (sort keys %doc) { 156 if(($doc{$e} ne "used") && !$rem{$e}) { 157 158 if(!$anyremoved++) { 159 print "Missing symbols mentioned in symbols-in-versions\n"; 160 print "Add them to a header, or mark them as removed.\n"; 161 } 162 163 print "$e\n"; 164 $misses++; 165 } 166} 167 168if($summary) { 169 print "Summary:\n"; 170 printf "%d symbols in headers (out of which %d are ignored)\n", scalar(@syms), 171 $ignored; 172 printf "%d symbols in headers are interesting\n", 173 scalar(@syms)- $ignored; 174 printf "%d symbols are listed in symbols-in-versions\n (out of which %d are listed as removed)\n", scalar(keys %doc), scalar(keys %rem); 175 printf "%d symbols in symbols-in-versions should match the ones in headers\n", scalar(keys %doc) - scalar(keys %rem); 176} 177 178if($misses) { 179 exit 0; # there are stuff to attend to! 180} 181else { 182 print "OK\n"; 183} 184