Development/FAQs/Technical FAQ/ja: Difference between revisions

From KDE TechBase
(Created page with "=="virtual tables error" というエラーが出ます。==")
(Created page with "このエラーは、.moc ファイルがソースファイルと同期していない場合や、リンクされていない場合に多く起こります。正しく moc を使...")
Line 104: Line 104:
=="virtual tables error" というエラーが出ます。==
=="virtual tables error" というエラーが出ます。==


This often comes from the moc files not being in sync with the sources, or not linked at all. Check that you are running the right moc. 'which moc' will tell it. Regenerate your moc files (make force-reedit; make clean; make).
このエラーは、.moc ファイルがソースファイルと同期していない場合や、リンクされていない場合に多く起こります。正しく moc を使っているかどうか確かめて下さい。'which moc' で分ります。また、moc ファイルを再生成して下さい。 (make force-reedit; make clean; make)  


==I have added Q_OBJECT to myClassHeader.h but no moc files is generated?==
==I have added Q_OBJECT to myClassHeader.h but no moc files is generated?==

Revision as of 08:20, 6 February 2012

Other languages:


Development/FAQs/Technical FAQ

Warning
This section needs improvements: Please help us to

cleanup confusing sections and fix sections which contain a todo


The build system has changed in KDE4.

新しいアプリケーションを作り始めるにはどうすればよいですか?

kdesdk/kapptemplate か kdevelop を使って CMakeLists.txt を生成するのが一番簡単です。あるいは、他の KDE アプリケーションから CMakeLists.txt をコピーし、それを今ある KDE ソースコードのトップディレクトリに組み込むという方法もあります。古い方法ですが、スクラッチから作ることもできます。

plasma、kpart、kio、kdeinit... これらは何なのでしょう?

TechBase、特にアーキテクチャに関するページを確認してみてください。KDE book をチェックしてみるのも良いでしょう。

kpart を使う必要はあるのでしょうか?

無理に使う必要はありません。しかし使ったほうがはるかに良いです。KPart は強力なコードの再利用を可能にします。Given how simple it is to use the technology and how widely it is deployed, it is a shame not to use it if you can.

CMakeLists.txt はどうやって書けばよいのでしょうか?

CMake チュートリアルを参照してください。

make のターゲットにはどんなものがありますか?

  • all: デフォルトターゲット ("make" とタイプした時に実行されるターゲット)
  • clean: 全ての生成されたファイルを消去します。
  • distclean: clean で消去されるファイルに加えて Makefile.cvs から生成されるファイルも消去します。KDE ではあまり役に立ちません("dist" のコンセプトを知るには dist の項を、本当のクリーンを行なうよりよい方法を知るには svn-clean の項をみてください)。
  • dist: SVN ソースから tar ball を作ることを想定しています。しかし、KDE ではあまりサポートされていません。kdesdk/scripts/cvs2pack を使った方が良いでしょう。
  • force-reedit: Makefile.am を使って automake や am_edit をもう一度実行します。
  • install: 全てをインストールします。
  • install-strip: 全てをインストールし、バイナリファイルを strip します。(デバッグシンボルを取り除きます)
  • install-exec: バイナリファイルやライブラリファイルのみをインストールします。
  • install-data: データファイルのみをインストールします。
  • check: テストプログラムをコンパイルします。(それらは check_PROGRAMS で定義されています) "make check" の途中で実際にそれらのプログラムを実行することも出来ます。kdelibs/arts/tests/Makefile.am を参照して下さい。

SVN から checkout したのですが、configure スクリプトや Makefile ファイルが見あたりません

"make -f Makefile.cvs" を実行してください。Makefile を生成してくれます。

特定のディレクトリを一時的にビルドから除外するにはどうすればよいですか?

プログラムをハックする際、特定のディレクトリをビルドの対象から除くと便利かもしれません。もしそうしなければコンパイルされてしまうのですが、それは必要のないことです。 また、コンパイルされていないソースを checkout してきて、コンパイルエラーを直す時間や知識がない場合、ディレクトリをコンパイルしたくないかもしれません。 トップディレクトリで行なう方法とサブディレクトリで行なう方法の二つがあります。トップディレクトリで行なう方法は、単純にコンパイルしたくないディレクトリを消去すれば良いです(または、checkout しない)。

