gcc -Wunused-function -Wmissing-declarations does a good job at identifying functions that are not declared in any header file, and once you mark them static then tells you if they are unused. However, with programs that have been developed over many years, and have a lot of cruft in the source code (such as Doom/PrBoom), there may be many functions that are prototyped in header files but are not actually used from other files; gcc cannot tell you about these.
I had an idea for locating these unnecessary externs: just run the link stage of gcc with one .o file taken out, and record all the 'undefined reference to' errors you get. That gives you the list of used externs; so any others are unused. So I wrote a couple of scripts to assist with this. First, find-used-externs:
#!/usr/bin/ruby -w
def filter_gcc(cmdline)
IO.popen(cmdline.join(" ") + " 2>&1 ") do |p|
p.each_line do |l|
print $1,"\n" if l =~ /undefined reference to \`(.*)'/;
end
end
end
ARGV.each do | a |
next unless a =~ /\.o$/;
cmdline = ARGV.reject { |b| b == a }
filter_gcc(cmdline)
end
Which tells you all the symbols in .o files referenced by other files — cut and paste the normal link step for the project, and prefix the command with ./find-used-externs. It runs the link command once for each .o file, omitting only that .o file from the command line, and parsing the errors.
Secondly, you have to find all the externs provided by each .h file, and see if any are not on the used list. list-externs is a very crude script to try and read extern variables and function prototypes from header files:
#!/usr/bin/ruby -w
ARGF.each_line do |l|
l.sub!(/\/\/.*/,'')
l.sub!(/\/\*.*/,'')
print $1,"\n" if l =~ /^\s*extern.*\s([a-zA-Z_][a-zA-Z_0-9]*)\s*;/
print $1,"\n" if l =~ /^\s*[^#].*\s([a-zA-Z_][a-zA-Z_0-9]*)\s*\(/
end
So sort the output of that, and use comm(1) to find the entries that are not in the (sorted) output of find-used-externs. And that tells you what header file declarations are not currently needed.