qt 4.7.1이상하네요.

sandy의 이미지

뭐 저는 qt 완전 초보고 아는게 하나없지만
이번에 노키아에서 여는 Qt Conference - Seoul 2010(12월 14일)
(여기 관련 글타래가 있네요 , http://kldp.org/node/119396)도 있고 해서
최근에 발표된 Qt 4.7.1을 우분투 제 데스크탑에 컴파일 설치해봤습니다.

뭐 컴파일 과정에 몇가지 문제(이건 따로 다루죠)가 있긴 했지만 잘 컴파일되었고
설치도 끝나 kde 등 의존 프로그램들을 재컴파일해주었습니다.

그 과정에서 조금 심각해 보이는 문제가 나타나 글을 적어봅니다.

qt의 빌딩 툴 중에 qdbuscpp2xml, qdbusxml2cpp 이 있는데 이름이
나타내듯 컴파일과정에서 실시간으로 헤더나 소스파일에서 xml파일을 만들고
반대로 xml파일이 주어지면 헤더나 소스를 만들어 내는 도구죠.

이 툴중 qdbuscpp2xml은 화면(표준출력)으로 결과를 보이거나
-o옵션으로 결과 파일을 만듭니다.

예컨대

qdbuscpp2xml test.cpp > test.xml

또는

qdbuscpp2xml test.cpp -o 5.xml

그런데 새로 설치한 Qt 4.7.1라이브러리로 새로 링크하기위해 kde 라이브러리나 프로그램들을
재컴파일하는 과정에 위 도구가 사용되는데 ,예를 들어

/usr/bin/qdbuscpp2xml /media/sdc1/kdebase-4.2.2/apps/keditbookmarks/toplevel.h > /media/sdc1/kdebase-4.2.2/obj-i686-linux-gnu/apps/keditbookmarks/org.kde.keditbookmarks.xml

/usr/bin/qdbusxml2cpp -m -p toplevel_interface /media/sdc1/kdebase-4.2.2/obj-i686-linux-gnu/apps/keditbookmarks/org.kde.keditbookmarks.xml

이렇게 말이죠.
얼핏 아무 문제없어 보이지만 이런 과정을 거치는
모든 kde프로그램이 모두다 같은 에러로 빌드가 멈춥니다.

예컨대

[ 40%] Generating org.kde.keditbookmarks.xml
cd /media/sdc1/kdebase-4.2.2/obj-i686-linux-gnu/apps/keditbookmarks && /usr/bin/qdbuscpp2xml /media/sdc1/kdebase-4.2.2/apps/keditbookmarks/toplevel.h > /media/sdc1/kdebase-4.2.2/obj-i686-linux-gnu/apps/keditbookmarks/org.kde.keditbookmarks.xml
qdbuscpp2xml: exit code 0 from moc. Aborting <== !!!!!!!!!!!
QProcess: Destroyed while process is still running.
make[2]: *** [apps/keditbookmarks/org.kde.keditbookmarks.xml] error 1

사용된 toplevel.h 파일은 문제가 없습니다.
사용된 qdbuscpp2xml(4.7.1버젼에서 새로 설치한)파일에 무슨 문제가있는걸까요?

qdbuscpp2xml은 내부적으로 /usr/bin/moc-qt4을 호출해 입력 데이타를 처리하고
그 결과를 화면에 출력하게 되어 있는데 이게 결과를 처리하기도 전에 이유없이 exit해 버려서
그에 따라 파일 크기가 0인 아무내용없는 org.kde.keditbookmarks.xml 파일을 만들어 내
전체 빌드가 망가집니다.

간단한 예제 코드를 써서 알아보죠.

[/media/sdc2/test-qt-bin]$ more test.cpp
#include <QString>
#include <QDBusAbstractAdaptor>
 
class TestAdapter : public QDBusAbstractAdaptor 
{
        Q_OBJECT
        Q_CLASSINFO("D-Bus Interface", "tld.example.Foo")
public Q_SLOTS:
        void method(QString foo);
};

이 코드를 처리해서 xml 파일로 만들기 위해 아래 명령을 하면
이 작은 파일에서조차 기대와는 달리 작동하지 않습니다.

$  qdbuscpp2xml test.cpp > test.xml
qdbuscpp2xml: exit code 0 from moc. Aborting
QProcess: Destroyed while process is still running.
 
$ ls -al test.xml
-rw-r--r-- 1 s4ndy s4ndy 0 2010-11-24 18:24 test.xml
 
$  qdbuscpp2xml test.cpp -o test.xml
qdbuscpp2xml: exit code 0 from moc. Aborting
QProcess: Destroyed while process is still running.
 
$ ls -al test.xml
-rw-r--r-- 1 s4ndy s4ndy 0 2010-11-24 18:24 test.xml

strace로 추적해보면 /usr/bin/moc-qt4 도 잘 찾고
입력 파일을 읽어서 잘처리하고 있지만 이렇게 처리된 결과를 옵션에 따라
화면이나 파일로 보낼때 마지막 순간에 이유없이 프로세스간 데이타 전달이 끊기는게 보입니다.

왜 이런 일이 생기는 걸까요?

$strace -ff  qdbuscpp2xml test.cpp > test.xml
 
set_tid_address(0xb6f4e708)             = 27818
sched_getparam(27818, { 0 })            = 0
sched_getscheduler(27818)               = 0 (SCHED_OTHER)
clock_getres(CLOCK_MONOTONIC, {0, 999848}) = 0
sched_get_priority_min(SCHED_OTHER)     = 0
sched_get_priority_max(SCHED_OTHER)     = 0
sched_get_priority_max(SCHED_OTHER)     = 0
 
pipe([3, 4])                            = 0
fcntl64(3, F_SETFD, FD_CLOEXEC)         = 0
fcntl64(4, F_SETFD, FD_CLOEXEC)         = 0
 
 
readlink("/proc/27818/exe", "/usr/bin/qdbuscpp2xml", 4096) = 21
lstat64("/usr/bin/qdbuscpp2xml", {st_mode=S_IFREG|0755, st_size=38808, ...}) = 0
 
pipe([5, 6])                            = 0
fcntl64(5, F_SETFD, FD_CLOEXEC)         = 0
fcntl64(6, F_SETFD, FD_CLOEXEC)         = 0
fcntl64(5, F_GETFL)                     = 0 (flags O_RDONLY)
fcntl64(5, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
fcntl64(6, F_GETFL)                     = 0x1 (flags O_WRONLY)
fcntl64(6, F_SETFL, O_WRONLY|O_NONBLOCK) = 0
rt_sigaction(SIGCHLD, {0xb74ea4f0, [], SA_NOCLDSTOP}, {SIG_DFL}, 8) = 0
 
 
open("test.cpp", O_RDONLY|O_LARGEFILE|0x80000) = 7
fcntl64(7, F_SETFD, FD_CLOEXEC)         = 0
fstat64(7, {st_mode=S_IFREG|0644, st_size=231, ...}) = 0
brk(0x8094000)                          = 0x8094000
fstat64(7, {st_mode=S_IFREG|0644, st_size=231, ...}) = 0
 
 
read(7, "#include <QString>\n#include <QDB"..., 16384) = 231
read(7, "", 16153)                      = 0
 
 
clone(Process 27819 attached
child_stack=0xb6c9e4b4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb6c9ebd8, {entry_number:6, base_addr:0xb6c9eb90, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb6c9ebd8) = 27819
[pid 27818] pipe([8, 9])                = 0
[pid 27818] fcntl64(8, F_SETFD, FD_CLOEXEC) = 0
[pid 27818] fcntl64(9, F_SETFD, FD_CLOEXEC) = 0
[pid 27818] pipe([10, 11])              = 0
[pid 27818] fcntl64(10, F_SETFD, FD_CLOEXEC) = 0
[pid 27818] fcntl64(11, F_SETFD, FD_CLOEXEC) = 0
[pid 27818] pipe([12, 13])              = 0
[pid 27818] fcntl64(12, F_SETFD, FD_CLOEXEC) = 0
[pid 27818] fcntl64(13, F_SETFD, FD_CLOEXEC) = 0
[pid 27818] pipe([14, 15])              = 0
[pid 27818] fcntl64(14, F_SETFD, FD_CLOEXEC) = 0
[pid 27818] fcntl64(15, F_SETFD, FD_CLOEXEC) = 0
[pid 27818] pipe([16, 17])              = 0
[pid 27818] fcntl64(16, F_SETFD, FD_CLOEXEC) = 0
[pid 27818] fcntl64(17, F_SETFD, FD_CLOEXEC) = 0
 
[pid 27818] clone(Process 27820 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb6f4e708) = 27820
 
 
[pid 27820] execve("/usr/bin/moc-qt4", ["/usr/bin/moc-qt4", "test.cpp"], [/* 57 vars */]) = 0
[pid 27820] open("test.cpp", O_RDONLY)  = 3
[pid 27820] read(3, "#include <QString>\n#include <QDB"..., 16384) = 231
[pid 27820] read(3, "", 12288)          = 0
[pid 27820] read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\5\0\0\0\5\0\0"..., 4096) = 380
[pid 27820] read(3, "\nKST-9\n", 4096)  = 7
 
 
[pid 27820] write(1, "/*******************************"..., 2461) = 2461
[pid 27820] exit_group(0)               = ?
 
 
Process 27820 detached  <======!!!!!
 
 
[pid 27818] ioctl(10, FIONREAD <unfinished ...>
 
[pid 27819] <... select resumed> )      = ? ERESTARTNOHAND (To be restarted)
[pid 27819] --- SIGCHLD (Child exited) @ 0 (0) ---  <======!!!!!
[pid 27819] write(6, "\0", 1)           = 1
[pid 27819] read(5, "\0", 1)            = 1
[pid 27819] write(17, "\0", 1)          = 1
[pid 27819] select(6, [5], NULL, NULL, NULL <unfinished ...>
 
 
 
[pid 27818] <... ioctl resumed> , [2461]) = 0
[pid 27818] read(10, "/*******************************"..., 2461) = 2461
[pid 27818] read(16, "\0", 1)           = 1
[pid 27818] waitpid(27820, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG) = 27820
[pid 27818] ioctl(-1, FIONREAD, [0])    = -1 EBADF (Bad file descriptor)
[pid 27818] ioctl(-1, FIONREAD, [0])    = -1 EBADF (Bad file descriptor)
[pid 27818] close(17)                   = 0
[pid 27818] close(16)                   = 0
[pid 27818] close(7)                    = 0
[pid 27818] write(1, "<!DOCTYPE node PUBLIC \"-//freede"..., 299) = 299
[pid 27818] open("/proc/stat", O_RDONLY) = 7
[pid 27818] write(6, "@", 1 <unfinished ...>
 
 
[pid 27819] <... select resumed> )      = 1 (in [5])
[pid 27819] read(5, "@", 1)             = 1
[pid 27819] close(8)                    = 0
[pid 27819] close(11)                   = 0
[pid 27819] _exit(0)                    = ?
Process 27819 detached
 
 
<... write resumed> )                   = 1
close(6)                                = 0
close(5)                                = 0
rt_sigaction(SIGCHLD, {SIG_DFL}, {0xb74ea4f0, [], SA_NOCLDSTOP}, 8) = 0
exit_group(0)                           = ?
Process 27818 detached

좀더 알기쉽게 strace 내에서 출력을 파일로 보내지 않고 strace -ff qdbuscpp2xml test.cpp 로 그냥 화면으로 보내보면 xml 파일이 화면에 잘 표현되고 있는것이 나타납니다.
그러나 strace 없이는 화면에 이 xml 자료가 나오지 않습니다

[pid 28735] fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 5), ...}) = 0
[pid 28735] write(1, "<!DOCTYPE node PUBLIC \"-//freede"..., 143<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
) = 143
[pid 28735] write(1, "<node>\n", 7<node>
)     = 7
[pid 28735] write(1, "  <interface name=\"tld.example.F"..., 37  <interface name="tld.example.Foo">
) = 37
[pid 28735] write(1, "    <method name=\"method\">\n", 27    <method name="method">
) = 27
[pid 28735] write(1, "      <arg name=\"foo\" type=\"s\" d"..., 48      <arg name="foo" type="s" direction="in"/>
) = 48
[pid 28735] write(1, "    </method>\n", 14    </method>
) = 14
[pid 28735] write(1, "  </interface>\n", 15  </interface>
) = 15
[pid 28735] write(1, "</node>\n", 8</node>
)    = 8

추측하기로 qt4.7.1 에 구현된 Qprocess 나 Qthread 에서 clone으로 생겨난 자식 프로세스를 제대로 처리 못하고 있는게 아닌가 의심됩니다

ifree의 이미지

moc 에서 에러가 나는 경우라면 qmake 가 제대로 처리되지 않았을 확률이 높은데 이 부분은 체크해 보셨는지요.

nagaman의 이미지

WEBKIT, XML, NETWORK 정상작동합니다만.. // 가끔 Qthread가 죽어버립니다.. 원인불명.. stack trace 가 안되네요 .ㅜ

음.. 절망적인건... 속도가 너무 구리네요..

그래서 그냥 php로 모든것을 해결하려 합니다. ㅜㅜ