Diary

Diary?

学生の研究日記だったらしいです。多分。

開発日記。

オススメの本(頂いた本):

いちばんあたらしいの2017 11/17 6:33

_17(Fri)

パンダ可愛い。毎日可愛い。すごい。


C 言語の時、リファクタリングなどを通して、ある関数が使われている / いないをチェックする方法が欲しいことは時々あります。static 関数であれば、コンパイラが「誰も使っていない static 関数があるけど、いいの?」と warning を出してくれますが、static でなければ、別のファイルが利用するかもしれないので、特に何も言いません。リンク時に、visibility が default でないもの(ELF とかで、外部から見えないシンボル)なのに、参照がない場合に警告でも出してくれればいいんですが、今ちょっと見てみても、そういうオプションは無さそう。

というわけで、調べてみようと思ったんだけど、多分必要なのは、「ある関数から呼ばれた関数一覧」があれば、どの関数が参照を持っていないかわかるんじゃないか、というもの。まぁ、やれば出来るんだろうけど、面倒なので、もちろん書きたくないし、ソフトとかインストールしたくない。

Twitter で聞いてみたところ、https://searchcode.com/codesearch/view/17596782/ を教えてもらいました。要点は次の通り:

(1) nm を使うことで、「あるファイルから呼ばれる、他のファイルの関数一覧」一覧を得ることが出来る。 (2) 「あるファイルにある export された関数一覧」を得ることができる。

これを比較すれば、「export された関数一覧だが、外から誰も参照していない関数」、つまり「static でいいんじゃないの?」という提案ができる、と。そして、static 化すれば、その後でもし使っていなければ、「誰も使ってないんじゃ無いの?」ということがわかる。まぁ、その前に grep してしまえばいいのですが。

誰も使ってないけど、拡張ライブラリのために一応置いてある関数もあるので、一概に「誰も使ってない」とも言えないのだけど、まぁ grep すればいいのでヒントにはなる。

で、Perl script は動かなかったので、Ruby でちょろっと書き直した。

#
# This tool is inspired by https://searchcode.com/codesearch/view/17596782/

funcs = Hash.new{|h, k| h[k] = Hash.new(0)} # [type => [name]]
ARGV.each{|file|
  `nm #{file}`.each_line{|line|
      # 0000000000000190 t call_cfunc_5
    if /................ (.) (.+)/ =~ line
      type = $1
      func = $2
      funcs[type][func] += 1
    else
      raise line.dump
    end
  }
}
require 'pp'

exported_functions = funcs['T'].keys
undefined_functions = funcs['U']
include_file_data_ary = Dir.glob(File.join(__dir__, '../include/ruby/*.h')).map{|include_file|
  [include_file, File.read(include_file)]
}

ref_func = []
found_func = []
unfound_func = []
exported_functions.each{|f|
  if undefined_functions.has_key? f
    ref_func << [undefined_functions[f], f]
  else
    found = false
    include_file_data_ary.each{|(include_file, data)|
      if !data.scan("#{f}(").empty?
        found_func << "#{f} in #{include_file}"
        found = true; break
      end
    }
    unless found
      unfound_func << "static?: #{f}"
    end
  end
}
ref_func.sort_by{|(n, f)| -n}.each{|(n, f)|
  puts "#{f} is reffered from #{n} files"
}
puts found_func
puts unfound_func

便利。最後のほう、include/ にあれば公開関数に違いない、と想像している。

Log

2002 01 02 03 04 05 06 07 08 09 10 11 12
2003 01 02 03 04 05 06 07 08 09 10 11 12
2004 01 02 03 04 05 06 07 08 09 10 11 12
2005 01 02 03 04 05 06 07 08 09 10 11 12
2006 01 02 03 04 05 06 07 08 09 10 11 12
2007 01 02 03 04 05 06 07 08 09 10 11 12
2008 01 02 03 04 05 06 07 08 09 10 11 12
2009 01 02 03 04 05 06 07 08 09 10 11 12
2010 01 02 03 04 05 06 07 08 09 10 11 12
2011 01 02 03 04 05 06 07 08 09 10 11 12
2012 01 02 03 04 05 06 07 08 09 10 11 12
2013 01 02 03 04 05 06 07 08 09 10 11 12
2014 01 02 03 04 05 06 07 08 09 10 11 12
2015 01 02 03 04 05 06 07 08 09 10 11 12
2016 01 02 03 04 05 06 07 08 09 10 11 12
2017 01 02 03 04 05 06 07 08 09 10 11 12

SASADA Koichi (ko1 at atdot dot net) / Skype ID: ko1_ssd


rss