もし何らかの理由でそのようなことをしたくないのであれば、configure を実行する前に DO_NOT_COMPILE=someapp としてみて下さい。そうすれば、configure は "someapp" をスキップします。もしほんの少しのディレクトリしかコンパイルしたくなければ、DO_NOT_COMPILE にほとんど全てのディレクトリを加える代わりに、コンパイルしたいトップレベルのサブディレクトリをトップディレクトリの inst-apps というファイルにリストアップしてください。

サブディレクトリを含むディレクトリをコンパイルしないで済ますには、Makefile や Makefile.am を修正しなくてはいけません。Makefile.am を修正することは推奨されていません。なぜなら、そのファイルは KDE Subversion にも入っており、まちがってコミットしてしまう恐れがあるからです。よってここでは、Makefile を修正する方法を示します。

コンパイルしたくないディレクトリのひとつ上のディレクトリにある Makefile をテキストエディタでひらいて SUBDIRS 変数を探して下さい。多くの場合、次のようになっているはずです。

SUBDIRS = share core ui . proxy taskmanager taskbar applets extensions data

コンパイルしたくないディレクトリをこの行から消して下さい。そうすれば、新しく make した際、そのディレクトリのコンパイルはスキップされます。

たまに、SUBDIRS が他の変数から構成されるので難しくみえることがあるも知れません。

SUBDIRS = $(COMPILE_FIRST) $(TOPSUBDIRS) $(COMPILE_LAST)

この場合、COMPILE_FIRSTTOPSUBDIRSCOMPILE_LAST を探して下さい。それらの中にあなたがコンパイルしたくないディレクトリが入っているはずです。それを見付けたところで削除して Makefile を保存して下さい。

You can also copy the original line in the file when editing and make it a comment by prefixing a '#' in front of it. Then undoing the change is as easy as making the modified line a comment and removing the comment in the original line.

どのようなコンパイルオプションがありますか?

--enable-debug

デバッグシンボルを組み込み、最適化を不可にします。また、kdDebug() によるロギングを有効にします。

--disable-debug

前のオプションの逆です。最適化を有効にし、kdDebug() によるロギングを無効にします。

--enable-final

すべての .cpp ファイルを1つの .all_cpp.cpp ファイルにまとめ、それぞれの .cpp ファイルをコンパイルする代わりにそのファイルを1回でコンパイルします。これにより、コンパイルを速くし、より最適化されたコードを生成します。しかし、かなり多くのメモリを必要とします。また、様々なソースファイルからインクルードされるヘッダファイルが次々とクラッシュしたときや、違うソースファイルで同じ名前の C スタティク関数を使ったときは、コンパイルエラーになります。この方法はパッケージングするには有効ですが、もちろん開発者がすべきではありません。なぜなら、1つファイルを修正するだけで全部を再コンパイルしなくてはいけないからです。

--disable-fast-perl

By default KDE uses perl instead of sh and sed to convert Makefile.in into Makefile. This is an addition to autoconf done by Michael Matz. You can use this option to disable this but it is a lot slower.

どのようなコンパイルオプションが推奨されていますか?

もしあなたが開発者なら、Qt や KDE を --enable-debug オプションを付けてコンパイルすべきです。そうすれば、Qt や KDE の関数呼び出しの内部まで自分のプログラムをデバッグできます。 あなたが純粋なユーザーでも、--enable-debug オプションを付けても問題ありません。KDE はより多くのディスクスペースを占めることになりますが、それでデスクトップが遅くなることはありません。このオプションを付ける利点としては、アプリケーションがクラッシュした際にスタックトレースを得ることが出来ることです。もし、クラッシュの挙動に再現性があるならば、bugs.kde.org でそのクラッシュが報告されていないことを確認した後に、提出してください。それにより、KDE を改善していくことが出来ます。 Qt に関しては、qt-copy/README.qt-copy でコンパイルオプションの説明がされています。

コンパイルを速く済ますための Tips はありますか?

