• Dear Cerberus X User!

    As we prepare to transition the forum ownership from Mike to Phil (TripleHead GmbH), we need your explicit consent to transfer your user data in accordance with our amended Terms and Rules in order to be compliant with data protection laws.

    Important: If you accept the amended Terms and Rules, you agree to the transfer of your user data to the future forum owner!

    Please read the new Terms and Rules below, check the box to agree, and click "Accept" to continue enjoying your Cerberus X Forum experience. The deadline for consent is April 5, 2024.

    Do not accept the amended Terms and Rules if you do not wish your personal data to be transferred to the future forum owner!

    Accepting ensures:

    - Continued access to your account with a short break for the actual transfer.

    - Retention of your data under the same terms.

    Without consent:

    - You don't have further access to your forum user account.

    - Your account and personal data will be deleted after April 5, 2024.

    - Public posts remain, but usernames indicating real identity will be anonymized. If you disagree with a fictitious name you have the option to contact us so we can find a name that is acceptable to you.

    We hope to keep you in our community and see you on the forum soon!

    All the best

    Your Cerberus X Team

How to make a target - A "Hello World" target

Ferdi

Member
3rd Party Target Dev
Joined
Jun 21, 2017
Messages
88
This tutorial is for windows only.

1. Compile and run an example

The first thing to make a target is to get a very simple example to compile and run. So in this tutorial the example is:

C++:
#include <stdio.h>

int main()
{
    printf("Hello World From C++\n");
    return 0;
}

And to compile it, the command is:

Code:
g++ -o main main.cpp

And use your favorite command line:

Code:
D:\devtools\hello>g++ -o main main.cpp

D:\devtools\hello>main
Hello World From C++

D:\devtools\hello>

So if you want to create a new target, the first thing to do is to get one simple example to compile. Also how to compile that example.

2. Modify and compile transcc.

2a. Modify src\transcc\builders\builders.cxs

This is where you define your target. So add the following lines

Code:
Import xna
Import hello

...

    builders.Set "xna",New XnaBuilder( tcc )
    builders.Set "hello",New HelloBuilder( tcc )

2b. Create src\transcc\builders\hello.cxs

Code:
Import builder

Class HelloBuilder Extends Builder

    Method New( tcc:TransCC )
        Super.New( tcc )
    End

    Method Config:String()
        Local config:=New StringStack
        For Local kv:=Eachin GetConfigVars()
            config.Push "#define CFG_"+kv.Key+" "+kv.Value
        Next
        Return config.Join( "~n" )
    End
 
    Method IsValid:Bool()
        Select HostOS
        Case "winnt"
            If tcc.MINGW_PATH Return True
        Default
            Return True
        End
        Return False
    End

    Method Begin:Void()
        ENV_LANG="cpp"
        _trans=New CppTranslator
    End

    Method MakeTarget:Void()

        Local out:="main"
        DeleteFile out

        Execute "g++ -o " + out + " main.cpp"

        If tcc.opt_run
            Execute "~q" + RealPath( out ) + "~q"
        Endif
    End
End

New is where this class is initialized. Config method is for those keywords like GLFW_WINDOW_WIDTH and GLFW_WINDOW_HEIGHT. We wont be using it. IsValid method is to check whether the directory path is defined in bin\config.winnt.txt. So in our case we want to use Mingw compiler. Begin method is what language do we translate Cerberus to cpp, java, javascript etc.

And MakeTarget is where the command line happens. In this example, we delete the executable. Then we compile the source file. Lastly we execute the newly executable.

2c. Compile transcc

Before you do this step, copy bin\transcc_winnt.exe to bin\transcc_winnt_original.exe. So you keep a backup of your original transcc before you modify it.

Now we need to compile this. So we need a transcc to create a transcc! The command to compile is:

Code:
transcc_winnt.exe -target=C++_Tool transcc.cxs

Here is my command lines:

Code:
D:\devtools\Cerberus\src\transcc>d:\devtools\Cerberus\bin\transcc_winnt.exe -taget=C++_Tool transcc.cxs
TRANS cerberus compiler V2017-07-04
Parsing...
Semanting...
Translating...
Building...

D:\devtools\Cerberus\src\transcc>

You need to copy transcc.build\cpptool\main_winnt.exe to bin\transcc_winnt.exe. So usually I create a batch file called c.bat like this:

Code:
d:\devtools\Cerberus\bin\transcc_winnt.exe -target=C++_Tool transcc.cxs
copy d:\devtools\Cerberus\src\transcc\transcc.buildv2017-07-04\cpptool\main_winnt.exe d:\devtools\Cerberus\bin\transcc_winnt.exe
pause

2d. Start to create the hello target. Create targets\hello\target.cxs

Create a directory call hello in the targets directory. Then create the file target.cxs:

Code:
#TARGET_NAME="Hello Tool"
#TARGET_SYSTEM="hello"
#TARGET_BUILDER="hello"

