Programming Field - プログラミング Tips

MinGW: ld を使った C++ アプリのリンク

MinGW: gcc ではなく ld を使ったリンク方法にあるように、g++ (ここでは C++ アプリなので) をリンカとして使わずにリンクする場合は ld を使いますが、このときに必要なライブラリはさらに増えます。これを忘れると、エラーが出てリンクできません。

エラーの発生例

例えば、以下のような仮想関数を使うアプリケーションでは、後述のようにリンクするとエラーが必ず起きます。

ソース testapp.cpp

#include <stdio.h>

class CVirtBase
{
public:
    virtual void ShowMessage() = 0;
};

class CVirtImpl : public CVirtBase
{
public:
    virtual void ShowMessage();
};

void CVirtImpl::ShowMessage()
{
    printf("CVirtImpl message\n");
}

void CallShowMessage(CVirtBase* p)
{
    p->ShowMessage();
}

int main()
{
    CVirtImpl* p = new CVirtImpl;
    CallShowMessage(p);
    delete p;
    return 0;
}

コマンド

(MinGW: gcc ではなく ld を使ったリンク方法(Windowsアプリ)とほとんど同じです。)

g++ -o testapp.o -c testapp.cpp
ld -o testapp.exe -Bdynamic $(MINGW_DIR)/lib/crt2.o \
    $(MINGW_DIR)/lib/gcc/mingw32/3.4.2/crtbegin.o \
    $(MINGW_DIR)/lib/gcc/mingw32/3.4.2/crtend.o \
    -L$(MINGW_DIR)/lib/gcc/mingw32/3.4.2 -s \
    testapp.o -lmingw32 -lgcc -lmoldname \
    -lmingwex -lmsvcrt -lkernel32

出力されるエラー

testapp.o(.text+0x5f):testapp.cpp: undefined reference to `operator new(unsigned int)'
testapp.o(.text+0x82):testapp.cpp: undefined reference to `operator delete(void*)'
testapp.o(.rdata$_ZTV9CVirtBase[__ZTV9CVirtBase]+0x8):testapp.cpp:
    undefined reference to `__cxa_pure_virtual'
testapp.o(.rdata$_ZTI9CVirtBase[__ZTI9CVirtBase]+0x0):testapp.cpp:
    undefined reference to `vtable for __cxxabiv1::__class_type_info'
testapp.o(.rdata$_ZTI9CVirtImpl[__ZTI9CVirtImpl]+0x0):testapp.cpp:
    undefined reference to `vtable for __cxxabiv1::__si_class_type_info'

エラーの回避方法

これを回避するには、ライブラリ指定で「-lmingw32」の前に-lstdc++」を加えます。(この位置でないと、「undefined reference to ...」のメッセージが立て続けに出ます → MinGW: リンク時のライブラリ順序)

訂正後のコマンド (ld の部分のみ)

ld -o testapp.exe -Bdynamic $(MINGW_DIR)/lib/crt2.o \
    $(MINGW_DIR)/lib/gcc/mingw32/3.4.2/crtbegin.o \
    $(MINGW_DIR)/lib/gcc/mingw32/3.4.2/crtend.o \
    -L$(MINGW_DIR)/lib/gcc/mingw32/3.4.2 -s \
    testapp.o -lstdc++ -lmingw32 -lgcc \
    -lmoldname -lmingwex -lmsvcrt -lkernel32