undefined referenceに関して
MinGWでビルドする際に特有?なはまり方をしたのでメモ
その1呼び出し規約の食い違い
#include <GL/glut.h> void display(void) { } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutCreateWindow(argv[0]); glutDisplayFunc(display); glutMainLoop(); return 0; }
例えばこんなソースを
TARGET=sample.exe OBJS=main.obj CC=i686-mingw32-gcc CFLAGS=-I/usr/local/i686-mingw32/include LD=i686-mingw32-gcc LDFLAGS=-L/usr/local/i686-mingw32/lib -lglut32 -lopengl32 -lgdi32 -lglu32 -lwinmm all: $(TARGET) $(TARGET): $(OBJS) $(LD) -o $@ $^ $(LDFLAGS) .SUFFIXES:.obj .c.obj: $(CC) -c -o $@ $< $(CFLAGS) clean: rm -f $(TARGET) $(OBJS)
でビルドすると・・・
$ make i686-mingw32-gcc -c -o main.obj main.c -I/usr/local/i686-mingw32/include i686-mingw32-gcc -o sample.exe main.obj -L/usr/local/i686-mingw32/lib -lglut32 -lopengl32 -lgdi32 -lglu32 -lwinmm main.obj:main.c:(.text+0x1c): undefined reference to `___glutInitWithExit' main.obj:main.c:(.text+0x37): undefined reference to `___glutCreateWindowWithExit' main.obj:main.c:(.text+0x52): undefined reference to `___glutCreateMenuWithExit' main.obj:main.c:(.text+0x92): undefined reference to `_glutDisplayFunc' main.obj:main.c:(.text+0x97): undefined reference to `_glutMainLoop' collect2: ld はステータス 1 で終了しました make: *** [sample.exe] エラー 1
何故かglutのリンクに失敗する。
なんでかと思って調べてみたところシンボル名が違うのを発見。
$ objdump.exe -t /usr/local/i686-mingw32/lib/libglut32.a | grep glutMainLoop [ 15](sec 1)(fl 0x00)(ty 20)(scl 2) (nx 0) 0x000007e4 _glutMainLoop@0 # @0がついてる
glut.hを確認すると
GLUTAPI void APIENTRY glutMainLoop(void);
となっている。
ここに至ってAPIENTRYが未定義くさいことに気づく。
ソースの先頭のglut.hより前に
#include <windows.h>
とすることで解決した。
今回使っているglutは
http://vision.kuee.kyoto-u.ac.jp/~nob/doc/opengl/opengl.html
で紹介されている手順で作成した。
その2リンクする順番
上の例だとLDFLAGSの
-lglut32 -lopengl32
を
-lopengl32 -lglut32
の順にするとglut32から呼んでいるopengl32の関数がundefined referenceになる。
左のライブラリから右のライブラリを呼ぶ関係になっていないといけない。
(glut32がスタティックライブラリのため)
同様の問題にSDLの
-lSDLmain -lSDL (SDLmainがスタティック)
と
-lmingw32 -lSDLmain (両方ともスタティック)
の順序問題がある。
要するに3つを
-lmingw32 -lSDLmain -lSDL
の順で書く必要がある。
Makefileだと
$(TARGET): $(OBJS) gcc -o $@ $^ $(LDFLAGS)
のように自分のオブジェクト($^)のあとにライブラリ($LDFLAGS)が来る順番でないといけない。
Linuxでも試してみたがリンクの順番による問題は無いようだった。
順番が関係あるのはMingw特有なのかと思ったが解説発見。
http://www.hakodate-ct.ac.jp/~tokai/tokai/gtkmm/etc/p1.htm
静的ライブラリのせいだった。
今回の例だと
libglut32.a
と
libSDLmain.a、libmingw32.a
が該当する。
なるほど。