gccのpre-compiled headerがらみの謎の現象
対処法は分かったが理由がサッパリ分からない謎の現象。これを詮索している余裕がないので、とりあえず起きたことを記しておく。後で再現できるかどうかは分からない。
まず、2つのソースコードがある。1行しか違ってない!
$ diff -u t_params.cpp t_params2.cpp --- t_params.cpp 2016-05-13 12:19:14 +0900 +++ t_params2.cpp 2016-05-13 12:19:12 +0900 @@ -1,5 +1,5 @@ // -*- coding: sjis -*- - +#include "stdafx.h" #include <stdio.h> #include "OJOLparams.h"
stdafx.h は、MSVCと揃えるために、gccでも使っているプリコンパイルヘッダ。次のよう。
// -*- coding: sjis -*- // gcc/g++向けのPCH(pre-compiled header)の定義 // #ifndef STDAFX_H #define STDAFX_H #include <stdio.h> #include <iostream> #include <Windows.h> #include <vector> #endif // STDAFX_H
Makefileの関連する場所は、
CXX:=mingw32-g++ CXXFlags:=-std=gnu++0x -MD -DNO_MFC -DMY_DEBUG # ... %.o : %.cpp %.h stdafx.h.gch $(CXX) $(CXXFlags) -c $< # pch = pre-compiled header .PHONY:pch pch : stdafx.h.gch stdafx.h.gch : stdafx.h $(CXX) $(CXXFlags) $<
mingw32-g++ のバージョンは、 mingw32-g++.exe (GCC) 4.6.2
オブジェクトを作るときは、.gchがあることを前提にしている。
さて、問題の現象。
make -k t_params.exe Making executable file mingw32-g++ -std=gnu++0x -MD -DNO_MFC -DMY_DEBUG -o t_params.exe t_params.cpp -L./ -lXYZW -lshlwapi C:\Users\hiyama\AppData\Local\Temp\cccemmLi.o:t_params.cpp:(.text+0x40): undefined reference to `XXXXyyyyyyZ::SetVolumeLabel(char const*)' collect2: ld returned 1 exit status make: *** [t_params.exe] Error 1 Compilation exited abnormally with code 2 at Fri May 13 12:22:01
make -k t_params2.exe Making executable file mingw32-g++ -std=gnu++0x -MD -DNO_MFC -DMY_DEBUG -o t_params2.exe t_params2.cpp -L./ -lXYZW -lshlwapi Compilation finished at Fri May 13 12:24:58
「#include "stdafx.h"」の行がないほうが、リンク時に、とある関数への参照が解決できないのだ。コンパイラ時じゃなくてリンク時!
`XXXXyyyyyyZ::SetVolumeLabel(char const*)'という関数は確実に存在している。その名前が見えなくなる。その名前だけが見えなくなる。
試しに、XXXXyyyyyyZ::SetVolumeLabel00(char const*) という関数を作ると、この名前はどっちでも見える、どっちもリンクが成功する。XXXXyyyyyyZ::SetVolumeLabel という名前だけが「#include "stdafx.h"」の影響を受ける。
ワカラン。
[追記]今日、時間がないが、たぶんこういう事情だろう。
stdafx.h では Windows.h がインクルードされている。問題は、Windows.h だろう。
SetVolumeLabel という名前はWindows APIにある。
かぶったのだ。このカブリは名前のマングリング(Name Mangling)で回避されるが、Windows.hをインクルードしないと、かぶっていることを認識できないので、カブリ回避の処理が走らないのだと思う。
[/追記]
[さらに追記]まず間違いない。[/さらに追記]
[もっと追記 date="翌日"]
かぶっていることを認識できないので、カブリ回避の処理が走らないのだと思う。
これは違った。マングリングではない。
かぶっているのは確かだけど、Windows API名がマクロ展開されるところに問題がある。結局はCプリプロセッサで細工しているからこんなことになる。今までのトラブルのほとんどがプリプロセッサがらみだ。
[/もっと追記]