Windows/Porting Guidelines

From KDE Community Wiki
Revision as of 18:56, 11 January 2008 by Jstaniek (talk | contribs) (New page: This document contains rules useful when you're porting selected KDE library to win32. Most of these rules are also valid for porting external libraries code, like application's libraries...)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

This document contains rules useful when you're porting selected KDE library to win32. Most of these rules are also valid for porting external libraries code, like application's libraries and even application's standalone code.

!!1. Before you start

  • Make sure (ask KDElibs/win32 maintainer) that the library you selected for porting is not ported, but just not commited yet.
  • You can ask maintainer for proposals, what can be useful for porting.
  • You will need KDE cvs account for your work.
  • Download most current (HEAD) of the KDE libraries.

!!2. Absolute dirs checking Look for '/' and "/" and change every single code like:

~pp~

 if (path[0]=='/')

~/pp~ or:

~pp~

 if (path.startsWith('/'))

~/pp~ with:

~pp~

 if (!QDir::isRelativePath(path))

~/pp~ (or "QDir::isRelativePath(path)" if there was used path[[0]!='/')

!!3. Ifdefs

3.1. __C++ code.__

Macros for C++ code are defined in qglobal.h file. If you've got included at least one Qt header, you probably have qglobal.h included already, otherwise, include it explicity.

Use ~pp~

 #ifdef Q_WS_X11
 ....
 #endif

~/pp~ for any C++ code that looks like X11-only.

Use ~pp~

 #ifdef Q_OS_UNIX
 ....
 #endif

~/pp~ for any C++ code that looks like UNIX-only, for example uses UNIX-specific OS features.

Use ~pp~

 #ifdef Q_WS_WIN
 ....
 #endif

~/pp~ for any C++ code that is MSWindows-only.

3.2. __C code.__ Note that qglobal.h is C++-only, so instead use ~pp~

 #ifdef _WINDOWS
 ....
 #endif

~/pp~

for any C code that is MSWindows-only (regardless to compiler type). In fact, you could use built-in _WIN32 but it's not defined on incoming 64bit MS Windows platform (_WIN64 is used there). So, there's a global rule for kdelibs/win32 defined globally in your build system (you don't need to include any file for this).

3.3. Rare cases: How to check in Windows-only code which compiler is used?

__MS Visual C++ - Qt-independent code (especially, C code)__ ~pp~

 #ifdef _MSC_VER
 ....//msvc code
 #endif

~/pp~

__MS Visual C++ - Qt code__ ~pp~

 #ifdef Q_CC_MSVC
 ....//msvc code
 #endif

~/pp~

__Borland C++ - Qt-independent code (especially, C code)__ ~pp~

 #ifdef __BORLANDC__
 ....//borland code
 #endif

~/pp~

__Borland C++ - Qt code__ ~pp~

 #ifdef Q_CC_BOR
 ....//borland code
 #endif

~/pp~

3.4. General notes. In many places using #ifdef Q_OS_UNIX / #else / #endif is more readable than separate #ifdefs.

3.5. Related links

!!4. Header files 4.1. __Common header file__. Unless there is are any header file from kdelibs included in your header file, you need to add: ~pp~

#include <kdelibs_export.h>

~/pp~ at the beginning of your header file to have some necessary system-independent macros defined.

4.2. __Export macros__. For win32 world, symbols are "hidden by default" (not visible by default as e.g. on unix). This has already been [1] on the kde mailing list.

For every library's code (not for standalone code), you need to make symbols exported for win32. Do this by adding ***_EXPORT macro (win32 export macro) after "class" keyword within any public class (and structure) declaration. You may also decide to put this macro even for non-public class, if you think that the class could be used somewhere outside your library.

Example:

~pp~ class KDEFOO_EXPORT FooClass { ... }; ~/pp~

__Note__: For kdelibs, ***_EXPORT macros for are defined in kdelibs_export_win.h file (in kdelibs/win/ directory). You can study this file to see how the macros are defined. This file is simply included by kdelibs_export.h, for win32 target.

__Note2__: Recently we're prepared to gcc's export capatibilities, probably in versions newer than 3.4, just like these in win32's msvc compiler. In kdemacros.h file (included by kdelibs_export.h) there are defines prepared for this functionality:

~pp~

  1. define KDE_NO_EXPORT __attribute__ ((visibility("hidden")))
  2. define KDE_EXPORT __attribute__ ((visibility("default")))

~/pp~

For gcc <= 3.4, KDE_EXPORT and KDE_NO_EXPORT macros are just empty. Note that we're not using KDE_NO_EXPORT for non-public symbols: in the future probably it will be better to use command line switch to turn hidding by default (as win32 compiler has).

__Note3__: *_EXPORT macros depend on MAKE_{LIBRARYNAME}_LIB macro. In KDE4 buildsystem (cmake) the latter is defined automatically by reusing {LIBRARYNAME}, for example MAKE_KATEINTERFACES_LIB is constructed when KATEINTERFACES library is compiled. The logic behind it is implemented in kdelibs/cmake/modules/KDE4Macros.cmake: ~pp~

  if (WIN32)
     # for shared libraries/plugins a -DMAKE_target_LIB is required
     string(TOUPPER ${_target_NAME} _symbol)
     set(_symbol "MAKE_${_symbol}_LIB")
     set_target_properties(${_target_NAME} PROPERTIES DEFINE_SYMBOL ${_symbol})
  endif (WIN32) 

~/pp~

4.3. __Exporting global functions__. Also add the same ***_EXPORT at the beginning of public functions' declaration and definition (just before function's type). This also includes functions defined within a namespace.

Example: ~pp~ namespace Foo {

KDEFOO_EXPORT int publicFunction();

} ~/pp~

4.4. __What not to export?__

  • methods inside classes (no matter static or not)
  • inline functions
  • template classes, e.g.:

~pp~ template <class T> class KGenericFactoryBase ~/pp~

4.5. __Visibility__ There are classes or functions that are made "internal", by design. If you really decided anybody could neven need to link against these classes/functions, you don't need to add **_EXPORT macro for them.

4.6. __Deprecated classes__ Before porting KDElibs to win32, I realized that deprecated classes already use KDE_DEPRECATED macro. We're unable to add another macro like this:

~pp~ class KDEFOO_EXPORT KDE_DEPRECATED FooClass { //< - bad for moc! ... }; ~/pp~

..because moc'ing will fail for sure. We've defined special macros like that in kdelibs_export.h file (fell free to add your own if needed):

~pp~

  1. ifndef KABC_EXPORT_DEPRECATED
  2. define KABC_EXPORT_DEPRECATED KDE_DEPRECATED KABC_EXPORT
  3. endif

~/pp~

So, we have following example of deprecated class:

~pp~ class KABC_EXPORT_DEPRECATED FooClass { //<- ok for moc ... }; ~/pp~

.. which is ok for __moc__. Note that sometimes KDE_DEPRECATED is also used at the end of functions. You don't need to change it for win32 in any way.

!!5. Loadable KDE modules/plugins

5.1. __K_EXPORT_COMPONENT_FACTORY macro__

Use K_EXPORT_COMPONENT_FACTORY( libname, factory ), defined in klibloader.h, instead of hardcoding: ~pp~

extern "C" {void *init_libname() { return new factory; } };

~/pp~ ...because the former way is more portable (contains proper export macro, which ensures visiblility of "init_libname" symbol).

Examples: ~pp~ K_EXPORT_COMPONENT_FACTORY( ktexteditor_insertfile,

   GenericFactory<InsertFilePlugin>( "ktexteditor_insertfile" ) ) 

K_EXPORT_COMPONENT_FACTORY( libkatepart, KateFactoryPublic ) ~/pp~

5.2. __More complex case__

Sometimes you need to declare a factory which defined as a template with multiple arguments, eg.:

~pp~ extern "C" {

 void* init_resourcecalendarexchange()
 {
   return new KRES::PluginFactory<ResourceExchange,ResourceExchangeConfig>();
 }

} ~/pp~

... but compiler complains about too many arguments passed to K_EXPORT_COMPONENT_FACTORY. To avoid this, you can use __typedef__:

~pp~ typedef KRES::PluginFactory<ResourceExchange,ResourceExchangeConfig> MyFactory; K_EXPORT_COMPONENT_FACTORY(resourcecalendarexchange, MyFactory) ~/pp~

The same trick can be used if the constructor of the factory takes multiple arguments.