Porting
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.
Option | Location | Setting |
---|---|---|
Include Directories | Build -> C++Compiler | include;${ECHO_ENGINE_DEPENDENCIES_DIR}/opt/yourplatform/include |
Preprocessor Definitions | Build -> C++Compiler | ECHO_PLATFORM_YOURPLATFORM |
Ouput | Build->Linker | ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/libecho3.${CND_DLIB_EXT} |
Additional Library Directories | Build->Linker | ${ECHO_ENGINE_INSTALL_DIR}/dist/${CND_CONF}/${CND_PLATFORM};${ECHO_ENGINE_DEPENDENCIES_DIR}/opt/yourplatform/lib |
Configuration Type | General | Set to static or dynamic library as necessary. Be sure to consider third party licencing requirements. |
Runetime Search Directories | Build -> Linker | ${ECHO_ENGINE_INSTALL_DIR}/dist/${CND_CONF}/${CND_PLATFORM};${ECHO_ENGINE_DEPENDENCIES_DIR}/opt/linux/lib |
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
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.
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