上にある --enable-final を読んで下さい :) make final は --enable-final なしでも現在のディレクトリに関して all-in-one-file トリックを使います。make no-final は --enable-final を付けていても現在のディレクトリを普通の方法でコンパイルします。 moc ファイルをインクルードして下さい! QObject の派生クラスを定義しているヘッダファイルは .moc ファイルを生成するために moc を通さなくてはいけません。.moc ファイルもコンパイルしなくてはいけませんが、方法は2つあります。ひとつは別々にコンパイルする方法、もうひとつはクラスを実装しているファイルにインクルードする方法です。後者の方がコンパイルスピードの点で効率的です。kdesdk/scripts/includemocs ではこの方法が自動的にこれを行ないます。 あるいは、容量の大きい RAM や、高速なマシン、新しい CPU を購入しましょう。bi-PIII 866 MHz と 1GB の RAM では、まともな速度で KDE はコンパイルされます。

Makefile の中で STRIP 変数がセットされているにもかかわらず、どこでも使われていないようですが…?

strip はコンパイル時に行なわれます。これを使うには "make install" の代わりに "make install-strip" を使ってください。

ソースコードを書く際、どのようにインデントすればよいですか?

今あるアプリケーションを書き換えるのであれば、そのアプリの作者のインデントを尊重してください。そうでなければ、あなたの好きなようにインデントを行ってください。

i18n と I18N_NOOP の違いは何ですか?

QString translatedStuff=i18n("foobar"); を使った場合、translatedStuff は "foobar" の翻訳結果が含まれます。一方、 const char *markedStuff = I18N_NOOP("foobar"); を使った場合、marketStuff はまだ、リテラル "foobar" を含んでいます。しかし、翻訳者はそのが翻訳されてほしいことを分っているので、後に QString translatedStuff=i18n(markedStuff); を実行すると、"foobar" の翻訳結果が得られます。これは I18N_NOOP なしではうまくいきません。 そのため、普通は i18n を使ってください。しかし、絶対に翻訳をさせずに後で翻訳したい場合や、KInstance が存在する前に翻訳したいものを持っておきたい場合は、I18N_NOOP() を使って下さい。

"virtual tables error" というエラーが出ます。

このエラーは、.moc ファイルがソースファイルと同期していない場合や、リンクされていない場合に多く起こります。正しく moc を使っているかどうか確かめて下さい。'which moc' で分ります。また、moc ファイルを再生成して下さい。 (make force-reedit; make clean; make)

I have added Q_OBJECT to myClassHeader.h but no moc files is generated?

You need am_edit to reparse your Makefile.am to generate the correct Makefile. If it's the first Q_OBJECT you're using in this directory, you'll need to re-run Makefile.cvs or create_makefile from kdesdk/scripts. Otherwise, you can simply run "make force-reedit".

To go quicker, I have coded my whole class in a cpp file, how do I get the moc files generated?

Hmm, don't do that, if some of the classes use the Q_OBJECT macro. Maybe METASOURCES=file.cpp might work for moc files though.

I have developed a kpart (or a plugin). I don't want to install it yet because it is not finished but I need that KDE finds it when I request it using KTrader or KLibLoader. How do I do that?

KDE searches its libraries in $KDEDIR/lib and in the lib directory of all the components of $KDEDIRS (note the additional 'S', this different from $KDEDIR). So, while you are still developing your library and don't want to install it, you can use this trick:

cd to your development directory, the one where your library is built.
Set up KDEDIRS so that it include your development directory: export KDEDIRS=`pwd`:$KDEDIR
Create a pseudo lib directory where KDE should find your component: ln -s .libs lib (all the objects and libraries are built in the .libs directory).
Run kbuildsycoca to inform KDE that it KDEDIRS has changed.

Now, KDE should find your library when using KTrader or KLibLoader.

How can I install additional KDE stuff when I am not root?

If want to install your application privately, configure it with another prefix: for $HOME/kdeprefix, use configure --prefix=$HOME/kdeprefix. Then let KDE know about this prefix: set KDEDIRS to $HOME/kdeprefix:$KDEDIR. To make KDE aware of new prefixes, one can also edit /etc/kderc and add

[Directories]
prefixes=/the/new/prefix

but this doesn't answer this specific question ;-) Make sure to run "kbuildsycoca" after setting the new KDEDIRS.

My kpart lib is not listed when I request it with KTrader

