ライブラリ*.libから関数名を抽出する

提供:yonewiki
2025年10月7日 (火) 18:35時点におけるYo-net (トーク | 投稿記録)による版 (ページの作成:「<yjavascript></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/vs2015.css"> <link rel="stylesheet" href="https://wiki.yo-net.jp/custom.css"> <script src="https://wiki.yo-net.jp/highlight/highlight.js"></script> <script src="https://wiki.yo-net.jp/custom.js"></script> <script type="text/javascript" charset="UTF-8" src="https://wiki.yo-net.jp/highlight/highlightjs-vba/dist/vba.min.js"></script> <script type="text…」)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)

言語と開発環境に戻る。

概要

 ライブラリを生成したときに所望の関数がちゃんと取り込まれているか確認するときに*.libファイルの中に関数名が存在しているかを抽出して確かめる手順について記述します。


 大規模なプロジェクトでは関数名が多すぎて、使いたいとおもっている関数が確実に出力されているのかを確かめるにはやはり、生成sareta*.libファイルに関数名を存在するかチェックした方が早い場合があります。


 dumpbinコマンドで関数名を得ることはできますが、膨大な関数名から全体を見渡すのは大変です。引数が違うだけで、同じ名前の関数がいっぱいあったり、名前マングリングによって余計な情報が取り込まれていたりします。すっきり関数名だけを抽出してやろうというのがこの記事の目的です。VisualStudioのツールから起動できるPowerShellスクリプトでdumpbinの結果から関数名の行だけをテキストに出力する処理をしてからPythonで名前マングリングを解除した関数名を取得しつつ、同じ関数名を一つに集約するという処理を行います。


 まず以下のようなdumpbinコマンドをPowerShellスクリプトによって一括で処理しながら、関数名に関する情報だけを取得します。この時点では名前マングリングがなされていて、読みにくいですが、まずはやってみましょう。


 Visual Studio のツールのPowerShellを選択してPowershellを起動します。そして、ライブラリファイルのあるフォルダをカレントディレクトにして、以下のコマンドをペロっと貼ります。libboost_regex-vc143-mt-gd-x64-1_89-non_icu.libというファイル名は以下の例の場合のライブラリファイル名ですので、自分で調べたいライブラリファイル名に変更して動作させてみて下さい。


PS C:\(libファイルのあるフォルダへのパス)\lib> dumpbin /SYMBOLS /NOLOGO libboost_regex-vc143-mt-gd-x64-1_89-non_icu.lib |
Select-String "External" |
ForEach-Object {
if ($_ -match "\|\s*([^\s]+)") { $matches[1] }
} | Sort-Object | Get-Unique > short_symbol_names.txt


 例えば、上記の例では自分で作ったboost.regexのデバッグ版64ビットアドレス方式のlibファイルの中身を見ようとしていて、short_symbol_names.txtというファイル名に同じディレクトリへ出力します。


 つぎにVisual StudioでPython プロジェクトを作ります。PythonはVisual Studioで動かさなくてもいいので、お好きな環境でペロっとして下さい。


import subprocess
import re
 
# 入力ファイル:デコレート名のリスト
input_file = r"C:\Users\speci\source\repos\boost_1_89_0\stage\lib\short_symbol_names.txt"
# 出力ファイル:関数名のみ
output_file = r"C:\Users\speci\source\repos\boost_1_89_0\stage\lib\demangled.txt"
 
# undname.exe のフルパスを指定
undname_path = r"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.43.34808\bin\Hostx64\x64\undname.exe"
 
# 関数名の重複を避けるため set で保持
function_names = set()
 
# 入力ファイルを読み込む
with open(input_file, "r", encoding="utf-16") as f:
  symbols = [line.strip() for line in f]
 
for sym in symbols:
  try:
    # undname を実行
    result = subprocess.run([undname_path, sym],
capture_output=True, text=True, check=True)
    demangled = result.stdout.strip()
    # "is :-" の行だけを抽出
    for line in demangled.splitlines():
      if "is :-" in line:
        line = line.split("is :-")[-1].strip()
 
        # 関数名だけ抽出する正規表現
        # クラス名::関数名、デストラクタ、演算子など対応
        m = re.search(r'(?:[\w:]+::)?(~?operator[^\s(]*|[\w~]+)\s*\(', line)
        if m:
          func_name = m.group(1)
          function_names.add(func_name)
        break  # "is :-" 行は1行だけ処理
 
  except subprocess.CalledProcessError:
    # undname が失敗した場合はスキップ
    print(f"undname failed for: {sym}")
  except FileNotFoundError:
    print(f"undname.exe not found: {undname_path}")
    break
 
# 関数名をソートして出力
with open(output_file, "w", encoding="utf-8") as out:
  for name in sorted(function_names):
    out.write(name + "\n")
 
print(f"Extraction completed: {len(function_names)} unique function names")


 

言語と開発環境に戻る。