Tiny Thor (made with Monkey X)
Develop on Windows or OSX and deploy easily
Crypt of the Necrodancer (made with Monkey X)
New Star Soccer - BAFTA Winner 2013!!! (made with Monkey X )
Ted - The code editor of Cerberus X
Avalon Legends (made with Monkey X)
Race Time (made with Monkey X)

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

Ferdi Jul 14, 2017

  1. Ferdi

    Ferdi Member 3rd Party Target Dev

    Messages:
    68
    Likes Received:
    26
    Trophy Points:
    18
    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:

    Code (C++):
    1.  
    2. #include <stdio.h>
    3.  
    4. int main()
    5. {
    6.     printf("Hello World From C++\n");
    7.     return 0;
    8. }
    9.  
    And to compile it, the command is:

    Code (Text):
    1. g++ -o main main.cpp
    And use your favorite command line:

    Code (Text):
    1.  
    2. D:\devtools\hello>g++ -o main main.cpp
    3.  
    4. D:\devtools\hello>main
    5. Hello World From C++
    6.  
    7. D:\devtools\hello>
    8.  
    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 (Cerberus X):
    1.  
    2. Import xna
    3. Import hello
    4.  
    5. ...
    6.  
    7.     builders.Set "xna",New XnaBuilder( tcc )
    8.     builders.Set "hello",New HelloBuilder( tcc )
    9.  
    2b. Create src\transcc\builders\hello.cxs

    Code (Cerberus X):
    1.  
    2. Import builder
    3.  
    4. Class HelloBuilder Extends Builder
    5.  
    6.     Method New( tcc:TransCC )
    7.         Super.New( tcc )
    8.     End
    9.  
    10.     Method Config:String()
    11.         Local config:=New StringStack
    12.         For Local kv:=Eachin GetConfigVars()
    13.             config.Push "#define CFG_"+kv.Key+" "+kv.Value
    14.         Next
    15.         Return config.Join( "~n" )
    16.     End
    17.  
    18.     Method IsValid:Bool()
    19.         Select HostOS
    20.         Case "winnt"
    21.             If tcc.MINGW_PATH Return True
    22.         Default
    23.             Return True
    24.         End
    25.         Return False
    26.     End
    27.  
    28.     Method Begin:Void()
    29.         ENV_LANG="cpp"
    30.         _trans=New CppTranslator
    31.     End
    32.  
    33.     Method MakeTarget:Void()
    34.  
    35.         Local out:="main"
    36.         DeleteFile out
    37.  
    38.         Execute "g++ -o " + out + " main.cpp"
    39.  
    40.         If tcc.opt_run
    41.             Execute "~q" + RealPath( out ) + "~q"
    42.         Endif
    43.     End
    44. End
    45.  
    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 (Text):
    1.  
    2. transcc_winnt.exe -target=C++_Tool transcc.cxs
    3.  
    Here is my command lines:

    Code (Text):
    1.  
    2. D:\devtools\Cerberus\src\transcc>d:\devtools\Cerberus\bin\transcc_winnt.exe -taget=C++_Tool transcc.cxs
    3. TRANS cerberus compiler V2017-07-04
    4. Parsing...
    5. Semanting...
    6. Translating...
    7. Building...
    8.  
    9. D:\devtools\Cerberus\src\transcc>
    10.  
    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 (Text):
    1.  
    2. d:\devtools\Cerberus\bin\transcc_winnt.exe -target=C++_Tool transcc.cxs
    3. copy d:\devtools\Cerberus\src\transcc\transcc.buildv2017-07-04\cpptool\main_winnt.exe d:\devtools\Cerberus\bin\transcc_winnt.exe
    4. pause
    5.  
    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 (Cerberus X):
    1.  
    2. #TARGET_NAME="Hello Tool"
    3. #TARGET_SYSTEM="hello"
    4. #TARGET_BUILDER="hello"
    5.  
    Now if you run transcc_winnt.exe, you will see Hello_Tool as a valid target:

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

    Code (C++):
    1.  
    2. #include <stdio.h>
    3.  
    4. int main()
    5. {
    6.     printf("Hello World From C++\n");
    7.     return 0;
    8. }
    9.  
    3b. Creating and compiling hello.cxs

    Now open Ted and create hello.cxs:

    Code (Cerberus X):
    1.  
    2. Function Main()
    3.  
    4. End
    5.  
    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 (Cerberus X):
    1.  
    2. Function Main()
    3.     Print "Hello World From Cerberus"
    4. End
    5.  
    4b. targets\hello\template\main.cpp:

    Code (C++):
    1.  
    2. #include "main.h"
    3.  
    4. //${CONFIG_BEGIN}
    5. //${CONFIG_END}
    6.  
    7. //${TRANSCODE_BEGIN}
    8. //${TRANSCODE_END}
    9.  
    10. int main( int argc,const char **argv )
    11. {
    12.     bb_std_main( argc,argv );
    13. }
    14.  
    4c. targets\hello\template\main.h

    main.h is from cpptool:

    Code (C++):
    1.  
    2. //Lang/OS...
    3. #include <ctime>
    4. #include <cmath>
    5. #include <cctype>
    6. #include <cstdio>
    7. #include <cstdlib>
    8. #include <cstring>
    9. #include <vector>
    10. #include <typeinfo>
    11. #include <signal.h>
    12.  
    13. #if _WIN32
    14. #include <windows.h>
    15. #include <direct.h>
    16. #include <sys/stat.h>
    17. #undef LoadString
    18.  
    19. #elif __APPLE__
    20. #include <mach-o/dyld.h>
    21. #include <sys/stat.h>
    22. #include <dirent.h>
    23. #include <copyfile.h>
    24.  
    25. #elif __linux
    26. #include <unistd.h>
    27. #include <sys/stat.h>
    28. #include <dirent.h>
    29. #include <pthread.h>
    30. #endif
    31.  
    32. #define _QUOTE(X) #X
    33. #define _STRINGIZE( X ) _QUOTE(X)
    34.  
    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 (Cerberus X):
    1.  
    2.     Method MakeTarget:Void()
    3.  
    4.         ' This create main.cpp and put the Cerberus code in there.
    5.         Local main:=LoadString( "main.cpp" )
    6.         main=ReplaceBlock( main,"TRANSCODE",transCode )
    7.         main=ReplaceBlock( main,"CONFIG",Config() )
    8.         SaveString main,"main.cpp"
    9.  
    10.         Local out:="main"
    11.         DeleteFile out
    12.  
    13.         Execute "g++ -o " + out + " main.cpp"
    14.  
    15.         If tcc.opt_run
    16.             Execute "~q" + RealPath( out ) + "~q"
    17.         Endif
    18.     End
    19.  
    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: Jul 17, 2017
    Martin and MikeHart like this.
  2. Martin

    Martin Administrator Administrator Moderator

    Messages:
    263
    Likes Received:
    147
    Trophy Points:
    43
    Thanks, very good tutorial, well written! :)
     
  3. AndyAndroid

    AndyAndroid New Member

    Messages:
    26
    Likes Received:
    8
    Trophy Points:
    3
    @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.
     
  4. MikeHart

    MikeHart Administrator Staff Member Administrator Moderator

    Messages:
    1,237
    Likes Received:
    300
    Trophy Points:
    83
  5. AndyAndroid

    AndyAndroid New Member

    Messages:
    26
    Likes Received:
    8
    Trophy Points:
    3
    @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!
     
    MikeHart likes this.
  6. MikeHart

    MikeHart Administrator Staff Member Administrator Moderator

    Messages:
    1,237
    Likes Received:
    300
    Trophy Points:
    83
    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.
     
  7. Ferdi

    Ferdi Member 3rd Party Target Dev

    Messages:
    68
    Likes Received:
    26
    Trophy Points:
    18
    @MikeHart Cool!! I love the dark theme. And I love the code highlighting.

    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.

    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.

    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?
     
  8. AndyAndroid

    AndyAndroid New Member

    Messages:
    26
    Likes Received:
    8
    Trophy Points:
    3
    @Ferdi thanks for the additional information and general use case approach.
    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.
     
    MikeHart likes this.
  9. nullterm

    nullterm New Member

    Messages:
    20
    Likes Received:
    16
    Trophy Points:
    3
    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.
     
  10. Ferdi

    Ferdi Member 3rd Party Target Dev

    Messages:
    68
    Likes Received:
    26
    Trophy Points:
    18
    Good to hear it is helpful. Out of curiosity what (very rough / guess) percentage increase are you getting with C++ vs Java?
     
  11. nullterm

    nullterm New Member

    Messages:
    20
    Likes Received:
    16
    Trophy Points:
    3
    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.
     
  12. Ferdi

    Ferdi Member 3rd Party Target Dev

    Messages:
    68
    Likes Received:
    26
    Trophy Points:
    18
    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.
     
  13. Ferdi

    Ferdi Member 3rd Party Target Dev

    Messages:
    68
    Likes Received:
    26
    Trophy Points:
    18
    @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.