The case of linker unable to find symbol for QtService in MinGW-w64 when developing a Windows service based on QtWebApp

QtWebApp includes QtService for developer's sake when developing Windows service or Linux daemon. QtService is quite well made in many sense, but it's also "abandoned" by Qt Company for years.

I'm using mingw-builds, one of personal builds in MinGW-w64 project, to use the same compiler between Windows and Linux, as well as make use of easy portability. In recent development with QtWebApp I found out that if I dynamic-link QtWebApp the linker cannot find symbol for QtService<QCoreApplication>. As the version for GCC shipped with Qt 5.7 is 5.3 so it's not due to older compiler...... And I found a solution.

Open QtWebApp/qtservice/qtservice.h and find the line below.

template <typename Application>
class DECLSPEC QtService : public QtServiceBase

And I changed the line like this:

template <typename Application>
class /*DECLSPEC*/ QtService : public QtServiceBase

The DECLSPEC changes library header structure using #define. That is changed into either Q_DECL_EXPORT or Q_DECL_IMPORT, and unless it's the time to build the library itself, the value is always Q_DECL_EXPORT. The problem is that QtService is a template class, meaning that the symbol should be changed according to the template details, but if the function is declared as Q_DECL_EXPORT, the compiler assumes that necessary symbols are already built. If you see comment out that DECLSPEC and review the result of the compilation, you can see object file for the header file named qtservice.o.

Well, I had hard time to find this small thing, but I'm relieved that I found it quite quicker than expected. Now I can respect LPGL once again. :)

MinGW-w64에서 QtWebApp 기반 Windows service 개발시 linker가 QtService의 symbol을 찾지 못하는 경우

QtWebApp은 Windows service나 Linux daemon 개발시 편의를 위해 QtService를 함께 탑재하고 있습니다. QtService는 꽤 잘 만들어진 라이브러리입니다만, Qt Company에서 몇년째 손을 놓고 있는, '버려진' 라이브러리이기도 합니다.

저는 Windows-Linux간 동일 컴파일러 사용 및 portability 이슈로 인해 MinGW-w64의 personal build 중 하나인 mingw-builds를 사용하고 있는데, 최근 QtWebApp으로 개발을 진행하던 도중QtWebApp을 dynamic link하면 linker가 QtService<QCoreApplication>의 symbol을 제대로 찾지 못하는 것을 발견했습니다. Qt 5.7에 탑재된 GCC가 5.3이므로 버전이 낮아서 생기는 문제는 아닌 듯 했는데, 결국 방법을 찾았습니다.

QtWebApp/qtservice/qtservice.h 파일에 보면 아래와 같은 내용이 있습니다.

template <typename Application>
class DECLSPEC QtService : public QtServiceBase

그리고 전 이 구문을 이렇게 바꿨습니다.

template <typename Application>
class /*DECLSPEC*/ QtService : public QtServiceBase

딱히 별건 아니고, 저 DECLSPEC은 #define을 통해 library의 header를 바꿉니다. 정확히는 Q_DECL_EXPORT나 Q_DECL_IMPORT 중 하나로 바뀌게 되는데, 라이브러리를 빌드할 때가 아니면 항상 Q_DECL_EXPORT로 선언되어 있습니다. 문제는 뭐냐 하면, QtService 자체는 template class라서 그때그때 symbol이 달라질 수밖에 없는데, 해당 함수를 Q_DECL_EXPORT로 선언해버리면 컴파일러는 해당 symbol이 이미 library로 export된 것으로 판단하고 별다른 조치를 취하지 않는다는데 있습니다. 실제로 저 DECLSPEC을 주석 처리한 뒤 컴파일 결과를 확인해보면 qtservice.o 파일이 별도로 생성된 것을 볼 수 있습니다.

이거 하나를 찾아내려고 꽤나 삽질이 많았습니다만, 그래도 생각보다 쉽게 찾아내서 다행입니다. 이제는 LGPL을 지키면서 마음놓고 개발할 수 있어요. :)

블로그를 이전합니다

뭐, 이런 작은 변방의 블로그에 관심있으신 분들은 아무도 없으시리라 생각합니다만...... (웃음) 블로그 플랫폼을 블로거에서 dev.to로 옮겼습니다. 새 URL은 아래와 같습니다: https://dev.to/teminian 새로운 거처에서 뵙겠습니...

Popular in Code{nested}