見切り発車

とりあえずかきとめたい

Visual C++ でのweak symbol

解決したこと

他のコンパイラでは __attribute__((weak)) などと指定するweak symbol をVisual C++ で使用する方法について調べました。

環境

解決方法

weak symbol はリンク時に他に同じ名前のシンボルが見つからなければリンクされるシンボルです。

通常はリンク時に同じ名前のシンボルが複数ある場合にはエラーとなります。

Visual C++ の場合、 /alternatename:a=b というリンカオプションを使用して、a というシンボルの定義が見つからない場合には b というシンボルをリンクするという方法で同様のことができます。

msvc waek symbol で1年以内に更新された条件でググったら出てきた What does the /ALTERNATENAME linker switch do? を参考にしました。

サンプルコード

/*
 * C リンケージで宣言
 */
/// 呼び出す関数名
extern "C" int func();
/// デフォルト実装
extern "C" int _default_func();
/*
 * リンカーへの指定
 */
#if defined(_M_IX86)
// x86 は_ が付加される
#pragma comment(linker, "/alternatename:_func=__default_func")
#elif defined(_M_IA64) || defined(_M_AMD64)
// x64 は そのままの名前
#pragma comment(linker, "/alternatename:func=_default_func")
#endif

/*
 * C++ リンケージで宣言
 */
/// 呼び出す関数名
extern int func2();
/// デフォルト実装
extern int _default_func2();

// Visual Studio 2019 では以下の指定でリンクできた
// リンクエラーの時に出力されたエラーメッセージを参考に指定
#if defined(_M_IX86)
#pragma comment(linker, "/alternatename:?func2@@YAHXZ=?_default_func2@@YAHXZ")
#elif defined(_M_IA64) || defined(_M_AMD64)
#pragma comment(linker, "/alternatename:?func2@@YAHXZ=?_default_func2@@YAHXZ")
#endif

// 1:デフォルト実装が呼び出される
// 0:独自実装が呼び出される
#define USE_DEFAULT 1

/// メイン関数
int main()
{
    return func() + func2();
}

#if !USE_DEFAULT
/// C リンケージの独自実装
int func() {
    return 0;
}
/// C++ リンケージの独自実装
int func2() {
    return 0;
}
#endif

/// C リンケージのデフォルト実装
int _default_func() {
    return 1;
}
/// C++ リンケージのデフォルト実装
int _default_func2() {
    return 2;
}

/alternatename に指定するのはリンク時のシンボル名なのでソースコード中の関数名そのままではなく、 x86 のC リンケージの場合は名前の前に_ が付加され、C++ リンケージの場合は名前マングリングが適用されています。

その他

github にサンプルをコミットしました。