Now if you run transcc_winnt.exe, you will see Hello_Tool as a valid target:

Code:
D:\devtools\Cerberus>bin\transcc_winnt.exe
TRANS cerberus compiler V2017-07-04
TRANS Usage: transcc [-update] [-build] [-run] [-clean] [-config=...] [-target=...] [-cfgfile=...] [-modpath=...] <main_cerberus_source_file>
Valid targets: C++_Tool Desktop_Game_(Glfw3) Desktop_Game_(Glfw3+Angle) Hello_Tool Html5_Game Windows_RT_Game_(Phone) Windows_RT_Game_(Tablet)
Valid configs: debug release

3. Compiling the simple example from step 1 using the new transcc

3a. Copy d:\devtools\hello\main.cpp to targets\hello\template\main.cpp.

You will need to create the directory template in the hello target directory.

C++:
#include <stdio.h>

int main()
{
    printf("Hello World From C++\n");
    return 0;
}

3b. Creating and compiling hello.cxs

Now open Ted and create hello.cxs:

Code:
Function Main()

End

And also set the build target to Hello Tool. And run it, you should see it prints out "Hello World From C++" like in this screenshot:

screenshot1.png


So at this point in the tutorial, our transcc is working and it can compile the example from step 1.

4. Compiling Print from Cerberus

4a. Let's change hello.cxs to be:

Code:
Function Main()
    Print "Hello World From Cerberus"
End

4b. targets\hello\template\main.cpp:

C++:
#include "main.h"

//${CONFIG_BEGIN}
//${CONFIG_END}

//${TRANSCODE_BEGIN}
//${TRANSCODE_END}

int main( int argc,const char **argv )
{
    bb_std_main( argc,argv );
}

4c. targets\hello\template\main.h

main.h is from cpptool:

C++:
//Lang/OS...
#include <ctime>
#include <cmath>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <typeinfo>
#include <signal.h>

#if _WIN32
#include <windows.h>
#include <direct.h>
#include <sys/stat.h>
#undef LoadString

#elif __APPLE__
#include <mach-o/dyld.h>
#include <sys/stat.h>
#include <dirent.h>
#include <copyfile.h>

#elif __linux
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>
#include <pthread.h>
#endif

#define _QUOTE(X) #X
#define _STRINGIZE( X ) _QUOTE(X)

4d. src\transcc\builders\hello.cxs

Modify MakeTarget method to include making main.cpp. So this 4 lines of code translate Cerberus code to C++.

Code:
    Method MakeTarget:Void()

        ' This create main.cpp and put the Cerberus code in there.
        Local main:=LoadString( "main.cpp" )
        main=ReplaceBlock( main,"TRANSCODE",transCode )
        main=ReplaceBlock( main,"CONFIG",Config() )
        SaveString main,"main.cpp"

        Local out:="main"
        DeleteFile out

        Execute "g++ -o " + out + " main.cpp"

        If tcc.opt_run
            Execute "~q" + RealPath( out ) + "~q"
        Endif
    End

Remember to recompile the transcc using the batch file we created earlier.

4e. Compiling hello.cxs

If you try to compile hello.cxs, you will still see "Hello World From C++". This is because any changes you make in targets\hello\template directory is still the same in your current build directory. SO YOU HAVE TO REMEMBER TO DELETE THE YOUR BUILD DIRECTORY! If not your changes will not take effect.

Here is a screenshot of what you should see:

screenshot2.png


Summary

1. Get the simplest example compiling and running.
2. Create a new target in transcc.
3. Use the example from step 1 and compile that with transcc.
4. Get Cerberus code compiling and running.

I tried to make this tutorial as simple as possible, so you have a good understanding of the basic of creating a target. Please let me know if there are any questions, comments, mistakes, and problems.
 
Last edited by a moderator:
Thanks, very good tutorial, well written! :)
 
@Ferdi - Great to see this and good approach to keep it very simple. A few things that could help are:

  • @MikeHart or @Martin, is there a way to have the Code(CerberusX) to show things like Code(c++), Code(c), Code(command line), Code(javascript), Code(php), etc...? It would immediately indicate the context of the snippet.
  • Additional information on how the template folder is used by transcc, and pointers to documentation on the special statements like //${CONFIG_BEGIN}, etc...
  • Is it possible to make any sort of changes in the template folder without having to recompile transcc with the corresponding cxs in the builders folder?
  • Information on scope of what a real new target might take to build, not an explanation about how to do it, just a little warning about how much work it might be and what are the caveats?
  • Information on use case of "fixing" a bug or adding an enhancement to an existing target, what sort of things would require a recompile of transcc, what sort of things might only require a file (template) change?
You don't need to respond to these bullet points directly in this thread, whatever you can add to the original post would be welcome and appreciated.
 
