이 문제는 동적 라이브러리를 생성할 때 발생한다. 다른 정적 라이브러리들을 링킹하는 과정에서 fPIC 옵션을 지정한 경우, 모든 정적 라이브러리가 fPIC 옵션을 가지고 컴파일 되어야 한다. 하지만, 그 중에 fPIC으로 컴파일 되지 않은 라이브러리가 있는 경우에는 이를 다시 컴파일 해주어야 한다. 이 중 libstdc++는 조금 머리 아픈 경우로써, 재컴파일 하려면 몇 가지 단계를 거쳐야 하므로 이를 정리한다. 사실 이 문제는 GCC 4.7 버전에서 해결되었다.(http://gcc.gnu.org/bugzilla/show_bug.cgi?id=28811)
실제 에러 메시지는 다음과 같이 보인다.
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/4.6/libstdc++.a(ctype.o): relocation R_X86_64_32S against `vtable for std::ctype<wchar_t>' can not be used when making a shared object; recompile with -fPIC
먼저 다음 명령으로 gcc의 최신 버전을 받는다. 이 글은 GCC 4.7.2 버전을 기준으로 설명한다.
sudo apt-get install gcc-4.7
sudo apt-get install g++4.7
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.7 20
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.7 20
sudo update-alternatives --config gcc
sudo update-alternatives --config g++
그리고 혹시 경로 문제가 발생할 수 있으므로 다음을 ~/.bashrc에 추가한다.
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
export LIBRARY_PATH=/usr/lib/i386-linux-gnu
export C_INCLUDE_PATH=/usr/include/x86_64-linux-gnu
export CPLUS_INCLUDE_PATH=/usr/include/x86_64-linux-gnu
다음으로 해야 하는 일은 이제 단순하다. 여러분이 작성한 소스 코드는 반드시 -fPIC 옵션을 이용해서 컴파일 한다. 또한, 링크를 할 때 반드시 다음 옵션을 추가한다.
-fPIC -static-libgcc -static-libstdc++
이제 libstdc++ 관련 빌드 문제는 해결되었을 것이다. 이클립스에서는 다음과 같이 해야 한다. 프로젝트 탐색깅에서 프로젝트 이름에서 마우스 오른쪽 버튼 -> Properties -> C/C++ Build -> Generate Makefiles automatically를 해제한다. 이제 수동으로 Make File들을 수정할 수 있다. 단 수정 전에 최소한 한 번은 빌드를 해서 전체 Makefile을 처음부터 다시 작성하는 수고를 하지는 말자.
makefile에서는 라이브러리 연결에 관련된 내용을 수정할 수 있다. 내용을 보면 다음과 같은 내용이 있을 것이다.
# Tool invocations
libbustard_importer.so: $(OBJS) $(USER_OBJS)
@echo 'Building target: $@'
@echo 'Invoking: GCC C++ Linker'
g++ -L/usr/local/lib -shared -o "libbustard_importer.so" $(OBJS) $(USER_OBJS) $(LIBS)
@echo 'Finished building target: $@'
@echo ' '
이것을 아래와 같이 추가해 준다. 바꾸고 저장하는 과정에서 경고가 나오더라도 무시하고 수정한다.
# Tool invocations
libbustard_importer.so: $(OBJS) $(USER_OBJS)
@echo 'Building target: $@'
@echo 'Invoking: GCC C++ Linker'
g++ -fPIC -static-libgcc -static-libstdc++ -L/usr/local/lib -shared -o "libbustard_importer.so" $(OBJS) $(USER_OBJS) $(LIBS)
@echo 'Finished building target: $@'
@echo ' '
다음으로 objects.mk도 수정해야 한다.
LIBS := -lboost_filesystem -lboost_iostreams -lboost_system
이것을 아래와 같이 추가해 준다.
LIBS := -Wl,-Bstatic -lboost_filesystem -Wl,-Bstatic -lboost_iostreams -Wl,-Bstatic -Wl,-Bstatic -lboost_system
아마 이제 정상적으로 so 파일을 생성할 수 있을 것이다. 만약 boost 라이브러리에서 fPIC 문제가 발생한다면 다음과 같이 한다.
sudo ./b2 cxxflags="-fPIC -m64" -j8 -a --prefix=/usr/local
sudo ./b2 install cxxflags="-fPIC -m64" -j8 --prefix=/usr/local
64 비트 컴퓨터일 경우 위와 같이 한다. 만약 LZMA(liblzma.a) 같은 압축 라이브러리에서 fPIC 문제가 발생하면 다음과 같이 한다. XZ Utils(http://tukaani.org/xz/)를 다운로드 받는다.
sudo ./configure --prefix=/usr/local --with-pic
sudo make
sudo make install
중요한 것은 모든 컴파일에서 옵션이 같은 것이 fPIC 관련 에러를 줄이는 방법이다.
댓글