Page MenuHomePhabricator

Porting
Updated 2,541 Days AgoPublic

Porting Echo to a new platform requires quite a bit of work. This document lists each of the things you need to address and explains each in detail.

Setup

Organising your files

Any source files you want to add should go into src/Platforms/YourPlatform and headers in include/echo/Platforms/YourPlatform

NetBeans project configuration

We use environment variables defined in env/YourPlatform-prebuild.config to set compiler and linker flags. This is so a single point of change can persist for all projects if they are set up to reference these variables.

In the env folder the *-prebuild.config files define flags to be used by the various build tools. NetBeans Project configuration files usually reference these parameters.

The *-postbuild.sh scripts are scripts to execute after NetBeans has compiled and linked. These scripts are used as a work around to allow a post build step which is required to complete the build process for some platforms. Unfortunately this is a limitation of NetBeans, hopefully in the future this will be resolved.

Copy the prebuild and postbuild files for the platform that closely matches yours. You will need to rename them to YourPlatform-prebuild.config and YourPlatform-postbuild.sh. Open the prebuild configuration file and rename each occurrence of ECHO_VAR_RELEASE_ to ECHO_VAR_YOURPLATFORM_ keeping the naming convention consistent.

Modify each variable as appropriate for your target. For example, you may need to modify compiler settings or library dependencies.

Now, in NetBeans open the echo3 project then open the project properties window. Click on the "Manage Configurations" button. Either create a new configuration or duplicate another one if it is closer to what you already want (often the case).

You'll need to modify the project properties so that the variables are used.

