Window用のC/C++プログラムのビルド時にどうしてもリンクできないときは以下の確認をしましょう
1. verboseオプション
ビルド時に問題が発生した場合はコンパイラとリンカにverboseオプションをつけて詳細を出力させましょう. 注意点としては、たいがいのビルドはmakeかmsbuild(Visual Studio)かgccによってされるので、そのままverboseオプションをつけても(makeやmsbuildへのオプションとみなされ)リンカにverboseオプションを渡すことが出来ないことです.
ビルドにmakeやmsbuild(Visual Studio)を使っている場合は、IDEのプロジェクションオプションからコンパイラとリンカにverboseオプションをつけましょう. 何かしらのIDEを使ってビルドした場合、たいていログが出力されてリるのでそれを見てもよいと思います. gccの場合は一部のオプションを除き普通にオプションをつけただけではコンパイラにオプションを渡すことになります. リンカにオプションを渡したい場合は「-Wl,--verbose」のようにオプションの前に「-Wl,」をつけましょう.
2. ライブラリディレクトリの設定
リンクしたいライブラリがへのパスがオプションで確実に指定されているか確認しましょう. リンカのverboseオプションが有効になっているなら大体コンソールに表示されると思います. オプションの文字は処理系によって異なるので注意.
3. ライブラリファイルの設定
リンクしたいライブラリが確実にリンカの引数に指定されているか確認しましょう. オプションの文字は処理系によって異なるので注意.
4. シンボル情報
Windowsの場合、静的ライブラリとインポートライブラリという異なる概念がどちらも.libという拡張子で表されるという凶悪仕様があります. インポートライブラリとは、動的ライブラリのリンクに用いるファイルです. だいたいの静的ライブラリはファイル名がlibから始まりますが、そうでない静的ライブラリも普通に存在します . 一方、インポートライブラリ中のシンボルには__imp__から始まるという規則があります. なので、本当に欲しいシンボルが_symbolName(静的ライブラリ)であるにもかかわらず、ライブラリ内のシンボルが__imp__symbolName(インポートライブラリ)になっていないか(あるいはその逆になっていないか)確認しましょう.
バイナリツールには通常オブジェクトファイル内のシンボル情報を表示するコマンドがついてきます. MinGWやLinux(Cygwin)の場合はnmというコマンド、Visual Studio(MSBuild)の場合はdumpbinというコマンドが利用できます. 適当なバイナリファイルを引数にすると次のようにシンボル情報が表示されます.
// cygwinのnmコマンドでシンボル情報表示 C:\> cygwin64\bin\nm C:\cygwin64\lib\crt0.o 0000000000000000 b .bss 0000000000000000 d .data 0000000000000000 N .debug_abbrev 0000000000000000 N .debug_aranges 0000000000000000 N .debug_frame 0000000000000000 N .debug_info 0000000000000000 N .debug_line 0000000000000000 N .debug_line_str 0000000000000000 N .debug_str 0000000000000000 p .pdata 0000000000000000 r .rdata$zzz 0000000000000000 t .text 0000000000000000 r .xdata 0000000000000000 T WinMainCRTStartup U cygwin_crt0 U cygwin_premain0 U cygwin_premain1 U cygwin_premain2 U cygwin_premain3 U main 0000000000000000 T mainCRTStartup
// MSBuild(Visual Studio)のdumpbinでシンボル情報表示 C:\> "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64\dumpbin" /LINKERMEMBER "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\ucrt\x64\ucrt.lib" 中略 187F6 _cgets 187F6 __imp__cgets 1886E _cgets_s 1886E __imp__cgets_s 188E8 _cgetws 188E8 __imp__cgetws 18960 _cgetws_s 18960 __imp__cgetws_s 189DA _cputs 189DA __imp__cputs 18A52 _cputws 18A52 __imp__cputws 18ACA _getch 18ACA __imp__getch 18B42 _getch_nolock 18B42 __imp__getch_nolock 18BC0 _getche 18BC0 __imp__getche 18C38 _getche_nolock 18C38 __imp__getche_nolock 18CB8 _getwch 18CB8 __imp__getwch 中略
MinGWによって提供されるオブジェクトファイルのシンボル情報をMinGWのnmコマンドとMSBuild(Visual Studio)のdumpbinコマンドで表示してみました. 後者を見ると分かるように、静的リンク用のシンボルと動的リンク用のシンボルの両方を含む(静的ライブラリでもありインポートファイルでもある).libファイルもあることが分かります. あるいは、このようなファイルを作りたかったので両者の拡張子をわざと同じにしているのかもしれません.
さて、以降はdumpbinだけを考えます. ライブラリによっては動的ライブラリと静的ライブラリの両方を提供しているライブラリがあります. これは一見喜ばしいことのように思えますが、言い換えると そのライブラリを使用するプロジェクトのビルドオプションで、動的ライブラリと静的ライブラリのどちらを利用するか設定しなければならないということです.
例えば、GLEWというライブラリは動的ライブラリと静的ライブラリの両方の形式が提供されています. ヘッダファイルの一部を見ると、プリプロセスのマクロ定数によって__declspecをつけたりつけなかったりしています. このようにしてGLEWを使うプロジェクト(=GLEWのヘッダをインクルードするプロジェクト)は、プリプロセスのマクロ定義によってGLEWを動的ライブラリとしてリンクするか静的ライブラリとしてリンクするかを切り替えることが出来ます. IDEのプロジェクトプロパティや、CMake時にプリプロセッサのマクロ定義を間違えないようにしましょう.
// glew.h /* * GLEW_STATIC is defined for static library. * GLEW_BUILD is defined for building the DLL library. */ #ifdef GLEW_STATIC # define GLEWAPI extern #else # ifdef GLEW_BUILD # define GLEWAPI extern __declspec(dllexport) # else # define GLEWAPI extern __declspec(dllimport) # endif #endif
5.そもそも類似名のシンボルも存在しないとき
nmやdumpbinコマンドを使って.libのシンボルを表示したとき、似たシンボル名が全くない場合はそもそも必要なライブラリが足りていない可能性があります. あるいは、リンクしようとしているライブラリのバージョンが古くシンボルが存在しないか、バージョンが新しくなった時に削除された可能性があります. 適切なライブラリがそもそも存在するかを確認しましょう.