Skip to content

Porting Guide

Günter Obiltschnig edited this page Jul 10, 2016 · 4 revisions

Introduction

The POCO C++ Libraries have been designed with portability in mind from the beginning -- as the original name C++ Portable Components implies. The libraries have been ported to a number of different operating systems, including all major Unix platforms, Windows, OpenVMS, QNX and VxWorks, although some ports are no longer regularly maintained.

Porting the POCO C++ Libraries to a new platform is quite straightforward, provided that the platform provides certain features:

  • A C++ compiler conforming to C++03. As or release 1.7.4, POCO does not use C++11 features, but this will surely change, so in the future a conforming C++11/14 compiler will be required.
  • Support for threads and basic synchronization mechanisms (mutex, as well as Windows-style event or POSIX-style condition variable, and optional semaphore).
  • A filesystem API.
  • A Berkeley or POSIX Sockets API for the Net library.

Generally, the porting effort will be a lot easier if the target platform supports the POSIX APIs. In this case, only adaptions to the existing POSIX abstraction layer may be necessary. A Berkeley or POSIX Sockets API is definite a requirement, as the entire Net library is built on the concept of sockets.

Another issue to consider is the build system for the target. The porting effort will be easiest if the existing GNU Make-based or CMake based build systems can be used. If neithe GNU Make nor CMake can be used due to a platform specific build system, projects and scripts for that build system must be created. Examples for such target platforms are Windows (here, Visual Studio project files are used, although CMake support is also available), the VxWorks port and the no-longer maintained OpenVMS port.

When porting the POCO C++ Libraries to a new platform, only a limited number of source files need to be changed. Most of the POCO source code is cross-platform, building on the platform abstraction layer implemented in the Foundation library.

Affected Libraries

The following libraries need to be modified in order to support a new platform:

  • Foundation
  • XML
  • Util
  • Net

The necessary modifications are discussed in the following.

Foundation

The Foundation library contains the main platform abstraction layer, which needs to be modified in order to support a new platform. Specifically, the following classes are affected:

  • Poco::Debugger
  • Poco::DirectoryIterator
  • Poco::Environment
  • Poco::Event
  • Poco::FPEnvironment
  • Poco::FileStream, Poco::FileInputStream, Poco::FileOutputStream
  • Poco::File
  • Poco::LocalDateTime
  • Poco::LogFile
  • Poco::Mutex
  • Poco::NamedEvent
  • Poco::NamedMutex
  • Poco::Path
  • Poco::Pipe
  • Poco::Process
  • Poco::RWLock
  • Poco::Semaphore
  • Poco::SharedLibrary
  • Poco::SharedMemory
  • Poco::Thread
  • Poco::Timestamp
  • Poco::Timezone

Furthermore, the new platform must be declared in the Foundation/include/Poco/Platform.h header file. A new platform identifier (POCO_OS_) must be defined and assigned an unused number. Furthermore, the new platform must be detected in the Platform.h header, either using platform-specific identification macros provided through the toolchain (such as _WIN32 or linux), or a custom-defined macro defined during the build process (like POCO_VXWORKS).

If a new compiler is used, also the Foundation/include/Poco/Types.h file must be extended to include definitions of the fixed-sized integer types (Poco::UInt8, Poco::UInt16, etc.) specific to the compiler or toolchain.

Most of these classes have the platform-specific code factored out into separate source files for each platform. The typical implementation pattern used is such that a class (like Poco::Thread) privately inherits from a platform-specific implementation class (Poco::ThreadImpl), which is declared and implemented in its own header and source file. For example, for the Poco::Thread class, the common part is implemented directly in the Poco::Thread class, inheriting privately from, and using public or protected methods provided by the Poco::ThreadImpl class. Different implementations of the Poco::ThreadImpl class exist for different platforms, but all implementations of Poco::ThreadImpl implement the same interface to Poco::Thread. The interface of Poco::ThreadImpl is not formally defined, instead, by convention, every platform must implement the same API. Virtual methods are not used for performance reasons. There's one implementation of Poco::ThreadImpl for Windows, using the WIN32 API, one for Windows Compact Embedded/CE, one using the POSIX Threads API and another one using the VxWorks taskLib API. The header file Foundation/include/Poco/Thread.h declares the Poco::Thread class to be a private subclass of Poco::ThreadImpl. The Thread.h file will include the correct header file for each platform, using following code fragment:

#if defined(POCO_OS_FAMILY_WINDOWS)
#if defined(_WIN32_WCE)
#include "Poco/Thread_WINCE.h"
#else
#include "Poco/Thread_WIN32.h"
#endif
#elif defined(POCO_VXWORKS)
#include "Poco/Thread_VX.h"
#else
#include "Poco/Thread_POSIX.h"
#endif

Each of the platform-specific headers contains a declaration of the ThreadImpl class specific for the respective platform. Similarly, the Foundation/src/Thread.cpp source file will include the correct implementation file of the ThreadImpl class, using a similar code fragment:

#if defined(POCO_OS_FAMILY_WINDOWS)
#if defined(_WIN32_WCE)
#include "Thread_WINCE.cpp"
#else
#include "Thread_WIN32.cpp"
#endif
#elif defined(POCO_VXWORKS)
#include "Thread_VX.cpp"
#else
#include "Thread_POSIX.cpp"
#endif

For each new platform that requires a new implementation, a new header and implementation file following the used naming scheme has to be created, and the new header and implementation files have to be included by Thread.h and Thread.cpp.

The interface of Poco::ThreadImpl looks like this:

class Foundation_API ThreadImpl
{
public: 
    typedef <ThreadHandleType> TIDImpl;
    typedef void (*Callable)(void*);

    enum Priority
    {
        PRIO_LOWEST_IMPL,
        PRIO_LOW_IMPL,
        PRIO_NORMAL_IMPL,
        PRIO_HIGH_IMPL,
        PRIO_HIGHEST_IMPL
    };
   
    ThreadImpl();
    ~ThreadImpl();

    TIDImpl tidImpl() const;
    void setPriorityImpl(int prio);
    int getPriorityImpl() const;
    void setOSPriorityImpl(int prio, int policy);
    int getOSPriorityImpl() const;
    static int getMinOSPriorityImpl(int policy);
    static int getMaxOSPriorityImpl(int policy);
    void setStackSizeImpl(int size);
    int getStackSizeImpl() const;
    void startImpl(SharedPtr<Runnable> pTarget);
    void joinImpl();
    bool joinImpl(long milliseconds);
    bool isRunningImpl() const;
    static void sleepImpl(long milliseconds);
    static void yieldImpl();
    static ThreadImpl* currentImpl();
    static TIDImpl currentTidImpl();
    
private:
    // ...
};

There are a few classes that don't follow this scheme of separating the common and the platform-specific code. An example is the Poco::Timestamp class. This is done for classes where the platform-specific code is very small.

XML

For the most part, the XML library does not need porting. However, recent releases of the underlying expat parser have some platform-specific code for obtaining the current time and process ID. This may need porting. The respective code is in the file XML/src/xmlparse.cpp (functions gather_time_entropy() and generate_hash_secret_salt()).

Util

In the Util library, the Poco::Application and Poco::ServerApplication implementations may require changes for a new platform. If the target platform does not support separate processes, the Poco::SystemConfiguration class should disable the "system.pid" property, like it's done for VxWorks. If the target platform does not support the main() function as entry point to the application, the POCO_APP_MAIN and POCO_SERVER_MAIN macros may need to be adapted, like it's done for VxWorks.

Net

In the Net library, the header file Net/include/Poco/Net/SocketDefs.h should be extended to include the necessary headers for the target platform. Furthermore, the Poco::Net::SocketImpl, Poco::Net::NetworkInterface, Poco::Net::SocketAddress, Poco::Net::HostEntry, Poco::Net::DNS and Poco::Net::IPAddressImpl classes may need some changes.