OptionLocationSetting
Include DirectoriesBuild -> C++Compilerinclude;${ECHO_ENGINE_DEPENDENCIES_DIR}/opt/yourplatform/include
Preprocessor DefinitionsBuild -> C++CompilerECHO_PLATFORM_YOURPLATFORM
OuputBuild->Linker${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/libecho3.${CND_DLIB_EXT}
Additional Library DirectoriesBuild->Linker${ECHO_ENGINE_INSTALL_DIR}/dist/${CND_CONF}/${CND_PLATFORM};${ECHO_ENGINE_DEPENDENCIES_DIR}/opt/yourplatform/lib
Configuration TypeGeneralSet to static or dynamic library as necessary. Be sure to consider third party licencing requirements.
Runetime Search DirectoriesBuild -> Linker${ECHO_ENGINE_INSTALL_DIR}/dist/${CND_CONF}/${CND_PLATFORM};${ECHO_ENGINE_DEPENDENCIES_DIR}/opt/linux/lib
NOTE: The paths for dependencies that include yourplatform need to be set to the path to match your dependency build location. See Building Dependencies for more information.

You will need to set any additional options as needed.

Finally, to tell NetBeans which toolchain to use for building you may need to set up a custom toolchain. Unfortunately these settings don't move around with the project since they are system independent. When we come up with a way to transfer these settings automatically we'll add instructions to do so. In the mean time you might need to supply any special steps required to setup the toolchain for your target.

To add the toolchain, configure toolchains in Netbeans preferences. Define each tool (e.g. which g++ to use). Now in the Project options in Build you should be able to select the new toolchain with the "Tool Collection" option.

Building dependencies

To document. In the mean time, see echo-dependencies for any instructions. Summary:

  • edepbuild essentially wraps ./configure; make and allows you to override some variables, or the entire build step, for each library with a config file. (You can tell it to use cmake instead as well).
  • libraries to build are in the X folder (run the script to acquire if they aren't) and should not contain version numbers.
  • Copy an existing echo-dependencies/scripts folder that closely matches your platform target.
  • Rename each config file with the platform prefix you want to use for dependencies (this is the dependency target name and also the "install" folder location which you should use as the yourplatform.
  • yourplatform-library.config needs to be updated for each library. Refer to other scripts to see various examples of how to deal with different libraries as some aren't maintained as well as others or the versions we are using require some manual steps along the way. It is not uncommon to see sed used in a script to replace some build script option (One rule is we don't want to modify the library source as it makes maintenance trickier when you want to update the library).
  • Run ./edepbuild yourplatform library to just build the one library. If your build fails, it is recommended to delete the build/yourplatform folder to start from a clean environment for that library, for some libraries that use cmake, cmake will create temporary files that persist some settings which might cause a second build to succeed or a previously successful step fail. This means you might commit scripts that don't build from scratch.
  • Make sure all required libraries build. If your platform doesn't need one of the dependencies because it is provided by the system you can skip it with ONLY_SETUP=1 in your configuration file. Some platforms might also need a dependency that all others don't, in this case you will need to set up a script for each other platform (at least until we make some improvements to edepbuild.

Code

NOTE: When creating files for your platform you will need to add them to the project. When you do so, make sure you set all configurations to exclude your new file. For example, if you create src/Platforms/YourPlatforms/SomeGraphicsImplementation.cpp you will need to exclude it from all other configurations to prevent it from being built, similarly you'll need to exclude any files you don't want to build for your platform. To exclude files from a configuration, select one or more files in the project file list and select properties. There should be an Exclude from build check box you need to check.

Platform can mean two things in Echo and it depends on the context to what you refer to. Normally it means a physical device or software target such as a console or operating system. But when you are implementing your target platform "Platform" can also refer to a API implementation of a particular system. For example OpenAL is considered a target since it is portable. Rather than implementing an OpenAL implementation (or copying it) for your device target, it makes more sense to just use the existing OpenAL implementation. Normally this broader term applies when discussing the implementation details of your target.

A platform target can utilise existing system implementations simply by including or excluding the corresponding files from the build configuration. It is recommended to do so when possible to save effort and reduce maintenance overhead. On that note though, you can include multiple implementations in your build, just make sure the most appropriate one is used as the default.

Types.h

You may need to configure your platform types if boost cannot give you type sizes. If you can rely on boost to do type size detection then you can skip to the next section.

If you need to define basic types then create echo/Platforms/YourPlatform/Types.h Define the following types in this file:

u8
u16
u32
u64

s8
s16
s32
s64

f32
f64

Define either ECHO_LITTLE_ENDIAN or ECHO_BIG_ENDIAN to suit your platform.

For example this is compatible with gcc:

#ifndef ECHO_ENDIAN_DETECTED
#if defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define ECHO_LITTLE_ENDIAN
#define ECHO_ENDIAN_DETECTED
#elif defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define ECHO_BIG_ENDIAN
#define ECHO_ENDIAN_DETECTED
#else
#error Could not determine platform endian-ness
#endif
#endif //ECHO_ENDIAN_DETECTED

You'll need to modify echo/Types.h to include a test for your platform then include the appropriate Types.h file. For example:

//--------------------- Include types for YOURPLATFORM -----------------------
#ifdef ECHO_PLATFORM_YOURPLATFORM
#include <echo/Platforms/YourPlatform/Types.h>
#endif //ECHO_PLATFORM_YOURPLATFORM

Platform namespace

Contains all of the functions that give access to creating the various platform specific objects. You should create src/Platforms/YourPlatform/Platform.cpp (perhaps copy from an existing) and implement all the required functions as per the header file. These are essentially default objects of the given type for the platform. For example, the CreateDefaultAudioSystem() function might create a OpenALAudio() object.

You should have a look at the different Platform.cpp files for each platform to get a better idea of how some of the implementations are set up. Since the Android environment is quite different to a Linux one you can see how things are set up.

NOTE: On some platforms it might be appropriate to enforce a singleton type instance, but you shouldn't be enforcing your design choice on the user of the platform namespace. Single instances usually are only appropriate when there is a one-to-one relationship with an API or hardware device and that one object controls it. In these cases the one object should be able to deal with use cases where there are essentially two Echo "applications" instances executed in one. This might sound strange, but what you want to consider is that if someone created a Tetris game it should be able to be launched from within an Echo application and have all resources separate to the parent. The general rules is not to enforce any singleton type behaviour though.

Execution Model

Implement an ExecutionModel class. You also need to return an instance of it in Platform::CreateExecutionModel().
See ExecutionModel.h for more documentation on how to properly implement on. You can often copy one from an existing platform that similar execution constraints.

Timing

Implement the platform methods for CPUTimer in Platforms/YourPlatform/PlaformTimingLibraryCPUTimer.cpp

File System

  • If needed create a FileSystemSource compatible with your platform.

Otherwise if your operating system manages a file system for you then you can configure FileSystemSourceFile.
Echo specifies that there will be at least a default file system source. That is a source that data is acquired from by default when the source isn't included in a file path.

If your platform supports writing files in some way, you should create a persistent FileSystemSource so that an application can save data (configurations, screenshots etc).

Threading

Need to either implement:

  • The platform methods for Thread in `Platforms/YourPlatform/PlaformThreadingLibraryThread.cpp
  • The platform methods for Mutex in `Platforms/YourPlatform/PlaformThreadingLibraryMutex.cpp

Boost is available as a threading target.

Graphics

Need to implement the following:

  • A RenderTarget
  • A Texture as include/echo/Platforms/YourPlatform/PlatformGraphicsLibraryTexture.h and src/Platforms/YourPlatform/PlatformGraphicsLibraryTexture.cpp

Creating a graphics implementation is quite a lot of work. There is an OpenGL implementation available. OpenGLES is available through the OpenGL interface (since they are similar) by defining ECHO_GLES_SUPPORT as a pre-processor.

Audio

Need to implement the following:

  • Audio system
  • AudioBuffer (the audio system will create instances of these)

There is an OpenAL implementation that might be suitable for your platform. Keep in mind that OpenAL needs to be dynamically linked to satisfy the license.

If your implementation doesn't support Audio, return a null shared pointer from the Platform function.

Shell

Shell implementation is not a requirement.
If you want applications to be able to execute commands via the Shell object you'll need to implement a Shell class.

Input

Implement some input devices which should be set up in Platform::CreateDefaultInputManager(), typically a Mouse and Keyboard devices are available on most platforms but this isn't a strict rule.

If you want to allow programmers to be lazy about their device acquisition then create both of these devices, if your platform doesn't support either then you can create a pseudo device for each and update the pseudo devices via some other means. For example a "Mouse" device is currently available for Android which is a PseudoMouse that has its position and left button updated on touch events. This isn't a requirement though since it is recommended that application developers utilise a mapped input device for their application so it can be remapped via a configuration file for each of planned targets.

Network

Networking isn't a requirement for a platform target but is highly recommended.

Since a socket based networking environment is usually available on platforms there are some classes that aren't in the Platform folder since we haven't come across a platform that we support where this isn't the case. So the socket networking system is implemented in as SocketNetworkSystem but can be excluded for a platform if required.

Networking is still abstracted though, the network system is a factory for Connection objects. The factory is often configured with a SocketNetworkSystem as a default but can also be configured with a custom network implementation.

Last Author
0xseantasker
Last Edited
May 14 2017, 1:50 PM

Event Timeline

0xseantasker edited the content of this document. (Show Details)
0xseantasker edited the content of this document. (Show Details)
0xseantasker changed the visibility from "All Users" to "Public (No Login Required)".Mar 6 2019, 4:45 PM