Visual c++ の同一ソリューション内ライブラリ参照と、ライブラリプロジェクトへの静的リンクライブラリのリンクの仕方。
概要
Visual Studio はエディターとして超優秀だけど、ビルド時の「追加の依存ファイル(静的リンクライブラリなど)」の指定や、インクルードパスの指定をする「プロジェクトプロパティ」がとてもわかりにくいし、それをわかりやすくしようとした結果生まれた .props
ファイルによるプロジェクトプロパティのファイル定義がまたややこしいってんで、なにかちょっと不慣れなことをしようとしたり、古いOSSを新しいVSで使おうとすると痛い目に遭いがち。
今回はそれげな話の一つとして、実務で遭遇した以下の2件についてメモを残しておきます。
- スタティックリンクライブラリを作るプロジェクト(PrjS1)と、それを使って動く .exe を作るプロジェクト(PrjE)、の2プロジェクトを持つVisual Studio の一つのソリューション(Sln1)において、PrjEがPrjS1.libを使うケース
- 単独のスタティックリンクライブラリを作るプロジェクト(Sln2/PrjS2) を用意し、PrjS1.libが PrjS2.lib を使うケース
図にまとめるとこんな感じ
それそれどのように "参照" やリンクを行うのか、についてまとめておこうと思います。
前提知識
私も記憶喪失になりがちなので、大事な前提知識として、DLLやLIBってなんやねん?を詳細に説明して下さっている記事へのリンクを貼らせていただきます。
(1) ソリューション内の参照
ソリューション内のプロジェクト参照とは何か。
こちらに記載があります。
プロジェクト内の参照の管理 - Visual Studio | Microsoft Docs
Visual Studio は、プロジェクトへのパスが指定されると、アセンブリを見つけることができます。
とありますが、.lib
ファイルをビルドするプロジェクトを参照した場合は、結果の .lib
ファイルを見つけることが出来る、と言う意味ですね。
ソリューション内の別のプロジェクトへの参照の仕方
- プロジェクトを右クリック → 追加 → 参照 → ソリューション内の
.lib
ファイルを作るプロジェクト名にチェック- 参照右クリック→参照の追加、でも同じ
似たような項目で、プロジェクトの依存関係というのがあります。
- ソリューションを右クリック → プロパティ → 共通プロパティ → プロジェクトの依存関係
こちらは、同一ソリューション内のプロジェクト間のビルド順を定義するための設定です。試しに PrjE が PrjS1 に依存するよう指定すると、ビルド順こそ最適化されますが、 PrjS1 中のコードの header を持ってきて使おうとすると、 未解決の外部シンボルが参照されました
のようなエラーが出ます。これは無論、 PrjS1.lib
がリンクできていないからです。
方法: プロジェクトの依存関係を作成および削除する - Visual Studio | Microsoft Docs
逆に、先にPrjEからPrjS1を参照すると、自動的に PrjEがPrjS1を依存することもプロパティに追記されます。
ソリューションの構成とプラットフォームの自動反映
このようにプロジェクト参照で引いている .lib
は、構成(Debug/Release)やプラットフォーム(x86/x64) をソリューション全体で変えたとしても、利用する側の PrjE に対し、適切な構成・プラットフォームで作られた PrjS1.lib
を渡してくれます。
それを確認するために、以下の手順で意地悪をしてみます。
- 一旦ソリューションをクリーン
- Debug/x86 で PrjS1 をプロジェクトのみビルド
- Debug/x86 で PrjE をプロジェクトのみビルド → 正しくビルドされる( PrjS1.lib のデバッグビルド物を引けている)
- Release/x86 で PrjE を再度プロジェクトのみビルド → ビルド完了出来ない(この時点ではPrjS1.lib** のリリースビルドが存在しないため)
- Release/x86 で PrjS1.lib をプロジェクトのみビルド、Debug/x86 でビルドした PrjS1.lib を削除
- Release/x86 で PrjE を再度プロジェクトのみビルド → 正しくビルドされる
その間、プロジェクトプロパティ類は一切編集しませんでしたがこのように、適切な .lib
ファイルを引いてくれることがわかります。
ちなみに細かい話ですが、ソリューションエクスプローラ上で PrjE / 参照 / PrjS1
を選択してプロパティウィンドウを見ると、構成が Debug
の時に Release\PrjS1.lib
が完全パスとして指定されていたり、その逆だったりすることがあります。これはおそらく Visual Studio の表示上のバグで、実際、Visual Studio を再起動すると、正しい .lib
ファイルのパスが記載されています。
(2) ソリューション外のビルド物である .lib
ファイルを、自分のライブラリ(.lib
を出力する)プロジェクトに追加する
他所のリリース物を自分のプロジェクトに取り込んで使う場合、こちらの方が良くあると思います。特に、 PrjE(.exeを作るプロジェクト) に PrjS2(.lib) をリンクする場合は、 プロジェクトプロパティ / リンカー / 追加のライブラリディレクトリ
と 入力 / 追加の依存ファイル(.libファイル)
を指定する、という「VSおきまりの」手続になります。
今回やりたいのは、静的リンクライブラリを出力するプロジェクトに外部の静的リンクライブラリをリンクする、ことです。基本的には上記と同じなのですが、 .exe
を出力するプロジェクトと .lib
を出力するプロジェクトで、若干プロジェクトプロパティの構成が異なっています。 .h
ファイルのインクルードに関しては、 .exe
のプロジェクトの場合と同様に、 C/C++ / 全般 / 追加のインクルードディレクトリ
に使いたい .h
ファイルのあるディレクトリを指定します。
ライブラリファイルの指定は、ライブラリアン / 全般
タブ中の 追加の依存ファイル
と 追加のライブラリディレクトリ
を、それぞれ構成・プラットフォーム毎に正しく設定する必要があります。これにより、構成・プラットフォームを変えても、PrjS1 はそれ毎に正しい .lib
ファイルをビルドしてくれ、最終的に PrjE は正しくビルドされることになります。
所感
昔ながらの静的リンクライブラリのロードの仕方として、 #pragma comment(lib, "filename.lib") 式もありますが、その他の dll ファイルの置き場などすべてプロジェクトのプロパティから指定しているので、
.lib` ファイルもプロジェクトプロパティの指定でやりきりたいなぁと私は考えています。コード中に書く方がマルチプラットフォーム開発では良いことも多いかも知れませんが、それはそのときに。
[VC++] リンクするライブラリファイルをソースコード内に記述する | あみだがみねのもろもろ備忘録
これまでかなり適当にやって、何となくビルドできればおっけーって感じで通ってきてた内容を一通り整理できて良かったです。