静的ライブラリのすべてのシンボルを強制的にリンク(使用されていないものを含む)
7379 ワード
C++プログラムは、静的ライブラリをリンクするときに、静的ライブラリのいくつかのメソッドがどこにも呼び出されていない場合、最終的に呼び出されていないメソッドや変数は破棄され、ターゲットプログラムにリンクされません.これにより、バイナリファイルを生成するボリュームが大幅に減少します.しかし、静的ライブラリのいくつかの方法がどこにも使用されていない場合でも、使用されていないコードを最終的なバイナリファイルにコンパイルしたい場合があります.
どうしてこのような需要があるのですか?確かに、このような需要があるのは少数の状況ですが、次のような需要に遭遇すると、必要になります.例:ダイナミックプラグインメカニズム.コードにはメソッドが直接呼び出されませんが、実行時にメソッドを動的にロードして実行したい場合があります. は、コードオーバーライド率統計を実行する.静的ライブラリのすべてのコードのオーバーライド状況を統計する必要があります.使用されるコードのオーバーライド状況だけではありません.
gccコンパイルの場合、比較的やりやすいので、--whole-archiveリンクオプションを追加するだけです.しかし、Windowsプラットフォームでは、マイクロソフトのコンパイラにはこのようなオプションはありません.最も近いオプションは/OPT:NOREFです.
ドキュメントを参照:https://msdn.microsoft.com/en-us/library/bxwfs976.aspx説明:/OPT:REF eliminates functions and data that are never referenced;/OPT:NOREF keeps functions and data that are never referenced.
/OPT:NOREFはDebugでデフォルトで開かれており、このプロジェクトで使用されていない関数と変数のみを強制的に保持できます.参照される静的ライブラリの使用されていない関数と変数は有効ではありません.マイクロソフトのバグだと思っている人もいますが、この投稿ではLINK.EXE BUG:/OPT:NOREF option doesn't work!
同じ問題に遭遇したのは私だけではありません.例えばStackOverFlowでは、What is the Visual studio equivalent to GNU ld option--whole-archiveという質問があります.
使用されていないシンボルへのリンクを強制するために/INCLUEオプションを使用することをお勧めする人もいれば、/OPT:NOREF(明らかにだめ)を使用する人もいます.
シンボルの強制リンクを指定するには、/INLUDEを使用します.しかし、静的ライブラリに何百ものシンボルが強制/INCLUDEを必要としている場合は、どうすればいいですか?
したがって、最良の方法は、上記の/OPT:NOREF BUGの投稿で誰かが言及した方法であり、コードで使用することです.
上記の方法では、リンクにincludeのシンボルを強制することができます.include:シンボル名の後ろにあります.include静的ライブラリ内のすべてのシンボルを強制する場合は、静的ライブラリ内のすべてのシンボルを探し出し、上記の方法でincludeを強制する必要があります.
人が手ですべてのSymbolsを見つけて、上のコードを追加するのはあまり頼りになりません.Symbolsのフォーマットの読み取りが悪すぎてメンテナンスができない一方で、静的ライブラリシンボル情報が変更された場合、このメンテナンスのコストはさらに大きくなります.だから、このプロセスを自動的に完了させなければなりません.
静的ライブラリのすべてのシンボルリストを表示します.Linuxではnmを使用できます.Windowsプラットフォームではdumpbinを使用できます.
dumbinを実行します.exeは、Visual Studioの開発コマンドライン環境で実行する必要があることに注意してください.しかし、Developer Command Promptで実行する必要がない小さなテクニックがあります.つまり、VS 2013環境であれば、バッチを作成し、先頭に追加します.
dumpbin/LinKERMEMBER xxxを使用しています.Libは、静的ライブラリMyLibを表示するなど、すべての記号の名前をリストすることができます.libすべての記号:
したがってdumpbinを実行し、出力結果からすべてのシンボル名を抽出し、#pragma comment(linker,"/include:xxx")コードを自動的に生成するだけでよい.
そこで、Pythonスクリプトを書いてdumpbinを実行し、正規表現ですべての記号名を取得し、すべての記号を強制includeしたヘッダファイルを自動的に生成しました.キーコードは次のとおりです.
Visual Studioエンジニアリング構成のPost-Build Eventと組み合わせると、静的ライブラリをコンパイルした後にヘッダファイルを自動的に更新できます.例:
このスタティックライブラリを使用するエンジニアリングコードでは、#include"LinkAllSymbols.h"だけで済みます.
コントラスト
OpenCppCoverageを使用してコードオーバーライド率テストを行い、以下の比較を行います.
通常、linker時にinclude静的ライブラリのすべてのシンボルを強制しない場合、コードオーバーライド率の結果は次のとおりです.
上記の方法でLinkAllSymbolsを自動的に生成する.h並#include“LinkAllSymbols.h”、カバー率結果:
github
すべてのコードは次のとおりです.https://github.com/coderzh/LinkAllSymbols
どうしてこのような需要があるのですか?確かに、このような需要があるのは少数の状況ですが、次のような需要に遭遇すると、必要になります.例:
gccコンパイルの場合、比較的やりやすいので、--whole-archiveリンクオプションを追加するだけです.しかし、Windowsプラットフォームでは、マイクロソフトのコンパイラにはこのようなオプションはありません.最も近いオプションは/OPT:NOREFです.
ドキュメントを参照:https://msdn.microsoft.com/en-us/library/bxwfs976.aspx説明:/OPT:REF eliminates functions and data that are never referenced;/OPT:NOREF keeps functions and data that are never referenced.
/OPT:NOREFはDebugでデフォルトで開かれており、このプロジェクトで使用されていない関数と変数のみを強制的に保持できます.参照される静的ライブラリの使用されていない関数と変数は有効ではありません.マイクロソフトのバグだと思っている人もいますが、この投稿ではLINK.EXE BUG:/OPT:NOREF option doesn't work!
同じ問題に遭遇したのは私だけではありません.例えばStackOverFlowでは、What is the Visual studio equivalent to GNU ld option--whole-archiveという質問があります.
使用されていないシンボルへのリンクを強制するために/INCLUEオプションを使用することをお勧めする人もいれば、/OPT:NOREF(明らかにだめ)を使用する人もいます.
シンボルの強制リンクを指定するには、/INLUDEを使用します.しかし、静的ライブラリに何百ものシンボルが強制/INCLUDEを必要としている場合は、どうすればいいですか?
したがって、最良の方法は、上記の/OPT:NOREF BUGの投稿で誰かが言及した方法であり、コードで使用することです.
#pragma comment(linker, "/include:?emptyreference@Noisy@@QAEXXZ")
上記の方法では、リンクにincludeのシンボルを強制することができます.include:シンボル名の後ろにあります.include静的ライブラリ内のすべてのシンボルを強制する場合は、静的ライブラリ内のすべてのシンボルを探し出し、上記の方法でincludeを強制する必要があります.
人が手ですべてのSymbolsを見つけて、上のコードを追加するのはあまり頼りになりません.Symbolsのフォーマットの読み取りが悪すぎてメンテナンスができない一方で、静的ライブラリシンボル情報が変更された場合、このメンテナンスのコストはさらに大きくなります.だから、このプロセスを自動的に完了させなければなりません.
静的ライブラリのすべてのシンボルリストを表示します.Linuxではnmを使用できます.Windowsプラットフォームではdumpbinを使用できます.
dumbinを実行します.exeは、Visual Studioの開発コマンドライン環境で実行する必要があることに注意してください.しかし、Developer Command Promptで実行する必要がない小さなテクニックがあります.つまり、VS 2013環境であれば、バッチを作成し、先頭に追加します.
@echo off
if defined VS120COMNTOOLS (
call "%VS120COMNTOOLS%\vsvars32.bat")
dumpbin/LinKERMEMBER xxxを使用しています.Libは、静的ライブラリMyLibを表示するなど、すべての記号の名前をリストすることができます.libすべての記号:
d:\Code\Cpp\LinkAllSymbols\Debug>dumpbin.exe /linkermember:1 MyLib.lib
Microsoft (R) COFF/PE Dumper Version 12.00.30501.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file MyLib.lib
File Type: LIBRARY
Archive member name at 8: /
557D4C17 time/date Sun Jun 14 17:40:39 2015
uid
gid
0 mode
ED size
correct header end
9 public symbols
328 ??4Turtle@@QAEAAV0@ABV0@@Z
328 ??_C@_0M@KEAKLOKJ@Turtle?5run?4?$AA@
328 ?Download@@YAHXZ
328 ?Run@Turtle@@QAEXXZ
19CE ?FishRun@@YAXXZ
19CE ?Run@Fish@@QAEXXZ
2D16 ??_C@_08EMEDHABH@Dog?5run?4?$AA@
2D16 ?Foo@@YAHXZ
2D16 ?Run@Dog@@QAEXXZ
Summary
28B4 .debug$S
F0 .debug$T
102 .drectve
15 .rdata
C .rtc$IMZ
C .rtc$TMZ
15A .text$mn
したがってdumpbinを実行し、出力結果からすべてのシンボル名を抽出し、#pragma comment(linker,"/include:xxx")コードを自動的に生成するだけでよい.
そこで、Pythonスクリプトを書いてdumpbinを実行し、正規表現ですべての記号名を取得し、すべての記号を強制includeしたヘッダファイルを自動的に生成しました.キーコードは次のとおりです.
import re
regex = re.compile(r"\s+.*\s([\?_]+.*)")
exclude = []
def gen_header_file_for_lib(lib_path, header_path):
cmd = ['dumpbin.exe','/linkermember:1', lib_path]
lines = execute_command(cmd)
symbols = find_matches(lines, regex, exclude)
with open(header_path, 'w') as f:
header_guard = "LINK_ALL_SYMBOLS_H_"
f.write("#ifndef " + header_guard + '
')
f.write("#define " + header_guard + '
')
f.write("// Generated by GenLinkerSymbols.py. Do not modify!
")
for symbol in symbols:
pragma_line = '#pragma comment(linker, "/include:' + symbol + '")'
f.write(pragma_line + '
')
f.write("
#endif // " + header_guard + '
')
print("Link symbols count: %s" % len(symbols))
def find_matches(lines, regex, exclude_list):
def match(line):
m = regex.match(line)
if m:
return m.group(1).split()[0]
return None
def exclude_filter(line):
if not line:
return False
for exclude in exclude_list:
if line.find(exclude) >= 0:
return False
return True
matches = filter(exclude_filter, map(match, lines))
return list(set(matches))
Visual Studioエンジニアリング構成のPost-Build Eventと組み合わせると、静的ライブラリをコンパイルした後にヘッダファイルを自動的に更新できます.例:
python ..\GenSymbolsHeader.py $(OutDir)$(TargetName)$(TargetExt) ..\Include\LinkAllSymbols.h
このスタティックライブラリを使用するエンジニアリングコードでは、#include"LinkAllSymbols.h"だけで済みます.
コントラスト
OpenCppCoverageを使用してコードオーバーライド率テストを行い、以下の比較を行います.
通常、linker時にinclude静的ライブラリのすべてのシンボルを強制しない場合、コードオーバーライド率の結果は次のとおりです.
上記の方法でLinkAllSymbolsを自動的に生成する.h並#include“LinkAllSymbols.h”、カバー率結果:
github
すべてのコードは次のとおりです.https://github.com/coderzh/LinkAllSymbols