Skip to content
Alessandro Febretti edited this page Mar 9, 2015 · 5 revisions

Last revision: ver. 6.3 - 6 March 2015

Starting form version 5.0, omegalib features a fully modular design. This new design allows users to start with a very lightweight version of omegalib, and customize it with the modules they need. Modules are kept in separate repositories so each revision history is separate, and development by different users is easier. When needed you can create your own modules in C++ or python, save them into a github repository and make them accessible to other omegalib users.

How does omegalib install modules

Omegalib does the following to perform module search and installation:

  • During the first cmake configuration, a module list file is downloaded from a specific github repository, called the module hub. The predefined module hub is http://github.com/omega-hub/hub, and it can be customized by setting the OMEGA_HUB_URL CMake variable. Changing the hub repository is useful if you want to maintan your own module list.
  • The module list file is simply a CMakeLists.txt file containing a list of available modules, the url of their github repository and a brief description.
  • CMake populates a list with checkable boxes for each module in the list
  • The user clicks on modules that should be installed, or lists their names in the MODULES CMake variable. The variable is particularly useful for command line configurations: for instance, typing cmake [path-to-omega-source] -DMODULES="cyclops sprite omegaVtk" will setup an omegalib build environment with the cyclops, sprite and omegaVtk modules (and all their dependencies)
  • CMake clones the github repositories of all the selected modules. The repositories get cloned in the <omegaSource>/modules directory. CMake then runs the CMakeLists.txt file for each module. This file is used to setup the builds of native C++ modules, specify install commands, and lists module dependencies. The module dependencies are used to install additional required modules.
  • The user does a cmake configure (possibly multiple times), until all the modules are downloaded and all the dependencies have been resolved.
  • the build environment is ready

Creating a module

Omegalib modules can be created in C++ or python. This section will document steps common to both module types. Folowing sections will detail how to develop modules in each language.

Setting up a module development environment

The first step in creating a module is choosing a name for it. Make sure the name is unique (not shared with other modules), and as explanatory as possible.

You should create a directory in <omegaSource>/modules with your module name. All your module code and data will be in this directory.