The mimetype database must be rebuilt when you install new services (such as applications or parts). In theory this happens by itself (kded is watching those directories), but in doubt, run "kbuildsycoca". The best way to debug trader-related problems is to use ktradertest: cd kdelibs/kio/tests; make ktradertest, then run ./ktradertest to see how to use it.

I changed something in kdelibs, installed the new lib, but new KDE apps don't seem to use it?

The solution is simple: start new apps from a command line, then they will use the new lib.

The reason is that applications started by other KDE applications (kicker, minicli, konqueror, etc.) are started via kdeinit, which loads the libs when KDE starts. So the "old" version of the libs keep being used. But if you want kdeinit to start using the new libs, simply restart it. This is done by typing kdeinit in a terminal.

This is necessary if you can't start things from the command line - e.g. for a kioslave. If you change something in kio, you need to restart kdeinit and kill the running kioslave, so that a new one is started.

I'm developing both a KPart and a standalone application, how do I avoid duplicated code?

Apps are often tempted to link to their part because they of course have much functionality in common. However this is wrong for the reasons below.

A lib is something you link to, a module is something you dlopen. You can't dlopen a lib ; you can't link to a module.

A lib has a version number and is installed in $libdir (e.g. $KDEDIR/lib) a module doesn't have a version number (in its name), it's more like a binary (we don't have konqueror-1.14.23 either :), and is installed into kde_moduledir (e.g. $KDEDIR/lib/kde3) (which means it's not in the search path for ld.so, so this breaks on systems without -rpath).

If you didn't understand the above, don't worry. The point is: you should NOT make your application link to your (or any other) KPart, nor any other kind of dlopened module.

The solutions:

Let the app dlopen the part. This is what KOffice does. However this limits the app to the very limited ReadOnlyPart/ReadWritePart API. Keep in mind that you can't call a non-virtual method whose implementation you don't link to. The solution is to define a ReadWritePart-derived class (like we have in koffice: KoDocument), with new virtual methods. Either this derived class has code (and you need a lib shared by the app and the part, see point 2 below), or an abstract interface (header file only) is enough. You can also use known interfaces to child objects of the part instead of changing the base class of the part itself - this is the solution used by e.g. KParts::BrowserExtension.

Define a common library with the common classes and let both the part and the app use it. That library can be noinst_ or lib_, both work. In the first case the compiled object code is duplicated, in the second case a real versioned lib will be installed. The idea here is that the part itself is not available to the app, but instead the part is a very thin wrapper around the same classes as the app uses. Only KParts-specific stuff remains in the part.

What is the best way to launch another app?

In KDE there are several ways to start other programs from within your application. Here is a short summary of your options with reasons why you should or should not use them.

fork + exec

You never want to use this unless you have a very good reason why it is impossible to use KProcess.

KProcess

You want to use this if you need to start a new process which needs to be a child of your process, e.g. because you want to catch stdout/stderr or need to send it data via stdin. You should never use this to start other KDE applications unless your application is called kgdb :-)

startServiceByDesktopPath

Preferred way to launch desktop (KDE/Gnome/X) applications or KDE services. The application/service must have a .desktop file. It will make use of KDEinit for increased startup performance and lower memory usage. These benefits only apply to applications available as KDEinit loadable module (KLM)

KRun

Generic way to open documents/applications/shell commands. Uses startServiceBy.... where applicable. Offers the additional benefit of startup-notification.
KRun can start any application, from the binary or the desktop file, it will determine the mimetype of a file before running the preferred handler for it, and it can also start shell commands. This makes KRun the recommended way to run another program in KDE.

KToolInvocation::invokeBrowser

KToolInvocation::invokeBrowser launches a web browser. The difference with using the more generic KRun on the webpage URL is that KRun has to determine the mimetype of the URL first (which, for HTTP, involves starting a download to read the headers), so if you know that the URL is an HTML webpage, use invokeBrowser, it will be faster.

More details: the problem with KRun for webpages is that it delays the appearance of the browser window, and if the user's preferred browser is a non-kde application like firefox then it has to start a second download while konqueror which can reuse the kioslave started by KRun. On the other hand if the URL might be an image or anything else than html, then KRun is the right solution, so that the right application is started.

How do I create and submit a patch to KDE?

