【C言語】includeしてるファイルを全て(再帰的に)表示するツールってありますか?

もしくは検索するアルゴリズムを教えて頂けると嬉しいです。

例:a.hファイルがincludeしてるファイルを調べたい

a.h は b.h と c.h を include してる。
b.h は d.h と e.h を include してる。
c.h は f.h を include してる。
d.h は ...

結果:a.h は b.h, c.h,d.h,e.h.....をincludeしてます。

という感じ。同一階層ではなく色々な階層にヘッダファイルが散らばってます。
(どの階層にあるかは不明です)(フォルダ数は数十万以上あるので個別指定は不可能です)
ちなみにgcc -M 【ファイル名】は同一階層しか検索できませんでした。

回答の条件
  • 1人5回まで
  • 登録:2008/01/18 00:11:27
  • 終了:2008/01/25 00:15:02

回答(5件)

id:t_shiono No.1

t_shiono回答回数256ベストアンサー獲得回数222008/01/18 01:40:54

ポイント20pt

makedependで十分ではないでしょうか?

http://xjman.dsl.gr.jp/man/man1/makedepend.1x.html

何かの参考になれば。

id:negi_1126

ありがとうございます。m(_ _)m

おぉ。こんなツールがあるんですね。

・・・これってmakefileが無いと動作しないんですかね?

(自宅環境でmakefileが無い状態で実行したらmakedepend: error: [mM]akefile is not present

と表示されてしまいました。自分でmakefileを作ったら実行できました。)

会社の開発環境がちょっと特殊で、perlでバッチ処理を走らせてビルドを掛けてるので、

もしかしたら通常のCにあるようなmakeファイルが無いかも知れないんです。。

(ソースだけで2GBオーバー、数十万ファイルあるので全容を把握できてません)

まずは会社の開発環境にmakefileがあるか確認してみます。

ありがとうございました!

2008/01/18 07:23:16
id:practicalscheme No.2

practicalscheme回答回数157ベストアンサー獲得回数422008/01/18 07:40:40

ポイント20pt

gcc -H はいかがですか。

こんな感じで階層表示してくれます。

(gccにはビルド時に渡すのと同じオプションを渡す必要があります。

あと、-Mでもシステムヘッダを含む全てのヘッダを出してくれるはずですが…)

$ gcc -std=gnu99 -H -DHAVE_CONFIG_H -I. -I./../gc/include   -g -O2 -fPIC -fomit-frame-pointer -march=i686 -DUSE_I686_PREFETCH -c vm.c
. gauche.h
.. ./gauche/config.h
.. /usr/include/stdio.h
... /usr/include/features.h
.... /usr/include/sys/cdefs.h
..... /usr/include/bits/wordsize.h
.... /usr/include/gnu/stubs.h
..... /usr/include/bits/wordsize.h
..... /usr/include/gnu/stubs-32.h
... /usr/lib/gcc/i386-redhat-linux/4.1.2/include/stddef.h
... /usr/include/bits/types.h
.... /usr/include/bits/wordsize.h
.... /usr/include/bits/typesizes.h
... /usr/include/libio.h
 :
id:negi_1126

ありがとうございます。m(_ _)m

おぉ。ディレクトリ情報も表示してくれるのは有難いですね。