Each module directory should contain at least a file: CMakeLists.txt. For very simple modules with no dependencies, this file can be empty. This file can also contain a list of dependencies, modules needed my this module to work. Dependencies are specified using the request_dependency(<moduleName>) command. Note thas this makes it possible to create bundle modules: empty modules that contain only a CMakeLists file enumerating other modules. When users install a bundle module, all modules listed as dependencies will be installed automatically. This makes it practical to create pre-packaged distributions. See the vr-bundle module for an example of this (https://github.com/omega-hub/vr-bundle)

Adding the module locally

Since your module is not yet registered with an online hub, you will have to force-load it. Do do so, set the following cmake variable:

  • MODULES_LOCAL = [list of modules you want here]: here specify manually the list of all the local modules you want to enable.

For instance, using the omegalib maintenance scripts (v6.3+), if you have a local installation called master, your new module name is X you can type:

> omega set master MODULES_LOCAL X
> omega build master

Python Modules

In addition to the CMakeLists file, python modules should contain at least an __init__.py file. This file will be executed when users import the module using an import moduleName pyton statement. For simple modules, all you code can be placed in init.py. For more complex modules with multiple classes or scripts, init.py should in turn import each one of those modules.

example

This is an example of a python module called sphereMaker, containing a single function makeSphere that can be used to, you guessed, create sphere objects. We assume this module depends on the cyclop module. The module directory (which should be <omegaSoruce>/modules/sphereMaker) will contain the following three files:

CMakeLists.txt

# Tell omegalib this module depends on another module (cyclops). Cyclops will
# be automatically installed when this module is enabled.
request_dependency(cyclops)

init.py

# Just import the sphereMakerFunctions file, it will contain our actual function
from sphereMakerFunctions import *

sphereMakerFunctions.py

from cyclops import *
from omega import *
from euclid import *
def makeSphere(x, y, z, color):
	sp = SphereShape.create(1, 2)
	sp.setPosition(x, y, z)
	sp.setEffect("colored -e " + color) 
	return sp

...and that's it!

Now, in an omegalib application script or interactive console you can type the following to create a red sphere:

from sphereMaker import *
makeSphere(0, 2, -2, 'red')

C++ Modules

The following is an example of a CMakeLists.txt file that creates an omegalib C++ module:

request_dependency(cyclops)

# The following line makes sure the cyclops module is installed.
if(TARGET cyclops)
        # Set the module name here
        SET(MODULE_NAME templateModule)

        # Set module name and source files here
        add_library(${MODULE_NAME} MODULE 
                templateModule.cpp)

        # Set the module library dependencies here
        target_link_libraries(${MODULE_NAME}
                omega 
                omegaToolkit 
                cyclops)

        #------------------------------------------------------------------------------
        # DO NOT MODIFY ANYTHING BELOW AFTER THIS LINE
        set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
        if(WIN32)
                set_target_properties(${MODULE_NAME} PROPERTIES FOLDER modules SUFFIX ".pyd")
        endif()
endif()

Python Interface Declaration

C++ classes and methods are exposed using a module declaration section in your source file. The module declaration lists all the classes and methods you want to expose, together with some minimal information about how they work. Here is an example of a module declaration:

	BOOST_PYTHON_MODULE(templateModule)
	{
		// SceneLoader
		PYAPI_REF_BASE_CLASS(HelloModule)
			PYAPI_STATIC_REF_GETTER(HelloModule, createAndInitialize)
			PYAPI_METHOD(HelloModule, setObjectColor)
			;
	}

The module declaration uses a set of macros that internally use Boost::python to interface python and C++. The previous declaration creates a module named templateModule, containing a class HelloModule with a static and nonstatic method.

Python Wrapper Reference

Here is the set of macros that can be used to create a module declaration:

Class and Module Declarations

Macro Name Description
BOOST_PYTHON_MODULE(name) Starts the module declaration block. Each library can have only one module declaration bloc. The module name MUST match the name of the output module file (for instance, in the previous example the module output should be templateModule.pyd)
PYAPI_BASE_CLASS(name) Starts a base class declaration. This class will have pass by value semantics (i.e. a = b will make a copy of object b)
PYAPI_BASE_CLASS_WITH_CTOR(name) Like PYAPI_BASE_CLASS but the class has a default constructor, so objects can be constructed with a = Class().
PYAPI_REF_BASE_CLASS(name) Starts a base class declaration. This class will have pass by reference semantics (i.e. a = b will increase the reference count of b, but both variable will refer to the same object). This declaration can be used to expose C++ classes derived from 'ReferenceType'.
PYAPI_REF_BASE_CLASS_WITH_CTOR(name) Like PYAPI_REF_BASE_CLASS but the class has a default constructor, so objects can be constructed with a = Class().
PYAPI_REF_CLASS(name, base) Creates a pass-by-reference class derived from another class base.
PYAPI_REF_CLASS_WITH_CTOR(name, base) Creates a pass-by-reference class derived from another class base and supporting a default constructor

Method Declarations

Inside a class declaration you can use the following macros:

Macro Name Description
PYAPI_METHOD(className, methodName) Declares a method for the class. The method can return void, or simple data types (int, string, bool, float), and can accept any number or arguments
PYAPI_GETTER(className, methodName) Declares a getter for the class. The getter returns a user defined return-by-value type (see PYAPI_BASE_CLASS) or one built-in complex value type, like Vector3, Quaternion, etc.
PYAPI_REF_GETTER(className, methodName) Declares a reference getter for the class. The getter returns a user defined return-by-reference type (see PYAPI_REF_BASE_CLASS) or one built-in reference type, like SceneNode, Light, etc.
PYAPI_STATIC_REF_GETTER(className, methodName) Declares a static reference getter, that is, a reference getter that can be accessed using the class name directly (b = Class.staticMethod())
PYAPI_PROPERTY(className, propName) Declares a property: a public class field that can be read and written from python. The property can be one basic type (int, float, string).
(v6.0) PYAPI_REF_PROPERTY(className, propName) Declared a property to read/write a reference type field.
(v6.0) PYAPI_VALUE_PROPERTY(className, propName) Declared a property to read/write a structure value type field, like Vector, Quaternion, etc.

Other Declarations

Macro Name Description
PYAPI_ENUM(fullEnumName, enumName) Wraps a C++ enumeration into a Python enumeration.
PYAPI_ENUM_VALUE(fullEnumName, enumName) Declares a value for the enumeration.

Publishing your module

To make your module accessible to other developers you need to do two things: commit it to a new git repository (we suggest using GitHub to host your repository), and add it to the master module list. The default master module list is hosted in the https://github.com/omega-hub/hub repository (see https://github.com/omega-hub/hub/blob/master/CMakeLists.txt). You should fork this repository and modify its CMakeLists file to add your module. In your installation, you can tell CMake to use your fork of the master module list:

If you want to share your module with others, send a pull request on the omega-hub repository.

Clone this wiki locally