You have spotted a bug and you want to write the code to fix it. Or you want to code a specific feature. Sending a patch is very appreciated by developers. A tutorial is available but here is a description of how you should proceed:

  • Get the latest KDE using SVN to check that the code you want to write has not been added yet.
  • Check the bug database to see if your bug is not worked on.
  • Get in contact with the author. His/her name is in the about box or in the source header. If the project has a mailing-list, browse the archives to see if your bug/feature has not been the subject of any discussion. If you can't find any mailing lists or author, simply write to kde-devel.
  • Post a message explaining your intentions. It is important to inform the author(s) about what you are planning because somebody might already be working on your feature, or a better design could be proposed by the author, or he could give you some good advice.
  • Next step is to code your feature. It is usually a good idea to keep an original at hand and to work on a copy. This allow to check the behaviour of both versions of the code. Respect the author's indentation and naming scheme, code carefully, think about side-effects and test everything many times.
  • Using the latest KDE code, make a diff using either svn diff or a diff -uNp original-dir new-dir. Don't send reversed patch. The first argument of diff should be the old directory and the second the new directory.
  • Send a mail to the author/mailing-list with your patch as attachment (don't forget to attach it :-) ).
  • People usually have some remarks on your work and you must work further on your patch to improve it. It is common to see three or four submission before acceptation.

Ok, you have done it, your code has been included in KDE. You are now fully part of the KDE project. Thanx a lot.

How do I make my application Xinerama and multi-head safe?

Never make assumptions about the geometry of the "desktop" or the arrangement of the screens. Make use of the following functions from kglobalsettings.h:

 static QRect KGlobalSettings::splashScreenDesktopGeometry(); 
 static QRect KGlobalSettings::desktopGeometry(const QPoint& point); 
 static QRect KGlobalSettings::desktopGeometry(QWidget *w);

Use splashScreenDesktopGeometry() to determine the geometry of the desktop when you want to display an application splash screen. Use desktopGeometry() to determine the geometry of the desktop with respect to a given point on the desktop, or with respect to a given widget. Do not use the Qt class QDesktopWidget to determine these values yourself. The KDE functions take the user's settings into account, something the Qt functions cannot do.

It is ideal to try to avoid using the desktop geometry altogether. Your application will be much more standards compliant if you let the window manager place your windows for you. When this is not possible, you have the aforementioned functions available. Please beware that the geometry that is returned from these functions may not start at (0,0)! Do your math correctly!

One other caution: Both KWin and the NETWM specification have severe difficulties handling struts with Xinerama or "merged" displays. This can result in dead areas on the screen, for instance if kicker does not span a whole edge. There is not much that can be done about this, and you should try to avoid hacks to circumvent this at this time. We hope to find a proper solution for this soon.

I get an error about KDE not finding UIC plugins, but I know they're installed. What's wrong?

This is almost certainly an installation problem, not a KDE code problem. A number of problems can lead to this, but most likely you have more than one version of Qt laying around and the configure script is calling a different one than KDE is using.

Another thing that may help is to rebuild and reinstall your kdewidgets.so file, which is located in the kdelibs/kdewidgets directory. Note that if you *do* have multiple versions of Qt, this may compile against the wrong one.

This problem creeps up on various mailing lists occasionally, so looking at the archives on lists.kde.org may be helpful.

I put some functions in anonymous namespace and someone reverted it and made those functions static, why?

Symbols defined in a C++ anonymous namespace do NOT have internal linkage. Anonymous namespaces only give an unique name for that translation unit and that is it; they don't change the linkage of the symbol at all.

Linkage isn't changed on those because the second phase of two-phase name lookup ignores functions with internal linkages. Also, entities with internal linkage cannot be used as template arguments.

Can I delete a NULL pointer?

Yes. Calling delete on a null pointer is a noop in C++. Having "if (ptr) delete ptr;" is redundant. Doing ptr = 0; after a delete is a good idea, especially if the delete can be called on it from a different code path.

My locally installed application doesn't run, but KDEDIRS is set correctly, what's going on?

If you're running a 64 bits system, your libraries might have been compiled with the -DLIB_SUFFIX=64 option given to cmake. If your application wasn't compiled with that option, it'll get its modules installed into $prefix/lib/kde4, not $prefix/lib64/kde4 -- and then it will not be found. Easy solutions: a symlink to lib64 or compile your code with -DLIB_SUFFIX=64, too.