・・・ですが、ちょっと調べてみたのですが上記オプションは下記のような意味合いですよね?

 

  • std=gnu99

  →GNU規格とC99規格を組み合わせてコンパイルする

  • H

  →ディレクトリ付きで表示する

  • DHAVE_CONFIG_H

  →不明。。(-_-;

  • I

  →ヘッダファイルのディレクトリを指定する

  • g

  →デバッグ情報を生成する

  • O2

  →最適化する

  • fPIC

  →動的リンクに適する位置非依存コードを(中略)回避する

  • fomit-frame-pointer

  →フレーム・ポインタをレジスタ内に保持しない

  • march=i686

  →指定したCPUだけで動作するようにする。速い。

  • DUSE_I686_PREFETCH

  →不明。。(-_-;

  • c

  →コンパイルのみを行う

 

いや。ディレクトリ付きで表示してくれるのは大変ありがたいので参考には

なったのですが、t_shiono様への返信に書いたように会社の開発環境が特殊で

通常のシステムファイルのようにヘッダファイルの位置を環境変数などで

持っていないため、単純にgcc -Mやgcc -Hでは表示してくれないんですよ。。

(stdio.hなどはgcc -Hで上記のように表示してくれますが、自作ヘッダ

ファイルはディレクトリを指定しないと検索してくれないみたいです。。)

 

環境チームという名前のチームがあるのでそこに聞けば色々分かると思うのですが、

複数の会社で開発を行っている為、コンパイル環境の詳細などを現実的に聞くことが

出来ないんです。。(環境チームは別会社が担当)

 

・・・まぁビルドを掛ける際に走らせてるperlを解析すれば良い話なのですが、

そこに時間を掛けるくらいだったら力技でincludeファイルをgrep掛けまくる

方が現実的かなと思いまして。

 

ちなみに-Iオプションでディレクトリを指定するのは現実的に不可能です。

(数十万以上あるので)(ある程度はヘッダファイルの位置が決まってますが、

自分の担当ソース以外、どこにヘッダファイルがあるのか正確な情報は

ほとんど分かりません)

 

もし認識違いでしたらご容赦ください&教えて頂ければうれしいです。m(_ _)m

2008/01/19 16:54:02
id:dev_zer0 No.3

dev_zer0回答回数332ベストアンサー獲得回数252008/01/18 12:00:05

ポイント20pt

http://www.linux.or.jp/JM/html/GNU_gcc/man1/gcc.1.html

やはり、gcc -Mでmakefileを作成させるのが一番手っ取り早い気がします。

ちなみに、gcc -Mだとマニュアルの抜粋を引用すると

見つからないヘッダファイルは生成されたファイルであり、

それらはソースファイルと同じディレクトリに存在するとみなします。

とあるので-Iオプションでヘッダが存在する場所を指定する必要があります

# そのヘッダが存在する箇所が散らばっているらしいですけど...


取り合えず、ヘッダが存在するディレクトリを片っ端から-Iオプションに

追加してはどうでしょうか?

# ヘッダファイル名が被っていると色々ややこしいことになりますが...

ヘッダが存在するディレクトリを取ってくる方法はbashなら

for f in $(find /usr -name '*.h'); do

 dirname $f;

done | sort -u

で/usr配下のヘッダが存在するディレクトリを求めることが出来ます。

id:negi_1126

えーとですね。。一度全ソースディレクトリを*.hでgrep掛けたのですが

ヘッダファイルだけで数十万ファイルあったんですよ。。

正確には調べてないですが、単純に1フォルダに100個ヘッダファイル

があったとして計算しても数千フォルダ。。orz いやもっと少ないかも知れないですが。。

そんなにたくさんのディレクトリを-Iオプションで指定できるものなんですかねぇ?

 

もしどんなに多くても指定可能というのであれば、もうこの際ダメ元で試してみます。

#ちなみにファイル名は基本的に命名規則に則ってるハズだから被ってない。。と思います。

2008/01/19 17:06:31
id:studiokingyo No.4

d金魚回答回数47ベストアンサー獲得回数22008/01/20 09:08:58

ポイント20pt

私はこういうのを調べる場合にはdoxygen + graphvizを使います。グラフィカルに表示してくれるのでとても見やすいです。

資料が古めですが導入方法です。

http://d.hatena.ne.jp/studiokingyo/searchdiary?word=doxygen%a4%f...

また、最近ではgoogle:doxygen frontendがあるようです。

しばらくプログラミングからはなれているので今ではもっとスマートな方法があるのかもしれません。

id:negi_1126

おおっ!これは素晴らしいですね。

今度試してみます。ありがとうございます。m(_ _)m

2008/01/22 12:10:22
id:Bookmarker No.5

しおり回答回数191ベストアンサー獲得回数342008/01/21 00:24:53

ポイント20pt

includeしてるファイルを全て(再帰的に)表示するツールってありますか?

(中略)

同一階層ではなく色々な階層にヘッダファイルが散らばってます。

(どの階層にあるかは不明です)(フォルダ数は数十万以上あるので個別指定は不可能です)

そういう特殊なものは公開されていないと思います。

もしくは検索するアルゴリズムを教えて頂けると嬉しいです。

厳密なものでもないし性能も考えていませんが、こんな感じでできると思います。

(C/C++ では面倒だし、Perl はとうの昔に捨てたので、Ruby で書きました。)


find_headers:

#!/usr/local/bin/ruby

require 'find'
require 'set'

def put_usage
  $stderr.puts "Usage: #{$0} dir1 [dir2...] file"
end

def find_file(dirs, file)
  pattern = Regexp.new("/#{Regexp.escape(file)}$")
  for dir in dirs
    Find.find(dir) do |path|
      next unless FileTest.file? path
      if pattern =~ path
        return path
      end
    end
  end
  return nil
end

def find_headers(dirs, hfile)
  hpaths = Set.new
  File.foreach(hfile) do |line|
    next unless /^\s*#\s*include\s*[<"]([^>"]+)[>"]/ =~ line
    file = $1
    path = find_file(dirs, file)
    if path.nil?
      $stderr.puts "warning: #{file}: not found"
      hpaths << file
    else
      hpaths << path
      hpaths |= find_headers(dirs, path)
    end
  end
  return hpaths
end

if ARGV.size < 2
  put_usage
  exit 1
end

file = ARGV.pop
dirs = ARGV
hpaths = find_headers(dirs, file)

print(file, ': ', hpaths.to_a.join(', '), "\n")

実行例:

% find_headers /usr/include /usr/include/stdio.h
/usr/include/stdio.h: /usr/include/sys/_types.h, /usr/include/machine/_types.h, /usr/include/sys/_null.h, /usr/include/sys/cdefs.h
id:negi_1126

おおっ!!素晴らしい!!まさにコレ!というソースをありがとうございます!!

Rubyは触ったことないので上記の詳細は良く分かりませんが、早速インストールして試してみます。

ありがとうございました!!m(_ _)m

2008/01/22 12:29:54
  • id:practicalscheme
    私の示した実行例の、-H以外のオプションは通常のビルド時に付加されるものです。
    gccもコンパイル時にプロジェクト特有のインクルードファイルを探しに行く必要があるので、その情報はどうしたって外から与えなければなりません。さらに-Dオプションの指定などでインクルードされるファイルが変わってくる場合もあるので、「ビルド時と同じオプション」は必須条件になります。

    perlスクリプトからビルドしているのであれば、簡単なハックはそのperlスクリプトがgccを呼んでいる箇所を探しだし、そこに無理やり-Hオプションを挿入してみてはいかがでしょう。それでビルドすれば通常のメッセージに混ざって-Hの出力が出てくるはずです。-Hオプションの出力は"... "で始まるのでgrepで簡単に抜き出せるでしょう。
  • id:dev_zer0
    多分、シェルの制限で数千ディレクトリは直接は渡せないでしょうね。
    # 確か10Kbyte以上のコマンドは受け付けられないはず
     
    http://www.asahi-net.or.jp/~wg5k-ickw/html/online/gcc-2.95.2/gcc_2.html#SEC44
    しかし、環境変数を介して渡してみるのはどうでしょう
    環境変数C_INCLUDE_PATHを設定し、そこに数千ファイルのパスを追加するのです
    一応5000ディレクトリ、300Kbyte程度の環境変数の設定は私の環境では設定することができ
    set > env.txtの実行結果が5分ぐらい帰ってこなくて、
    ファイルの内容を見たら一応設定した内容であるようです。
     
    コンパイルについては私のマシン環境自体がメモリが32M, HDDが2Gという
    しょぼいマシンなので2Gのソースをコンパイルすることは私の環境では物理的に無理です。
  • id:Bookmarker
    > find_headers
    循環参照の考慮を忘れていたので、循環参照しているとスクリプトが終了しないかもしれません。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません