windeployqt를 이용하여 Qt Quick Controls 기반의 application을 packaging할 때의 주의점

Qt 5.5에서 windeployqt를 사용하여 Qt Quick Controls 기반의 application에 대한 packaging을 수행할 경우, PrivateWidgets 부분을 가져오지 못해 타 시스템에서는 UI가 보이지 않는 문제점이 있습니다.

이 문제를 해결하기 위해서는 Qt의 qml\QtQuick\PrivateWidgets 폴더를 패키지 디렉토리의 상응하는 위치로 복사해 주어야 합니다. (e.g. deployment\QtQuick\PrivateWidgets)


Qt Quick Control을 쓰시는 분들께 도움이 되시기 바랍니다.

Cautions on using windeployqt on Qt Quick Controls based applications

When packaging applications using windeployqt in Qt 5.5, you may experience the application doesn't show the interface because windeployqt doesn't recognize links to PrivateWidgets.

To solve the problem, copy qml\QtQuick\PrivateWidgetsfolder in Qt to respective location in deployment folder(e.g. deployment\QtQuick\PrivateWidgets).

Hope this helps those working with Qt Quick Controls.

On site development and Qt

Recently I had a chance to develop some applications on site. I used the greatly-productive Qt and Qt Creator, Application was built in an instant, and result was satisfactory. But the experience remained me some uncomfortable memory.

Except for skeleton codes, I put only 10 to 20 lines. I had to find out DLLs with more than 20MB, put them all to USB thumb drive, and I put the drive to PCs here and there. In each run I had to wait for 2~3 seconds more after starting running, and the delay became a burden as I repeated the job.

On Windows, Qt initiates DirectX and OpenGL, regardless of whether those modules are actually used in the application of not. My application was based fully on Qt Widgets and GDI, so that there's no way DirectX or OpenGL would be involved, but Qt initialized those stuff anyway. And to initialize, you have to wait for two or three seconds. If your system was already using those that's no problem, but in office environment, chances are that they'll be used only when you play video games, avoiding eyes of your boss.

