Helping Develop MoSync

We love open source software and by opening up the Mosync SDK under the GPL license, we aim to give a large group of developers the opportunity to go mobile in a short time on both the Windows and OS X environments. We look forward to working together with you to create new, great applications in mobile, as well as receiving your contributions and suggestions on how to make Mosync even better!

Participation from our community is very important in the success of the MoSync Open Source project. 
We invite you to participate on many levels. These activities require a certain level of technical skill. As a MoSync community member, you as a user can contribute in many other ways; i.e. by participating in the forum or by blogging about MoSync on the Internet.

Share your MoSync application

We'd really like to see what people have done with the MoSync SDK, and cordially welcome everyone to share their applications. You can find some of our own application on the Example Applications page, and some of our customer's applications on the Who's Using MoSync page.

Contribute code

Before you can contribute code to the MoSync SDK, we need you to do a couple of things:

Send your core patches for review to tony@mosync.com.


Raise an issue

How to Report an Issue

Report issues at our Jira Issue Tracker.

What follows are some additional tips on ways to make your bug report better so that someone will be able to help you.

The basics: what you did, what you wanted to happen, and what actually happened.

There are the three basic elements of a bug report, this may be only to basic but bear with us. You need to tell us exactly what you did:
"I instructed the program to draw a polygon on the canvas",
what you expected to have happen:
"I expected a red polygon to appear on the screen", and lastly what actually happened
"I got a blue circle, flickering on screen".

Always search the bug database first.

The odds are good that if you've found a problem, someone else has found it, too. If you spend a few minutes of your time making sure that you're not filing a duplicate bug, that's a few more minutes someone can spend helping to fix that bug rather than sorting out duplicate bug reports.

If you don't understand an error message, ask for help.

Don't report an error message you don't understand as a bug. There are a lot of places you can ask for help in understanding what is going on before you can claim that an error message you do not understand is a bug.

Be brief, but don't leave any important details out

This is a fine line to walk. But there are some general guidelines:

Use English

Yes, the MoSync developer community is global and include a great many people who can speak a great many languages. But if you were to report a bug in a language other than English, many (if not most) of the people who would otherwise help you won't be able to.

Don't report bugs about old versions

Every time a new version of a MoSync product is released, many bugs are fixed. If you're using a version of a product that is more than two revisions older than the latest version, you should upgrade to the latest version to make sure the bug you are experiencing still exists. (And it's not a bad idea to try upgrading even if your version is only a version behind the most current one.)

Only report one problem in each bug report

If you have encountered two bugs that don't appear to be related, create a new bug report for each one. This makes it easier for different people to help with the different bugs.

Suggest a feature

While commercial customers and partners can influence the direction and feature set of the MoSync Mobile SDK, you can too. Submit your feature request in the issue tracker.

Write a usability report

Usability reports are feedback from the community about usage of (new) features in the real world. A usability report is a short account of the user's first impact on a newly tried feature, recording his/her expectations and the level of satisfaction achieved.

An usability report should have the following components.

These reports are like any other contribution very important to us.

Send your usability reports to miles.midgley@mosync.com.

The Issue Tracker

The MoSync Issue Tracker is based on Jira and can be found here: jira.mosync.com. Jira allow users to see more than just one project at a time and ongoing work for up-and-coming releases and is integral in our development.

Note: Our oldIssue Tracker is still visible for archive purposes. We have imported all the issues from the old Google issue tracker. We are manually adding attachments, an ongoing task. If you were following an issue on the Goggle issue tracker you will have to resubscribe to that issue in Jira.

How to Add an Issue

Note: To post or follow issues you will need to create a user ID on Jira.

Follow the instructions and log in.

Next you will be presented with a dashboard. This gives an overview of the MoSync project.

At the top right there is a button to create an issue. This screen allows you to define if this issue is a Bug or New Feature. These are currently the only two issue types open to users.

The following screen shows what we would like you to fill in as a minimum.

Issue Resolution

Issues are usually resolved in 7 stages:

OpenA newly reported issue, no action taken yet
AcceptedA developer has accepted the issue and will soon start working on it
In ProgressA developer is working on the issue
ResolvedThe developer feels that the issue has been dealt with.
Code ReviewThe code is read is ready for code review.
Waiting QAThe code has been merged and QA can build and verify the issue is resolved. In most cases the fix will be in the next nightly build.
VerifiedThe QA department has checked the solution and has agreed that it is fixed

Reporting Issues

Some things to keep in mind before reporting an issue:

  • Please search the Issue Tracker to see if this issue has already been posted. It helps reduce our workload if there are no duplicate issues!
  • Please provide test cases, or sample code, or screen snapshots as attachments to your issue, if they are relevant.
  • If you know the exact area of the product where a bug is, use the issue labels to select the appropriate part of the product. The more accurately you label your issue, the faster we can process it.
  • Sometimes our developers and testers might want more information, the easiest way to communicate is via comments on the issue.
  • The Issue Tracker notifies you of comments posted and status updates to your issues. (You can turn this feature off — but if you do, remember to check back periodically to see what is happening with your issues.
  • If you find other issues that are of interest to you and you would like to keep track of them, simply click on the watch next to the issue. You will be notified by email about all changes to your starred issues.

Feature Requests

If you have suggestions for improving MoSync, enter it as an issue into the Jira issue tracker. Provide as much information as you like. We love feedback, and we are more than happy to let our user base help us determine the direction of development.

If you are missing a feature in MoSync, why not write it up? The development team keeps a close watch on the Issue Tracker so your queries and posts will usually be attended to within a few days. We are committed to providing the best possible user experience. Help us make MoSync the most powerful mobile development solution on the planet!

Building the MoSync SDK for Windows

These instructions describe how to build a Windows installation package for the MoSync SDK. The completed installation package is an .exe file, just like our featured releases and our nightly builds.

To build the full installation package, you will need a Windows machine, a Mac OS X machine, and a Linux machine. If you omit the iPhone and Moblin runtimes, you can build a partial package on just the Windows machine.

(Instructions for building the MoSync SDK from source on OS X are also available.)

Hardware and OS Requirements

To build the MoSync Eclipse IDE, the MoSync libraries, and the MoSync tools, you will need a computer running Windows (Windows XP, Windows Vista, or Windows 7) and capable of running Visual Studio C++ 2005.

To build the MoSync runtimes you will need:

  • For the Java ME, Android, Symbian, and Windows Mobile runtimes, your Windows computer.
  • For the iPhone runtime, a Mac running Snow Leopard (OS X v. 10.6).
  • For the Moblin runtime, a Linux computer running the i386 version of Ubuntu.

If you don’t need the iPhone and Moblin runtimes, everything can be built on the Windows machine.

Getting the MoSync Source Code

1. Download the source tarball (.tar.bz2) of our current feature release from our website or from our open-source project repository:

Alternatively, get the source tarball for our latest nightly build from our website:

or through TortoiseGit:

git clone https://github.com/MoSync/MoSync.git c:\mb\MoSync-trunk
git clone https://github.com/MoSync/Eclipse.git c:\mb\Eclipse

2. Unpack the source tarball into (or, if you have installed TortoiseGit, check it out to):

C:\mb

Getting Eclipse

3. Download target-platform.zip which contains everything needed to build the Eclipse-based IDE. Put the zip-file in:

C:\mb\eclipse\com.mobilesorcery.sdk.product\build

Installing the Dependencies

Important! Make sure you install and configure the dependencies in the order listed below. If you do not, terrible things may happen!

Visual Studio C++ 2005

4. Download and install Microsoft® Visual Studio® 2005 and apply Service Pack 1. Make sure that you install the runtime MT (Multi Threaded) DLL.

5. Add the following paths to Visual Studio:

  • To the end of the list at Tools > Options > Projects and Solutions > VC ++ Directories > Include Files add:

\mb\mosync-trunk\tools\ReleasePackageBuild\build_package_tools\include
\mb\mosync-trunk\libs
\mb\mosync-trunk\libs\MAStd

  • To Tools > Options > Projects and Solutions > VC ++ Directories > Library Files add:

\mb\mosync-trunk\tools\ReleasePackageBuild\build_package_tools\lib

6. Find the file:

C:\mb\mosync-trunk\tools\ReleasePackageBuild\build_package_tools\include\msvc\stdint.h

Copy it to the directory:

C:\Program Files\Microsoft Visual Studio 8\VC\include\

Visual Studio SDKs

7. Download and install the following Visual Studio SDKs:

8. Find the files:

C:\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Smartphone SDK\Include\Armv4i\gdiplus*.h 

Copy them to:

 

C:\Program Files\Microsoft Visual Studio 8\SmartDevices\SDK\Smartphone2003\Include\

 

9. Download and install the Ruby 1.8 (or later).

10. Download Sqlite 3 for Ruby 1.8 and put it in your ruby\bin directory. (If you have installed a later version of Ruby you'll have to find another version of the Sqlite 3 dll.)

11. Install Sqlite 3 Ruby Gem by opening a command (cmd) window and entering:

gem install sqlite3-ruby

12. Accept the installation of dependencies. These are the ones you need:

  • hoe
  • rake-compiler
  • mocha
  • rake
  • rubyforge

Java SE Development Kit (JDK) 1.6

13. Download and install Java SE Development Kit (JDK) 1.6.

14. Make sure the JDK’s \bin directory has been added to Window’s list of path environment variables, otherwise add it.

SonyEricsson J2ME SDK

15. Download and install the latest version of the SonyEricsson SDK for the Java ME Platform.

16. Download and install the ProGuard 3.7 Java obfuscator.

17. Put  the file proguard.jar in the \OnDeviceDebug\bin directory of the J2ME SDK.

Symbian Series 60 SDK

18.  Download and install ActiverPerl 5.8 Community Edition .

19. Download and install S60 3rd Edition SDK for Symbian OS FP1.

20. Download and install the Extensions plug-in for S60 3rd Edition SDK for Symbian OS, for C++, MR.
 
21. Download and install S60 2nd Edition SDK for Symbian OS FP3. If the installer asks you which network adapter to use, pick any.
 
22. Download and install S60 5th Edition SDK for Symbian OS. Make sure you install it in the folder \Symbian\s60v5\, as that is the location that is assumed by our build scripts.
 
23. Download the Extensions Plug-in for S60 3rd Edition SDK for Symbian OS, for C++, supporting Feature Pack 1, v2.5. Install it in both 3rd and 5th edition SDKs.
 
24. Download and unzip symbian-94-fixes.zip. Install it over the s60v5 SDK.
 
25. Download and unzip symbian-81-extras.zip. Install it over the s60v2 SDK, located in the folder:

\Symbian\8.1a\S60_2nd_FP3\

26. For both 3rd and 5th edition SDKs, run CSL Toolchain (GCCE) Install, found on the Start menu, under:

\S60 Developer Tools\* Edition SDK\v1.0\Tools

27. For each Symbian SDK, make sure that the following folder exists:

\Epoc32\Data\z\resource\apps\

Sometimes, this folder is a file, or does not exist at all, and in both cases this would cause the build to fail.

 28. For both 3rd and 5th edition SDKs, find line 31 in the file \epoc32\tools\e32env.pm:

die "EPOCROOT environment variable must be capitalised\n" if (!$found);

29. Disable this line by adding a hash sign (#) in front of it.

GNU binutils

30. Download and install CoreUtils for Windows.

31. Download and install Grep for Windows.

32. Download and install Sed for Windows.

33. Make sure the \bin directory of GNU binutils has been added to Window’s list of path environment variables, otherwise add it.

Building the SDK

34. If required, build the Moblin runtimes on Linux.

35. If required, build the iPhone runtime on Mac OS X.

(You do not need to build the Windows Mobile,  Java ME, Android, and Symbian runtimes, they are automatically built by the build script).

36. Locate the file run.bat.example in \mb\mosync-trunk\trunk\tools\ReleasePackageBuild, copy it, and name the copy run.bat.

37. Replace the SDK path in run.bat with one appropriate for your system:

start /B /BELOWNORMAL build_package.bat c:\SonyEricsson\JavaME_SDK_CLDC\OnDeviceDebug\ 2>&1 | tee log.txt

38. Start run_commercial_recompiler.bat. It will set up an environment, then call your run.bat (found in the \mb\mosync-trunk\tools\ReleasePackageBuild folder). You can use one of the other run_*.bat files to build the package in different ways.

If all goes well, an installer package should appear in \mb\MoSyncReleasePackage\.
It will be called something like MoSyncSetup_XXX.exe.

39. Done.

 

Building Runtimes for the MoSync SDK on OS X

If you want to create the Windows Mobile,  Java ME, Android, and Symbian runtimes to use with the OS X version of the MoSync SDK (see building the MoSync SDK from source on OS X), here’s how:

1. Follow the instructions above for Getting the MoSync Source Code and Installing the Dependencies.  (You do not need to get Eclipse or build the SDK.)

2. Run the following command from the command line to set the target MoSync Directory:

set MOSYNCDIR=\mb\MoSyncReleasePackage

3. Go to  the folder

\mb\mosync-trunk

and run the following command:

ruby workfile.rb base

4. Go to

\mb\mosync-trunk\tools\ConcurrentBuild

and run the following command:

ruby ConcurrentBuild.rb \mb\MoSyncReleasePackage \mb\MoSync-trunk android javame wm s60

The script will build your runtimes and put them in the \profiles folder under \mb\MoSyncReleasePackage .

5. Copy the runtimes to your mac installation folder and you can start using them on your Mac OS X version.

6. Done.

Building the MoSync SDK for OS X

These instructions describe how to build an OS X installation package for the MoSync SDK. The completed installation package is an .dmg file, just like our featured releases and our nightly builds.

To build a full installation package that includes all the MoSync runtimes, you will need a Windows, a Mac OS X, and a Linux machine. If you want an installation package that just has the iPhone runtime, you can build the whole thing on a single OS X machine.

To be able to follow these instructions you will need to be registered as an Apple Developer. Instructions for building the MoSync SDK for Windows are also available.

Hardware Requirements

To build the MoSync Eclipse IDE, the MoSync libraries, and the MoSync tools, you will need a Mac OS X Snow Leopard (OS X v. 10.6) computer capable of running Xcode.

To build the MoSync runtimes you will need:

  • For the Java ME, Android, Symbian, and Windows Mobile runtimes, Windows (Windows XP, Windows Vista or Windows 7) computer capable of running Visual Studio C++ 2005.
  • For the iPhone runtime, you can use your Mac OS X computer.
  • For the Moblin runtimes, you need a Linux computer running the i386 version of Ubuntu.

If you only want the iPhone runtime, everything can be built on OS X.

Preparing the Mac

1. Download and install Xcode 3.2.5 toolset from the iPhone Dev Center, including the iPhone SDK.

2. Download and install the 32-bit version of Fink for Snow Leopard.

3. Download and install MacPorts.

4. Download and install IceBerg for Mac OS X.

5. From the Terminal, run the following commands:

sudo fink -b install sdl
sudo fink -b install sdl-image
sudo fink -b install sdl-ttf
sudo fink -b install sdl-sound
sudo port install freeimage +universal
sudo port install ImageMagick +universal
sudo port install doxygen

Getting the MoSync Source Code

6. Get the MoSync source code from github repository:

git clone https://github.com/MoSync/MoSync.git MoSync

Getting Eclipse

7. Clone the MoSync Eclipse Repository into the same path as MoSync:

git clone https://github.com/MoSync/Eclipse.git Eclipse

8. Download the zip-package here that contains everything needed to build the Eclipse-based IDE and put it in the folder:

/MoSync/tools/ReleasePackageBuild/

Making the MoSync Package

9. In your checked out version of the MoSync SDK trunk, go to the folder:

/MoSync/tools/ReleasePackageBuild/

then run:

./build_mac_package.sh

10. If everything goes as it should, the script will build a .dmg installation package in the folder called /results.

11. Install the .dmg installation package on an OS X machine.

12. If required, build the Moblin runtimes on Linux.

13. If required, build the Windows Mobile,  Java ME, Android, and Symbian runtimes on Windows (see Building the MoSync SDK on Windows).

14. Add the runtimes to the folder:

/Applications/MoSync/profiles

15. Done.

Building an iPhone Runtime for the MoSync SDK on Windows

If you want to create an iPhone runtime to use with the Windows version of the MoSync SDK (see building the MoSync SDK for Windows ), here’s how:

1. Follow the instructions above for Preparing the Mac and Getting the MoSync Source Code. (You do not need to get Eclipse or make the MoSync package.)

2. Give your user the correct permissions to the /MoSync folder by entering the following command at the Terminal (replace user with you actual user name):

sudo chown -R user  /Applications/MoSync

3. To build the MoSync base prerequisites, go to your cloned MoSync source directory and run the command:

ruby workfile.rb base

4. Now you are ready to build the iPhone runtime from source. In your checked out version of the MoSync SDK trunk do:

cd runtimes/cpp/platforms/iphone
cp Classes/impl/config_platform.h.example Classes/impl/config_platform.h
ruby buildLibraries.rb
cp -R template $MOSYNCDIR/profiles/runtimes/iphoneos/1/

5. Find the runtime in the folder:

/Applications/MoSync/profiles/runtimes/iphoneos/1/

6. Copy it to your MoSync installation directory on your Windows computer in the folder:

\MoSync\profiles\runtimes\iphoneos\1\

7. Done.

Building the Moblin Runtimes on Linux

These instructions describe how to build the MoSync runtimes for Moblin. The runtimes can then be included when you build the MoSync SDK for Windows or build the MoSync SDK for OS X.

To build the Moblin runtimes you will need a machine running Ubuntu (9.10).

1. First install the runtime dependencies in the Linux terminal:

sudo apt-get install gcc g++ ruby rake subversion rpm
sudo apt-get install libgtk2.0-dev libexpat1-dev
sudo apt-get install libbluetooth3-dev libsdl1.2-dev
sudo apt-get install libsdl-image1.2-dev libsdl-ttf2.0-dev
sudo apt-get install libfreeimage-dev libssl-dev

Important! Do not install libsdl-sound -- Moblin does not support this library.

2. Download the source tarball (.tar.bz2) of our current feature release from our website or from our open-source project repository:

Alternatively, get the source tarball for our latest nightly build from our website:

or through TortoiseGit:

git clone https://github.com/MoSync/MoSync.git MoSync
git clone https://github.com/MoSync/Eclipse.git Eclipse

Important! You must download the same version as you downloaded to build the MoSync SDK for Windows or OS X. If you do not, when you try to use the SDK you may get an “IDL Version Mismatch” error.

3. Run the Linux runtime builder script in the MoSync source directory::

/tools/RuntimeBuilder/linux/build-linux-runtime-package.sh

4. You will now have two files in the current directory:

runtime.ubuntu.r*.i386.dbg.tar.gz
runtime.ubuntu.r*.i386.rel.tar.gz

Rename them to:

runtime.dbg.tar.gz
runtime.rel.tar.gz

5. If you are building the MoSync SDK for Windows, move the files to the following folder on the Windows build machine,

c:\mb\MoSyncReleasePackage\profiles\runtimes\moblin\1\

You are then ready to run the SDK build script.

If you are building the MoSync SDK for OS X, copy the runtimes to the machine on which you have installed the MoSync SDK, in the directory:

/Applications/MoSync/profiles/runtimes/moblin/1/

6. Done.

Building the MoSync SDK from Source on Linux

This guide explains how to build the MoSync SDK from source on Linux. It shows you how to set up your build environment and how to build GCC, Pipe-Tool, and the MoRE Emulator.

Please remember that support for Linux is limited and the build system was made for Windows. At the moment, it is only possible to build the MoRE Emulator on Linux, and to run some example programs in the Emulator. It is not possible to build the entire MoSync package (with its IDE) on Linux.

The distributions that we ourselves run at MoSync AB are Ubuntu 8.10/9.04/9.10 and Xubuntu 9.10. This description may work with those distributions. If you're using any other distribution, you may need to adapt these instructions.

Prerequisites

There are a few prerequisites to building the MoSync SDK. In Ubuntu, they can be installed by:

sudo apt-get install gcc g++ bison flex ruby rake subversion rpm libgtk2.0-dev libexpat1-dev
sudo apt-get install libbluetooth3-dev libsdl1.2-dev libsdl-image1.2-dev libsdl-ttf2.0-dev
sudo apt-get install libfreeimage-dev gperf

Note that, since the MoSync SDK is continuously evolving, there may be additional dependencies.

Setting up your Build Environment

The first step is to set up a directory where the compiled binaries, libraries and SDK header files will reside. From now on we will refer to this directory as the installation directory. The installation directory, which resides wherever you want, should contain the following directory structure:

 /<installation-directory>
        /bin
        /include
        /lib
        /libexec/gcc/mapip/3.4.6

The /include and /lib directories will be created automatically during compilation, but the other directories should be created manually because we need to compile GCC before the MoSync SDK can be compiled.

Once you have created the directory structure, the environment variable MOSYNCDIR should point to the installation directory. If you use bash then this is accomplished by adding the following line to your .bashrc:

export MOSYNCDIR=<installation-directory>

or in csh by adding the following line to .cshrc:

setenv MOSYNCDIR  <installation-directory>

When the lines have been added to your .bashrc or .cshrc the shell must be restarted, you can accomplish this by closing the terminal window and opening it again.

Building GCC

MoSync uses its own GCC backend that generates source code for the MoSync virtual machine. In order to build the MoSync GCC we start by downloading the source code from Google Code, the source code can be placed wherever you want, in this example we are using a directory called gcc_trunk. To download the code run svn:

git clone git://github.com/MoSync/gcc.git gcc_trunk

Now go into gcc_trunk and build the compiler, the compilation will fail when trying to compile libgcc since we do not use the standard linker. But the compiler will already have been built and will be placed in gcc_trunk/build/gcc/gcc/.

We build the compiler by performing the following steps:

cd gcc_trunk
./configure-linux.sh
cd build/gcc
make

Remember that the compilation will fail when trying to build libgcc, on my Ubuntu machine the error output begins with:

libgcc2.s: Assembler messages:
libgcc2.s:1: Error: unknown pseudo-op: `.model'
libgcc2.s:2: Error: unknown pseudo-op: `.code'
...

In order for the build scripts to find MoSync GCC it has to be moved to the installation directory:

cp gcc/xgcc gcc/cpp $MOSYNCDIR/bin
cp gcc/cc1 gcc/cc1plus $MOSYNCDIR/libexec/gcc/mapip/3.4.6/

Building Pipe-Tool and the Emulator

The source code for the MoSync SDK also resides on Google Code and is downloaded by:

git clone git://github.com/MoSync/MoSync.git mosync_trunk

MoSync uses its own build system coined 'work'. The build system consists of a set of Ruby files that compiles the MoSync SDK. In each directory that contains source files there is a file called workfile.rb, which instructs the build system how compile the source files. To build the fundamental tools of the MoSync SDK, move to the root of mosync_trunk and invoke:

./workfile.rb CONFIG="debug"

The above command builds the tools and libraries in debug mode but you should also build everything in release mode:

./workfile.rb CONFIG=""

You will then have to copy the font used in the emulator to the bin directory, stand in the root of mosync_trunk and invoke:

cp tools/ReleasePackageBuild/build_package_tools/mosync_bin/unifont-5.1.20080907.ttf $MOSYNCDIR/bin/

When this script is finished make sure that $MOSYNCDIR/bin contains cc1cc1plusxgccpipe-tool and moemu. You may then try the MAUIex example by performing:

cd examples/MAUI/MAUIex/
./workfile.rb CONFIG=""
cd build/pipe_release/
$MOSYNCDIR/bin/moemu -program program -resource ../resources

Coding Conventions

These coding conventions are guidelines for developers creating MoSync code. These conventions are largely inspired by and derived from existing ones in well-known programming environments such as Java and SDL. As such, they shouldn't come across as exotic to any moderately experienced programmer.

Header Files 

The #define Guard

All header files should have #define guards to prevent multiple inclusion. The format of the symbol name should be <PROJECT>_<PATH>_<FILE>_H_.

Header File Dependencies

Don't use an #include when a forward declaration would suffice.

Inline Functions

Define functions inline only when they are small, say, 10 lines or less.

Function Parameter Ordering

When defining a function, parameter order is: inputs, then outputs.

Names and Order of Includes

Use standard order for readability and to avoid hidden dependencies: C library, C++ library, other libraries' .h, your project's .h.

Scoping 

Nonmember, Static Member, and Global Functions

Prefer nonmember functions within a namespace or static member functions to global functions; use completely global functions rarely.

Local Variables

Place a function's variables in the narrowest scope possible, and initialize variables in the declaration.

Static and Global Variables

Static or global variables of class type are forbidden: they cause hard-to-find bugs due to indeterminate order of construction and destruction.

Classes 

Doing Work in Constructors

In general, constructors should merely set member variables to their initial values. Any complex initialization should go in an explicit Init() method.

Default Constructors

You must define a default constructor if your class defines member variables and has no other constructors. Otherwise the compiler will do it for you, badly.

Structs vs. Classes

Use a struct only for passive objects that carry data; everything else is a class.

Inheritance

Composition is often more appropriate than inheritance. When using inheritance, make it public.

Multiple Inheritance

Only very rarely is multiple implementation inheritance actually useful. We allow multiple inheritance only when at most one of the base classes has an implementation; all other base classes must be pure interface classes tagged with the Interface suffix.

Interfaces

Interfaces should be named using an I- prefix. Example: IMySexyInterface

Access Control

Make data members private, and provide access to them through accessor functions as needed. Typically a variable would be called mFoo and the accessor function getFoo(). You may also want a mutator function setFoo().

Declaration Order

Use the specified order of declarations within a class: public: before private:, methods before data members (variables), etc.

Write Short Functions

Prefer small and focused functions.

Other C++ Features

Reference Arguments

All parameters passed by reference must be labeled const.

Use of const

We strongly recommend that you use const whenever it makes sense to do so.

64-bit Portability

Code should be 64-bit and 32-bit friendly. Bear in mind problems of printing, comparisons, and structure alignment.

Preprocessor Macros

Be very cautious with macros. Prefer inline functions, enums, and const variables to macros.

Naming 

General Naming Rules

Function names, variable names, and filenames should be descriptive; eschew abbreviation. Types and variables should be nouns, while functions should be "command" verbs.

Type and Namespace Names

Type names start with a capital letter and have a capital letter for each new word, with no underscores: MyExcitingClass, MyExcitingEnum.

Variable Names

They start with a capital letter and have a capital letter for each new word, with no underscores. A m- prefix is used for member variables. A s- prefix is used for static variables. For instance: myExcitingLocalVariable, mMyExcitingMemberVariable, sMyExcitingMemberVariable

Constant Names

Use capitals and underscore as a separator: DAYS_IN_A_WEEK.

Function Names

Regular functions have mixed case; accessors and mutators match the name of the variable: myExcitingFunction(), myExcitingMethod(), getMyExcitingMemberVariable(), setMyExcitingMemberVariable().

Enumerator Names

Enumerators should be named either like constants or like macros: ENUM_NAME.

Macro Names

You're not really going to define a macro, are you? If you do, they're like this:  MY_MACRO_THAT_SCARES_SMALL_CHILDREN. 

Comments 

File Comments

Start each file with a copyright notice, followed by a description of the contents of the file.

Class Comments

Every class definition should have an /** accompanying comment */ that describes what it is for and how it should be used.

Function Comments

Every function should have a /** declaration comment */ which describes use of the function, using @param and @return syntax.

Variable Comments

In general the actual name of the variable should be descriptive enough to give a good idea of what the variable is used for. In certain cases, more comments are required.

Implementation Comments

In your implementation you should have comments in tricky, non-obvious, interesting, or important parts of your code.

Punctuation, Spelling and Grammar

Pay attention to punctuation, spelling, and grammar; it is easier to read well-written comments than badly written ones.

Formatting

Line Length

Each line of text in your code should be at most 80 characters long.

Preprocessor Directives

Preprocessor directives should not be indented but should instead start at the beginning of the line.

Class Format

Sections in public, protected and private order, each indented one space.

Indents and spaces

Inconsistent use of indents, tabs and spaces is a problem in much the same way as inconsistent naming is. Most text editors have the necessary options. For example, in Visual Studio, go Tools > Options > Text Editor > C/C++ > Tabs.
 
The following should apply to all MoSync code: one level of indention equals one tab. A tab is defined as the ASCII character \t. The actual screen size of the indents can thus be set by and for each user with no ill effects for others.

Syscalls

Syscalls are named using a ma- prefix. Only actual Syscalls and IOCTLs are named this way. Examples:
 
void maDisposeLayer(Handle layer);
void maSetMap(Handle layer, Handle srcMapResource, int destX, int destY);

Library functions

Library functions that are directly associated with the manipulation of some complex datatype (such as a struct) should be prefixed with the name of the type followed by an underscore, followed by the function name in camel case. Examples:

MAVec3_normalize(MAVec3* v);
MARect_containsPoint(const MAVec3* v, const MAPoint2d* p); 

Library functions that are not directly and strongly related to a datatype should be prefixed with an identifying name for the library, which should always contain an initial 'MA'. Examples:

MAMath_solveLinearSystem();
MAInet_sendMail();

Design Patterns

Syscalls and extensions

Syscalls and extensions constitute the lowest-level APIs available in MoSync. They are typically directly mapped to underlying platform features and are also subject to a number of restrictions:
 
The number of parameters is limited to four. If more information must be passed, the stack or struct pointers can be used.
Parameters cannot be function pointers. If a notification mechanism is required, one is required to make use of (custom) events.
The only allowed parameter types are primitive IDL types (see IDL documentation) and IDL structs that actually are declared in the relevant IDL file.
The only allowed return types are primitive IDL types.
MoSync memory cannot be allocated within syscalls, other than in the specific case of built-in or custom events.

Syscalls that manipulate objects/resources

Allocation, manipulation and deallocation of native objects (resources) is typically implemented by means of handles.
Typically, there is an maCreateX() function, which takes a placeholder handle to represent the allocated native object. Subsequent access to this object is provided through other syscalls that accept handles as their first parameter.
Finally, all objects are destroyed using maDestroyObject(). As an example, these are some functions that create and manipulate images:
 

void maCreateImageFromData(
in Handle placeholder,
in Handle data,
in int offset,
in int size
);
void maCreateImageRaw(
in Handle placeholder,
in MAAddress src,
in Extent size,
in int alpha
);
void maDrawImage(
in Handle image,
in int left,
in int top
);
void maDrawImageRegion(
in Handle image,
in MARect srcRect,
in MAPoint2d dstPoint,
in int transformMode
);

Asynchronous operations

Since MoSync doesn't support user-created threads, it is important to provide asynchronous interfaces to time-consuming native functionality such as network communication. Since syscalls can't accept function pointers, the central MoSync event system is used to provide progress notification. A few built-in event types are provided in the EVENT struct, but there's also a void* provided that can be used for custom events.

Writing Extensions for MoSync

 

We encourage everyone to help us develop MoSync, and writing new extensions for MoSync is probably the most common thing you will want to do. In this topic we introduce you to some important core concepts that you need to understand and lead you step-by-step through creating an API extension.

This topic assumes that you have a good understanding of how to use MoSync, that you understand the build process, and that you can build the MoRE runtime in Visual Studio. It also assumes that you have some basic familiarity with the MoSync code.

 

Core Concepts

In this section we introduce some core concepts that you will need to understand when you write extensions.

Runtimes and user code

Interaction of user code and runtime through syscalls

User code includes all the code that you write when you create an application with MoSync along with some of the MoSync libraries, such as the MAUI library.

A runtime is the thing that executes the user code on the device. For each platform that MoSync supports, there is a different runtime. Some runtimes are written in C++, others like the J2ME and Android runtimes are written in Java. Each runtime has two parts: one that executes the user code and one that interfaces to it to provide low-level services.

Syscalls and events

Communication between the user code and a runtime is through syscalls and events. Syscalls are like the traditional calls a user application makes to an OS kernel. Whenever the user code needs to do something it cannot do on its own, such as creating a socket connection, it performs a syscall to the runtime. To create a socket connection, for example, the syscall is maConnect.

A syscall is an actual instruction which the runtime traps during code execution. The instruction only has one argument, and that is the syscall number. A syscall, like any ordinary function call, can return a value. A syscall can do pretty much any thing you'd like it to do, but what it can never do is to block. If the syscall cannot finish immediately, such as when waiting for socket data, it needs to return and have the blocking call run in a thread in the background. Once it has finished, it will return the result through events which the user fetches through yet another syscall called maGetEvent.

The maIOCtl syscall

The maIOCtl syscall is a special syscall which is meant for extensions which aren't supported or fully supported on all the MoSync runtimes. What this means in practice is that anything that isn't part of the standard API, that is anything that isn't the least common denominator on all platforms,  will be implemented through an maIOCtl. Implementing an MaIOCtl is simpler than implementing an entirely new syscall, and is what you will be using to implement your extensions. The only limitation that the maIOCtl syscall has is that it only takes three parameters. But on the bright side, any or all the three can be user defined structures, which means that you can always pass all the parameters you like in a structure.

maapi.idl and Pipe-Tool

Any syscall starts its life in a file called maapi.idl. Here all syscalls, events, and event types (among other things) are defined. To minimize the amount of code redundancy, we have created a tool called idl2 which takes the maapi.idl file and generates several important files:

 

  • $MOSYNCDIR/bin/asm_config.lst — the file used by Pipe-Tool to recognise syscalls
  • runtimes/java/shared/invoke_syscall_java.h the inner part of switch case which handles different syscalls for the java runtimes
  • runtimes/cpp/core/invoke_syscall_cpp.h the inner part of switch case which handles different syscalls for the c++ runtimes
  • runtimes/java/shared/generated/core_consts.h opcodes and such for java runtimes
  • runtimes/java/shared/generated/maapi_consts.h constants in the maapi.idl file
  • intlibs/helpers/cpp_defs.h constants and structs in the maapi.idl file, for the C++ runtimes
  • intlibs/helpers/cpp_maapi.h all the syscall declarations for the C++ runtimes
The idl2 tool also generates a set of files with the string "_IX_" in their filename. These are extensions that have been implemented through the maIOCtl syscall. To the MoSync GCC, a syscall is the same as just a normal function call. It is completely unaware of the concept syscall. Recognising syscalls and patching the binary code with the syscall opcode is the job of pipetool. The way it recognises the syscalls is quite simple, it looks at the generated asm_config file to see if a function call is actually a syscall or not. If it is, then its call opcode is replaced with a syscall opcode.

The maapi.idl format is quite simple. It contains declarations for syscalls in a C-like syntax:
RETURN_TYPE IDENTIFIER ( (in|out) TYPE IDENTIFIER, ...);
where:
  • RETURN_TYPEis 
    • void [*]
    • [unsigned] char [*]
    • [unsigned] short [*]
    • [unsigned] int [*]
    • [unsigned] long [*]
    • [unsigned] float [*]
    • [unsigned] double [*]
  • IDENTIFIER is a normal C identifier (for example, maConnect )
  • in|out - Tells the idl2 tool whether the parameter goes in or out.
  • TYPE is any primitive or user defined type
A syscall declaration looks like this:
int maFrameBufferGetInfo ( out MAFrameBufferInfo info );
Note that the declarations are written in between:
#if IX_SOMETHING . . . #end 

For maIOCtl declarations the block ends up in a separate file with a similar name. It is in this block that you will be writing API extensions. The idl2 tool also produces wrapper code for any extensions that have been written through maIOCtl. This is another one of the advantages of the idl2 tool. It takes care of all the little details and updates every where that needs to be updated. The wrapper code might look something like this (from libs/MAStd/IX_CELLID.h):

static inline int maGetCellInfo ( MACellInfo* pInfo ) {     return maIOCtl( 56, (int)pInfo, 0, 0 ); } 

Creating an Extension Step-by-Step

Now that the concepts are in place, it's time to get our hands dirty. There are five steps to writing an API extension:
  1. Edit tools/idl2/maapi.idl
  2. Run the idl2 tool
  3. Add your implementation to the runtimes you need
  4. Rebuild all the user libraries
  5. Try it out

In this example we will write a simple extension as an maIOCtl, we will pass a structure with 16 chars in it, and will return the same chars through an event.

Step 1 — Editing tools/idl2/maapi.idl

We need to make four changes in this file:

  • Add an extension define
  • Add a new event type
  • Add a new inner structure to the event structure
  • Add a new maIOCtl

 

Adding the extension define

Edit tools/idl2/extensions.h file and add to it "#define IX_TUTORIAL". This is needed to process anything that is declared between '#if ...' and '#endif' in the maapi.idl file. Here is the start of our example:

#define IX_RESOURCE_TYPES
#define IX_GUIDO
#define IX_WLAN
#define IX_FILE
#define IX_RECORD
#define IX_CELLID
#define IX_CALL
#define IX_STREAMING
#define IX_CONNSERVER
#define IX_OPENGL_ES
#define IX_AUDIOBUFFER
#define IX_SEGMENTED_DATA
#define IX_PIM
#define IX_TUTORIAL

Adding the new event type

The MAEvent structure contains a field called "type", this field is an integer which identifies the event type. So next we need to add a constant which identifies our custom event. At the end of the block called "constset int EVENT_TYPE_" we add our custom event type:

#if IX_TUTORIAL
        TUTORIAL = 10001;
#endif

Note: To avoid collisions with future extensions from the MoSync team, we suggest that you always choose a large value for the event constant.

In the version of maapi.idl that we are working with, the entire block looks like this:

constset int EVENT_TYPE_ {
		/**
		* This event is posted when the operating system sends MoSync a command 
          * to exit. Causes include the OS shutting down and OS-controlled user 
         * commands. 
         * \see maGetEvent()
		*/
		CLOSE = 1;

		KEY_PRESSED = 2;
		KEY_RELEASED = 3;
		/// Connection
		CONN = 4;
		/// Bluetooth discovery
		BT = 5;
#if IX_GUIDO
		/// Has MAEvent::key be the identifier for the TTS session, as returned 
        /// by maStartSpeaking().
		TTS = 6;
#endif	//IX_GUIDO
#if IX_WLAN
		/// Uses MAEvent::state.
		WLAN = 7;
#endif	//IX_WLAN

		POINTER_PRESSED = 8;
		POINTER_RELEASED = 9;
		POINTER_DRAGGED = 10;

#if IX_CALL
		/// Has MAEvent::state be one of the \link CALLSTATE \endlink constants.
		CALL = 11;
#endif	//IX_CALL

		/**
		 * While MoSync doesn't have focus, no key events will arrive and the 
          * screen will not be updated. If the keypad is locked, no application 
          * will have focus.
		 * \see maLockKeypad
		 */
		FOCUS_LOST = 13;
		FOCUS_GAINED = 14;

#if IX_STREAMING
		/**
		* Has MAEvent::data point to a MAStreamEventData.
		*/
		STREAM = 15;
#endif	//IX_STREAMING
//#if IX_LOCATION
		/// Has MAEvent::data point to an MALocation.
		LOCATION = 16;

		/// MAEvent::state is one of the \link #MA_LPS_AVAILABLE MA_LPS 
          /// \endlink constants.
		LOCATION_PROVIDER = 17;
//#endif	//IX_LOCATION
#if IX_AUDIOBUFFER
		/// MAEvent::state is \> 0 when the audio stream is waiting for more data,
		/// or \< 0 on error.
		AUDIOBUFFER_FILL = 18;
#endif
		SCREEN_CHANGED = 21;

#if IX_TUTORIAL
         /// Just a simple event type added for the tutorial
         TUTORIAL = 10001;
#endif
	}

Adding the new inner structure to the event structure

Now that we have a new event type, it is time to create a way through which we can return data to the user from an event. This can be accomplished in two ways, one is to allocate dynamic memory in the runtime and let the runtime copy that memory to user memory. The runtime will also update the data pointer in the MAEvent struct. To do this, you have to write a few macros in the right places. The second method is to create a new struct with the data that you need to return to the user and embed this in the MAEvent struct. The second method has the advantage of being a bit simpler, but at the cost of bloating the MAEvent struct. For the sake of simplicity, we will only go through the later method in this document. So let's get started.

First, we define our struct. We can call it MATutorialEvenData, it needs to contain 16 chars. The next step is to embed it in the MAEvent struct, in the revision of the code base that the author is working with, the entire code will look like this.

struct MATutorialEventData {
	char m_data[16];
}

struct MAEvent {
	/**
	* One of the \link #EVENT_TYPE_CLOSE EVENT_TYPE 
	* \endlink constants.
	*/
	int type;
	union {
		struct {
			/**
			* In KEY events, this will be one of the 
			* \link #MAK_UNKNOWN MAK \endlink constants.
			*/
			int key;
			/**
			* In KEY events, this will be the native keycode.
			*/
			int nativeKey;
		} ked;

		/**
		 * Tutorial structure
		 */
		MATutorialEvenData tutorial;

		/**
		 * In POINTER events, this will be the location of the pointer.
		 */
		MAPoint2d point;

		/**
		* In \link #EVENT_TYPE_BT BT \endlink events, this will be a value \>= 0 or
		* one of the \link #CONNERR_GENERIC CONNERR \endlink constants.
		*/
		int state;

		/**
		* Valid only in CONN events.
		*/
		MAConnEventData conn;

		/**
		* Used by custom events. See invididual event descriptions.
		*/
		void* data;
	}
}

Adding the new maIOCtl

 

At this point we have all the parts in place to return data through events, now we just need a way of making a call to the runtime. This is where syscalls and maIOCtl comes in. We will define a new IOCtl in the maIOCtl block (after the opening bracket and before the closing bracket). The maIOCtl will look like this:

#if IX_TUTORIAL
  int maSyscallTutorial(in MAString data);
#endif //IX_TUTORIAL

where MAString is a defined as 'typedef char* MAString' at the top of the maapi.idl file.

Step 2 — Running the idl2 tool

Now that we've made actual changes to the syscall interface, we need to regenerate all the auto generated files that have to do with syscalls. In Visual Studio, build tools/idl2 and run it. Your output should look like this,

If you instead get this:

D:\workspace\repo-new\MoSync2.3\tools\idl2>Debug\idl2.exe
Error opening file "opengl_generated.idl" in
maapi.idl on line 2383
Exception: Unknown exception

Then you need to build the opengl_generated.idl, run tools\GLWrapperGenerator\build.bat and run the idl2 tool again.

You probably noticed that for most files it generates three different versions of it. For instance, the IX_TUTORIAL extension goes in:

  • intlibs\CPP_IX_TUTORIAL.h
  • libs\MAStd\IX_TUTORIAL.h
  • runtimes\java\shared\generated\IX_TUTORIAL_consts.h
The first one is to be used from the C++ runtimes (MoRE, Symbian, Windows mobile, Linux). The second file is to be used on the user side. The last file is to be used from the Java runtimes (such as J2ME and Android).
So let's look inside the first two files ( since we're only doing the changes for a C++ runtime in this example). In the first file we have:
#ifndef IX_TUTORIAL_DEFS_H #define IX_TUTORIAL_DEFS_H /** \brief A hash of the abstract representation of the API described in this file. * Identifiers, declarations and definitions are included in the calculation of the hash, * but documentation is not. */ #define MAIDL_HASH ((int)0xc2fcb710) /// Just a simple event type added for the tutorial #define EVENT_TYPE_TUTORIAL 10001 #define maIOCtl_maSyscallTutorial 247 #endif //IX_TUTORIAL_DEFS_H

In here we have hash (which is discussed in section 4), the event ID, and syscall ID. We will need these to write the code which handles the maIOCtl call in the runtime. The java version contains similar things.

In the next file we have:

#ifndef IX_TUTORIAL_H
#define IX_TUTORIAL_H

#ifdef __cplusplus
extern "C" {
#endif

/// Just a simple event type added for the tutorial
#define EVENT_TYPE_TUTORIAL 10001

static inline int maSyscallTutorial(const char* data) {
	return maIOCtl(247, (int)data, 0, 0);
}

#ifdef __cplusplus
}
#endif

#endif	//IX_TUTORIAL_H

As you see, this file is a bit different, there is an actual C function in there, this is because we wrote our new syscall/extension in the maIOCtl block. The idl2 tool knows that anything inside that block is not an actual syscall, but goes through the maIOCtl syscall. The first parameter is the maIOCtl ID, and in the previous file you can see that the preproccesor define "maIOCtl_maSyscallTutorial" is set to 247, which is quite practical and the reason that the previously discussed hash is needed to make sure that both the user libraries and the runtime agree on the same syscall interface.

Step 3 — Add your implementation in the runtimes you need

 

By this point, we have all the parts in place to do the maIOCtl on the user side.  Now you need to write the code on the runtime side which actually handles the IOCtl. In this document, the only runtime we will modify is MoRE, but modifying the other runtimes is similar.

In the source directory, there exists a file runtime/cpp/platforms/sdl/SyscallImpl.cpp, this file handles all the syscalls in the SDL runtime (MoRE). In the Visual Studio project you can find it under Platforms/cpp/sdl/SyscallImpl.cpp. Open it, and add the include "#include <helpers/CPP_IX_TUTORIAL.h>", this will include the definitions that have to do with our example.

Next we need to add the actual code for handling the IOCtl. So, scroll down to the part that says:

SYSCALL(int, maIOCtl(int function, int a, int b, int c)) {

This is the actual maIOCtl syscall. In it you will find a big switch statement. We need to add our own handler to this switch case. So just before the default case, we add this piece of code:

        case maIOCtl_maSyscallTutorial:
        {
            char *  data;
            MAEvent myevent;
            
            // Get pointer to memory
            data = (char*)SYSCALL_THIS->GetValidatedMemRange( a, 16 );

            // Copy to event
            myevent.type = EVENT_TYPE_TUTORIAL;
            memcpy( myevent.tutorial.m_data, data, 16 );

            // Put in event queue
            gEventFifo.put( myevent );

            // Return success code
            return 1;   
        }            

Let's go through the parts of this code. Firstly, a pointer to the argument that was passed to the maIOCtl from the user side, is fetched. The method GetValidatedMemRange takes a pointer to the user side memory and the number of bytes that the pointer points to. If the memory is valid, a pointer will be returned. Otherwise a panic will occur.  Secondly, the event type is set and the ASCIIZ string passed by the user is copied to the event structure. Thirdly, the event is put in the event queue, from where it can be fetched by the user through the maGetEvent syscall. And lastly, we return from the maIOCtl syscall.

Assuming that you have Visual Studio correctly set up and you can build MoRE, rebuild MoRE. The executable will be copied to your MoSync installation path (MOSYNCDIR/bin).

Step 4 — Rebuilding all the user libraries

This step is very important. Any change you make to the IDL file might change the binary interface of syscalls (specfically syscall IDs). Because of this there is a hash in the generated maapi.h file that is verified against the runtime to make sure the user code and the runtime have been built with the same interface. So we need to remove all the old files and rebuild the libs:

  1. In your MoSync installation dir (let's call it MOSYNCDIR), delete include/*
  2. delete MOSYNCDIR/lib/pipe/*
  3. In the source directory (let's call it MOSYNCSRC), do cd libs
  4. ruby workfile.rb
  5. ruby workfile.rb CONFIG=""

Step 5 — Trying it out

If you have gotten everything to work this far, there should be only one last step remaining, and that is to actually test that it works as expected. In the MoSync IDE, create a project and create in it a file called main.c containing the following code:

#include <ma.h>
#include <IX_TUTORIAL.h>

int MAMain ( )
{
	while ( 1 )
	{
		MAEvent e;
		while ( maGetEvent( &e ) != 0 )
		{
			switch ( e.type )
			{
				case EVENT_TYPE_CLOSE:
					return 0;

				case EVENT_TYPE_KEY_PRESSED:
				case EVENT_TYPE_POINTER_PRESSED:
					maSyscallTutorial( "world!" );
					break;

				case EVENT_TYPE_TUTORIAL:
					printf( "Hello %s\n", e.tutorial.m_data );
					break;
			}
		}
	}

	return 0;
}

If you've done everything correctly, this code will compile and run just fine. And in that case, congratulations, you've just written your first MoSync extension!