@MikeHart - Excellent! I see you already updated @Ferdi's post, makes it much more effective to see the code context. Although the C++ RGB is quite loud, guess that is the standard color scheme for it though. Cheers!
 
Although the C++ RGB is quite loud, guess that is the standard color scheme for it though
Yes, that is the standard that ships with the addon. When I find time, I will see if I can tone it done a notch.
 
@MikeHart Cool!! I love the dark theme. And I love the code highlighting.

Is it possible to make any sort of changes in the template folder without having to recompile transcc with the corresponding cxs in the builders folder?

Once you can see hello_tool, you are done with transcc. Sorry I didn't make this clear in the tutorial, I just wanted to make the tutorial simple. I usually just copy one of the other builder class. For example the dx9 target I am working is a straight copy of glfw.monkey.

Actually I can even use glfw as the target for my dx9, since the way it is compile using mingw and makefile is exactly the same. The problem comes when I want to specify the TARGET variable, that is - which mojo native file to use. So I have to copy my mojo.dx9.cpp to mojo.glfw.cpp.

For my dx9 target may be, it is possible to add a COMPILER config into transcc, then I don't have to change transcc. But my conclusion on this is there is no point, because ios is xcode, android is ant (if I am not wrong), windows phone is msvc, etc. Every target has a different compiler.

May be you can like use XML or JSON for Config, IsValid, and Begin methods. But MakeTarget method, you are stuck, that requires like a scripting language. So you might as well use Cerberus.

Information on scope of what a real new target might take to build, not an explanation about how to do it, just a little warning about how much work it might be and what are the caveats?

Making the transcc is actually the easy part. The hard part (and most of your time) is getting like mojo and making it working consistently with the other target. Also you will be fighting with whatever language that the target translate to. Just yesterday I was initialising a class and it was reseting when I try to use it. Took me a while, I found it was because the C++ code was memset(ing) the class to zero somewhere else. =( Would not happen in Cerberus. The best tip I can give is to try to reuse as much code as possible. Especially mojo, for example that matrix rotation code has to stay the same so all target is consistent.

Information on use case of "fixing" a bug or adding an enhancement to an existing target, what sort of things would require a recompile of transcc, what sort of things might only require a file (template) change?

transcc should not need to change. Once you have like hello_tool, you are pretty much done with transcc. For example glfw uses Makefile, so any files you want to add, you change the makefile not transcc.

In regard to additional information, hopefully I will get to it this weekend. I want to upload the dx9 target this weekend, for a baseline.

@AndyAndroid Just wandering ... are you thinking of making a target? If yes what target?
 
@Ferdi thanks for the additional information and general use case approach.
Ferdi said:
Just wandering ... are you thinking of making a target? If yes what target?
Mostly for understanding how things work under the hood. I have also wanted to play around with transpiling in general and get a feel for outputting framework specific code targeting php and node. I know others have done some work in that area so there are examples to start with. The most interesting would be actual "graphic" based targets because that would dictate the requirements to be on par with any other CerberusX target. I think in that area I would be interested in possibly playing around with a specific Apple Watch target as a subset of core, within the confines of the Apple watchOS 4 capabilities.
 
THANK YOU!!! I have a C++ build system for Android, and I might be able reuse it to build a C++ based Android target. As a down the road type objective. The first thing that kept me from taking some game prototypes all the way as the Java version didn’t cut it performance wise.
 
Good to hear it is helpful. Out of curiosity what (very rough / guess) percentage increase are you getting with C++ vs Java?
 
I haven’t done Cerberus C++ Android yet, but I have seen apps run at 12fps built in Java vs same approach do easily 60fps in C++. Which comes down to CPU intense stuff like physics and sending GL draw commands to the GPU.
 
Really that much speed increase! I do feel Android is under powered. I remember having a double for loop for map and it crawled in Android. Other targets were alright. Anyway thanks for the info.
 
@nullterm I have a 3D engine that works in Monkey X. I wanted to look at Monkey 2 new 3D engine. I ended up porting my 3D engine to Monkey 2. So I had the ability to look at Android in Java (Monkey X) and Android in C++ (via NDK in Monkey 2).

This is using roughly the same code, but some code is different, like the main loop is different. I also notice in Monkey 2 cubes are drawn more forward. I didn't want to waste time on it, so I just move it back using the translate matrix. Vertex shader and fragment shader codes are exactly 1 to 1.

The test is drawing 200 textured cubes on an Android device. Each cube is rotated, translated and the model view projection matrix is calculated. So that's where the Java vs C++ test, doing matrix calculation (lots of addition and multiplication). In Monkey X I am getting update FPS ~51 and render FPS ~21. And in Monkey 2 I am getting update FPS ~60 and render FPS ~15.

So from my experiment there is no performance gain.

I guess the advantage which Monkey 2 exploit is to use all the different C++ library like TTF fonts.
 
Back
Top Bottom