Of course if the application is big enough to show splash screen saying "WAIT!" waiting for two or three seconds is no problem, but for apps quickly developed on site and run instantly, it's like forever - when you're busy and quick-tempered, chances are that you hit enter key a lot of times, resulting in starting a lot of instances at once, delaying the actual start more than ever(well, sometimes you experience Windows eats your keyboard or mouse input. don't you?).

Nowadays I feel that the high productivity and abundant features of Qt has its own tradeoff - e.g. performance issue(not only startup time, but also performance of features, like QLinkedList against similar others) and shared library. Of course in Linux the situation can be different, but in Windows it has its own story(if you're a GTK user that's yet another different story, but it's out of scope as for now).

Anyway, after experiencing this and that, I moved again from Qt to wxWidgets. I love the instant startup at cold start and freely available static link thanks to its license policy, resulting in easier deployment. There are, of course, some(expected) productivity losses or features not existing, but it can be overcome with the power of will(.....) and my own development.

I don't want to open the flame - Qt is really a great product and I totally agree. But there's no such thing as one size that fits to all. For some time being, I'll have fun with my wxWidgets and Code::Blocks.

필요한 application의 현장 내 즉각적인 개발과 Qt

최근 현장에서 즉석으로 프로그램들을 만들 일이 있었습니다. 생산성 와방(......)인 Qt에 Qt Creator를 대동했습니다. 프로그램은 순식간에 만들어졌고, 원하는 결과를 정확하게 도출해냈습니다. 하지만 제게 그 경험은 일부 불편함을 남겼습니다.

Skeleton code를 제외하고 제가 작성한 핵심 코드는 약 10~20줄 남짓이었습니다. 그리고 전 20MB가 넘는 DLL들을 일일이 찾아 넣었고, 한데 모인 프로그램 패키지를 USB 메모리에 담아 각 PC에 꽂아가며 일일이 실행했습니다. PC에서 프로그램을 실행할 때마다 약 2~3초간의 지연이 있었고, 실행이 반복될수록 저 지연이 제게는 큰 부담으로 다가왔습니다.

Windows에서 Qt는 실행시 DirectX와 OpenGL을 기동시킵니다. 프로그램이 실제로 이 모듈들을 사용하는지의 여부는 상관없습니다. 제가 만든건 GDI 기반의 Qt Widgets 기반 프로그램이라 DirectX나 OpenGL이 끼어들 틈이 없었습니다만, Qt는 어쨌든 실행만 했다 하면 저 양대 그래픽 가속 시스템을 기동시킵니다. 그리고 저 모듈들은 최초 기동할때 최고 2~3초 정도를 잡아먹습니다. 이 모듈들이 이미 기동중이었으면 상관없지만, 사무용 PC 환경에서 저들 모듈이 기동하는건 팀장님 몰래 게임할 때(......) 빼고는 거의 없죠.

물론 splash screen을 띄워놓고 "기다리쇼"라고 할 정도의 큰 프로그램이라면 2~3초정도의 delay는 큰 문제가 되지 않습니다만, 현장에서 즉석에서 만들어져서 간단하게 쓸 프로그램에게 2~3초는 꽤 긴 시간입니다. 특히나 바쁜 상황일 경우, 성질 급한 사람들은 그 시간을 못 기다리고 엔터키를 연발하다가 instance를 수십개 넘게 만들어내는, 덕분에 프로그램의 실행이 더 지연되어 귀중한 시간을 낭비하는 상황까지 발생할 수 있습니다(뭐 사실 이런 사람들이 이해가 가기도 하는게, 가끔 보면 Windows가 키보드나 마우스 입력을 먹어버리는 경우가 있기도 하죠).

요즘 들어서 느끼는 거지만, Qt가 높은 생산성과 다양한 기능을 제공하는 이면에는 군데군데 발생하는 성능 이슈(꼭 cold start time이 아니더라도, linked list나 다른 여러 부분에서 미친듯이 속도가 느립니다)와 거대한 shared library가 있다는 생각이 듭니다. 일종의 tradeoff로 보고 있습니다만...... 물론 리눅스에서는 상황이 다릅니다만, Windows에서는 또 Windows만의 이야기가 있는 법이지요(GTK+ 계열 사용자시라면 또 다른 문제가 있을 것 같기도 합니다만, 그 부분은 다른 문제이니 여기서는 다루지 않겠습니다).

하여튼, 저런 상황을 겪고 난 이후 저는 또다시 Qt에서 wxWidgets로 옮겨왔습니다. Cold start시에도 instant로 번쩍하고 뜨고, 라이선스 정책 덕분에 static link에 대한 제약도 없어서 배포도 편합니다. 물론 구조적 특성상 생산성이 살짝 떨어진다거나 일부 기능이 없다거나 하는 문제도 있긴 하지만, 그 부분은 근성(......)과 직접 개발로 충분히 벌충할 수 있는 수준인 것 같습니다.

Qt는 정말 좋은 라이브러리입니다. 하지만 평양 감사도 저 싫으면 못하는 법이고, 모든 몸에 딱 맞는 하나의 치수를 가진 옷같은건 어디에도 존재하지 않지요. 당분간은 wxWidgets와 Code::Blocks로 연명하게 될 것 같습니다.

분명 랜선이 잘 연결되어 있음에도 리눅스의 ip link나 ifconfig에서 "NO_CARRIER" 메시지가 뜬다면......

가끔가다 보면 사람 참 황당하게 될 때가 있죠. 랜선은 멀쩡하고, 인터페이스 카드도 불을 잘 깜빡이는데, 리눅스에서 ip linkifconfig를 쳐보면 "NO_CARRIER"메시지가 뜨는 경우가 있습니다. 더 황당한건, 이 하드웨어에서 Windows를 부팅해보면 인터넷이 멀쩡하게 잘 된다는 거죠.

얼마 전에 제가 경험한게 바로 이 증상입니다. 정확히는 이런 식이었습니다:
  1. Cold boot to Linux: NO_CARRIER
  2. Cold boot to Windows and reboot to Linux: 연결되네!(무시라?)
그러니까, 리눅스로 바로 부팅하면 네트웍이 안되고, Windows로 부팅했다가 리눅스로 부팅하면 리눅스에서 네트웍이 되는 황당한(......) 현상인 겝니다. 상식적으로 이해가 안되죠. Arch Linux로 Gentoo(stable)로 바꿔봤고, dhcpcd도 dhclient(dhcp ebuild에 있는거)로 바꿔봤습니다만 소용이 없더군요. 사실 Gentoo+dhclient 조합으로 되는줄 알았는데, 나중에 다시 해보니 증상이 그대로였습니다.
 구글링을 해보니 Arch Linux 포럼에 저와 비슷한 증상을 경험한 사람들이 꽤 있더군요. 그리고 atl1c 모듈 말고 다른 네트워크 카드에서도 증상이 일어났습니다(Marvel에서 온 사람들도 있고, Qualcomm Atheros의 다른 계열 카드도 있고......). 포럼의 집단지성이 뭔가 해결책을 찾긴 했지만, 제게는 통하지 않더군요. 그리고 제 문제는 딴 곳에 있었습니다.

해서, 하여간 이런 별난 경우가 발생했을때 어떻게 대처할지에 대해서, 제가 발견한 내용을 포함하여 두 가지 대응방안을 적어놓습니다:
  1. (직접 찾은 것)
    BIOS에서 "power up from PCI device" 기능을 끕니다. 전 그러니까 되더군요(......). 다른 "power up from....." 설정은 관련이 없는 것 같습니다(이를테면 키보드로 켜기, 마우스로 켜기 등). 저도 "power up from USB keyboard" 기능은 켜놓고 있습니다.
  2. (https://bbs.archlinux.org/viewtopic.php?pid=994513#p994513에서 확인)
    PCI 시스템에 "on" 메시지를 던집니다. 이를테면 이런 식입니다: echo on > /sys/bus/pci/devices/0000:00:XX.0/power/control
간단하죠?

이 황당한 증상으로 멘붕에 빠지신(......) 다른 분들께도 도움이 되시길 바랍니다.

What to do if ifconfig/ip link says "NO_CARRIER" in your Linux box even though the line is physically connected

There are times that make you into craziness. Your physical network connection is okay, the lamps on the interface card are flickering, and you see "NO_CARRIER" in your Linux box if you type ip link or ifconfig(deprecated). And guess what? In same machine, if you boot with Windows, you're actually connected to Internet!

Yes. That's what I experienced a few weeks ago. More precisely, the symptom was as follows:
  1. Cold boot to Linux: NO_CARRIER
  2. Cold boot to Windows and reboot to Linux: IT'S WORKING!(what?)
So, if I boot directly to Linux and I see NO_CARRIER message, but if I boot to Windows and reboot to Linux(warm boot) and my Linux can connect to the network as nothing happened.

Darn. Which curse did make my box as dull as possible like this? First I blamed my lovely bleeding-edge Arch Linux and built Gentoo stable, and later blamed dhcpcd and installed dhclient(in dhcp ebuild). I thought I got it with Gentoo+dhclient, but I was mistaken. Neither was the devil within.


I googled and in Arch Linux forum I found that there are several people with same issue, and it was NOT only atl1c module either. Some were using Marvel chipsets, some used the same Qualcomm Atheros, and so on. Their "collective intelligence" found out a solution, but it was of no effect to me(and some others in the forum), and I found yet the other cause for the issue.

So, here I leave things I found you can try(both googled ones and my own finding):
  1. (My own finding)
    Disable
    "power up from PCI device" feature from BIOS. Yes. From BIOS. And it's done. Other "power up from....." settings(e.g. keyboard, mouse) were actually not related to the issue in any way(still I enable "power up from USB keyboard" feature).
  2. (from https://bbs.archlinux.org/viewtopic.php?pid=994513#p994513)
    Send "on" message to the PCI system. e.g. echo on > /sys/bus/pci/devices/0000:00:XX.0/power/control

Simple, huh?

Hope this helps others with same symptom.

mingw-builds 5.1.0R0으로 Qt Creator 3.4.1을 빌드하기

mingw-builds 5.1.0 Release 0으로 Qt Creator 3.4.1을 빌드하는 동안 발견되는 문제들과 그 해결방안(이라기보단 우회방안)을 정리했습니다.

----------------------------------------
[QString::QString(const char *) is private]
문제가 되는 부분은 src/lib/corelib/tools/filetime_win.cpp의 108번째 줄입니다. QT_NO_CAST_FROM_ASCII이 선언되었을때 QString의 헤더 파일과 관련되어 있는 것 같긴 한데, 자세한건 잘 모르겠네요.

일단 보시면, 해당 부분은 이렇게 생겼습니다:
const QString result = QString("%1.%2.%3 %4:%5:%6")

이 부분을 이렇게 바꾸면 어쨌든 해결됩니다:
const QString result = QString(QLatin1String("%1.%2.%3 %4:%5:%6"))

뭐 일단 컴파일이 되는게 중요하죠. ;)

----------------------------------------
[Psapi.lib is not found]
이 건 역시 qbs 빌드시 발생하는 오류입니다. 경우에 따라 src/shared/qbs/src/lib/corelib디렉토리에 있는 Makefile.Debug 또는 Makefile.Release 파일을 수정해야 합니다. 텍스트 에디터로 파일을 연 뒤 Psapi.lib를 찾아보면 다음과 같은 내용을 발견할 수 있습니다:

LIBS        =        -lglu32 -lopengl32 -lgdi32 -luser32 Psapi.lib -LD:/Components/Qt-5.4.2-MinGW32-5.1.0R0/qtbase/lib -lQt5Script -lQt5Gui -lQt5Xml -lQt5Core release\qbscore_resource_res.o 

아래와 같이 Psapi.lib-lpsapi로 바꿔주기만 하면 문제가 해결됩니다:
LIBS        =        -lglu32 -lopengl32 -lgdi32 -luser32 -lpsapi -LD:/Components/Qt-5.4.2-MinGW32-5.1.0R0/qtbase/lib -lQt5Script -lQt5Gui -lQt5Xml -lQt5Core release\qbscore_resource_res.o

아무래도 VC nmake에서 GNU makefile로 설정을 갖다붙이다가 실수한 것 같습니다. 어째 개발진 양반들이 파일 만들면서 딴생각을 한 것 같네요. :P

----------------------------------------
[MIB_TCP_STATE is not declared]
만일 Visual Studio를 쓴다면 단지 iphlpapi.h를 인클루드하는 것으로 모든게 해결됩니다만, MinGW에서는 이걸 손수 선언해줘야 합니다. src/lib/utils에 있는 tcpportsgatherer.cpp파일을 보시면 이런 내용을 보실 수 있습니다:
// Missing declarations for MinGW 32.
#if __GNUC__ == 4 && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 2)
typedef enum { } MIB_TCP_STATE;
#endif

아무래도 GCC 버전이 4.X일때만 동작하는 것 같죠? #if 부분을 comment out하는 걸로 해결할 수 있습니다.
// Missing declarations for MinGW 32. 
//#if __GNUC__ == 4 && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 2)
typedef enum { } MIB_TCP_STATE;
//#endif

이걸로 끝입니다. Qt Creator 3.4.1로 오신 여러분을 환영합니다!

Building Qt Creator 3.4.1 with mingw-builds 5.1.0R0

There are some issues in building Qt Creator with mingw-builds 5.1.0 Release 0. Here are compile errors and workarounds:

----------------------------------------
[QString::QString(const char *) is private]

The issue occurs in building qbs and on line 108 of file src/lib/corelib/tools/filetime_win.cpp. It seems to be related to QString header file when QT_NO_CAST_FROM_ASCII is defined, but I have no idea on details.

You can see the line looks like this:
const QString result = QString("%1.%2.%3 %4:%5:%6")


And you can change the line like this to workaround:
const QString result = QString(QLatin1String("%1.%2.%3 %4:%5:%6"))

Now it's resolved anyway. ;)

----------------------------------------
[Psapi.lib is not found]
One more build error when building qbs. You've got to manually edit either Makefile.Debug or Makefile.Release in src/shared/qbs/src/lib/corelib directory. Search for Psapi.lib with your favorite text editor, and you'll see this:
LIBS        =        -lglu32 -lopengl32 -lgdi32 -luser32 Psapi.lib -LD:/Components/Qt-5.4.2-MinGW32-5.1.0R0/qtbase/lib -lQt5Script -lQt5Gui -lQt5Xml -lQt5Core release\qbscore_resource_res.o 

Just change Psapi.lib to -lpsapi as shown below and it's done:
LIBS        =        -lglu32 -lopengl32 -lgdi32 -luser32 -lpsapi -LD:/Components/Qt-5.4.2-MinGW32-5.1.0R0/qtbase/lib -lQt5Script -lQt5Gui -lQt5Xml -lQt5Core release\qbscore_resource_res.o

It seems to be human error when copy-and-pasting VC nmake file to GNU makefile. Hey Trolls, WAKE UP!

----------------------------------------
[MIB_TCP_STATE is not declared]
If you're using Visual Studio, it's okay by just including iphlpapi.h in your source code, yet with MinGW you have to declare yourself. If you read the file tcpportsgatherer.cpp in src/lib/utils you'll see something like this:
// Missing declarations for MinGW 32.
#if __GNUC__ == 4 && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 2)
typedef enum { } MIB_TCP_STATE;
#endif

Well, this seems to work only if you're using GCC version 4.X, not with 5.1.0. Just comment #if like this and you're done.
// Missing declarations for MinGW 32.
//#if __GNUC__ == 4 && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 2)
typedef enum { } MIB_TCP_STATE;
//#endif

Now everything's done. Welcome to the world of Qt Creator 3.4.1! :)

Windows에서 Qt Widget 프로그램을 cold start하면 시간이 얼마나 오래 걸릴까?

아마 다들 아시겠지만, Qt는 시스템 위젯을 사용하는 대신 전용 위젯을 따로 사용합니다. 덕분에 DLL들 크기가 꽤 큰 편입니다(Qt Core와 Qt GUI, 그리고 기본 플러그인 몇 개만 합쳐도 20MB를 넘어습니다). 뒤집어서 말하자면 프로그램이 cold start를 하면 디스크 읽기 때문에 상대적으로 시작이 느릴 수밖에 없습니다.
그런데, 느리다면 얼마나 느리려나요? 스톱워치로 재보니 한 4초쯤 되는 것 같긴 하던데, 프로그램 동작을 사람 눈대중으로 측정하는건 프로그래머가 할 짓은 아닌 것 같더군요. 해서 Qt Creator가 기본으로 제공하는 Qt Widget application 소스코드를 살짝 수정해봤습니다:

#include “widget.h”
#include <QApplication>
#include <QDateTime>
#include <QMessageBox>
int main(int argc, char *argv[])
{
  QDateTime start=QDateTime::currentDateTime();
  QApplication a(argc, argv);
  Widget w;
  w.show();
  QMessageBox::information(NULL, “Time”, QString::number(start.secsTo(QDateTime::currentDateTime())));
  return 0;
}

간단하죠?
이 프로그램을 2012년쯤에 산 펜티엄에서 돌려보니 한 2초 정도가 걸리더군요. Warm start(재시작)시에 걸린 시간은 1초 미만이라 별 의미는 없어 보입니다.
그런데 이런 쓸데없는 결과에 관심있으신 분이 있으시긴 하려나(……).

How slow is it to cold start a Qt Widget application on Windows?

As you know, Qt uses its own widgets rather than using one system provides. So its DLLs are large(at least 20MB or so for just Qt Core + Qt GUI + some default plugins) so that it takes a bit relatively long to cold start the application.

But how long? I took my stopwatch application on my phone and it says it’s about 4 seconds for just showing blank window, but it’s not fair to rely on human sensory as a programmer myself.

So I tweaked the default Qt Widget application provided by Qt Creator as follows:


#include “widget.h”
#include <QApplication>
#include <QDateTime>
#include <QMessageBox>

int main(int argc, char *argv[])
{
   QDateTime start=QDateTime::currentDateTime();
   QApplication a(argc, argv);
   Widget w;
   w.show();

   QMessageBox::information(NULL, “Time”, QString::number(start.secsTo(QDateTime::currentDateTime())));
   return 0;
}


SImple, huh?

I ran the application on my Pentium which I bought at 2012 or so and found out that it takes 2 seconds to create the widget and show. For warm start(restart), it takes less than 1 second so it’s meaningless.

Anyone interested in this result?

One Year after Sinking of the MV Sewol

I’m sorry.I’m ashamed.I cannot raise my face.

The crybaby became father of a child, and soon becomes father of two children, but now he turns to the crybaby again.

My deepest apologies and regrets to the souls sacrificed in the sinking; children, fathers, mothers, brothers and sisters.

The present of the living is really a shame for those in heaven, yet I’ll step forward, however slow and hard it is.

Rest in peace.

세월호 참사 1주기입니다

미안합니다.
부끄럽습니다.
고개를 들 수가 없습니다.
어렸을 적 울보였던 아이는 이제 한 아이의 아버지이자 곧 두 아이의 아버지가 될 사람이 되었지만 오늘 또다시 울보 아이가 되어 눈물을 흘립니다.

세월호 참사로 희생된 영혼들. 아이들. 아버지들. 엄마들. 그리고 형과 누나와 동생들. 그 모든 분들께 그저 죄송스러울 따름입니다.

삶이 남은 자의 현재는 걸음을 멈추신 그대들이 하늘 위에서 내려다보기에 부끄러울 뿐입니다만, 아무리 느리더라도 어떻게든 한 발 한 발 앞으로 나가보겠습니다.

블로그를 이전합니다

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

Popular in Code{nested}