diff --git a/cjit/404.html b/cjit/404.html index af5c76f..d6d3aeb 100644 --- a/cjit/404.html +++ b/cjit/404.html @@ -220,11 +220,11 @@
The (miniaudio.h)[https://miniaud.io] built-in handles audio playback +
The miniaudio built-in handles audio playback and capture with ease. With this extension, you can seamlessly integrate audio functionality into your C scripts, creating immersive and interactive experiences for your users.
-Miniaudio provides two main sources of documentation -- A Programmer's manual -- Various examples
-Its full API reference is a work in progress. Miniaudio includes both -low level and high level APIs. The low level API is good for those who -want to do all of their mixing themselves and only require a light -weight interface to the underlying audio device. The high level API is -good for those who have complex mixing and effect requirements.
+Miniaudio provides two main sources of documentation
+ +Miniaudio includes both low level and high level APIs. The low level +API is good for those who want to do all of their mixing themselves +and only require a light weight interface to the underlying audio +device. The high level API is good for those who have complex mixing +and effect requirements.
In miniaudio, objects are transparent structures. Unlike many other libraries, there are no handles to opaque objects which means you need to allocate memory for objects yourself.
@@ -473,13 +497,16 @@Believe it or not, one can draw a beautiful terminal user interface
+(also called TUI) on a text console, with colors and blinking lights
+too. Our built-in termbox2
+allows this in an API that improves a lot on old approaches as ncurses
+or slang, by sucking much less :^)
Here is a quick synopsis:
+#define TB_IMPL
+#include "termbox2.h"
+
+int main(int argc, char **argv) {
+ struct tb_event ev;
+ int y = 0;
+
+ tb_init();
+
+ tb_printf(0, y++, TB_GREEN, 0, "hello from termbox");
+ tb_printf(0, y++, 0, 0, "width=%d height=%d",
+ tb_width(), tb_height());
+ tb_printf(0, y++, 0, 0, "press any key...");
+ tb_present();
+
+ tb_poll_event(&ev);
+
+ y++;
+ tb_printf(0, y++, 0, 0, "event type=%d key=%d ch=%c",
+ ev.type, ev.key, ev.ch);
+ tb_printf(0, y++, 0, 0, "press any key to quit...");
+ tb_present();
+
+ tb_poll_event(&ev);
+ tb_shutdown();
+
+ return 0;
+}
+
The termbox2 basic API is self explanatory:
+int tb_init();
+int tb_shutdown();
+
+int tb_width();
+int tb_height();
+
+int tb_clear();
+int tb_present();
+
+int tb_set_cursor(int cx, int cy);
+int tb_hide_cursor();
+
+int tb_set_cell(int x, int y, uint32_t ch,
+ uintattr_t fg, uintattr_t bg);
+
+int tb_peek_event(struct tb_event *event,
+ int timeout_ms);
+int tb_poll_event(struct tb_event *event);
+
+int tb_print(int x, int y,
+ uintattr_t fg, uintattr_t bg,
+ const char *str);
+int tb_printf(int x, int y,
+ uintattr_t fg, uintattr_t bg,
+ const char *fmt, ...);
+
To see a demo of what it can do, see the +examples/termbox.c +example which will draw a keyboard on your terminal and show the keys +you are pressing in real-time. Its code is a great source of knowledge +about what termbox2 can do!
diff --git a/cjit/faq/index.html b/cjit/faq/index.html index 8365d84..1e33846 100644 --- a/cjit/faq/index.html +++ b/cjit/faq/index.html @@ -11,11 +11,9 @@ - + - - @@ -228,6 +226,26 @@ + + +CJIT is a versatile C interpreter based on TinyCC, designed to compile C code in-memory and execute it live. This manual serves as a guide to the full potential of CJIT, empowering you to efficiently develop and test C programs in real-time.
CJIT is distributed as a small, all-in-one executable, ensuring a lightweight and portable solution for your coding needs. One of its standout features is the ability to call functions from any installed library, making it a robust tool for rapid prototyping and dynamic code execution on Linux, Windows, and macOS. \ud83d\udda5\ufe0f
The following sections will guide you through practical usage examples, helping you to swiftly integrate CJIT into your workflow. \ud83d\udcda\ud83d\udd27
"},{"location":"#hello-world","title":"Hello World!","text":"This classic example will make you create a hello.c
file and execute it with CJIT to print the string \"Hello World!\" in the terminal.
Please chose the right example code using tabs: MS/Windows, Apple/OSX or GNU/Linux
Info
All Windows based examples are made for the PowerShell terminal, if you are on WSL then chose GNU/Linux
Download CJIT pasting a command in the terminal
MS/WindowsApple/OSXGNU/LinuxInvoke-WebRequest -OutFile \"cjit.exe\" -Uri \"https://github.com/dyne/cjit/releases/latest/download/cjit.exe\"\n
curl -sLo cjit https://github.com/dyne/cjit/releases/latest/download/cjit-$(uname)-$(uname -m)\n
curl -sLo cjit https://github.com/dyne/cjit/releases/latest/download/cjit-$(uname)-$(uname -m)\n
Then create hello.c by pasting these lines in the terminal:
MS/WindowsApple/OSXGNU/Linux@\"\n#include <stdio.h>\n#include <stdlib.h>\nint main(int argc, char **argv) {\n fprintf(stderr,\"Hello, World!\\n\");\n exit(0);\n}\n\"@| Out-File -FilePath \"hello.c\" -Encoding ASCII\n
cat << EOF > hello.c\n#!/usr/bin/env cjit\n#include <stdio.h>\n#include <stdlib.h>\nint main(int argc, char **argv) {\n fprintf(stderr,\"Hello, World!\\n\");\n exit(0);\n}\nEOF\n
cat << EOF > hello.c\n#!/usr/bin/env cjit\n#include <stdio.h>\n#include <stdlib.h>\nint main(int argc, char **argv) {\n fprintf(stderr,\"Hello, World!\\n\");\n exit(0);\n}\nEOF\n
Finally execute hello.c using CJIT with:
MS/WindowsApple/OSXGNU/Linux.\\cjit.exe .\\hello.c\n
./cjit hello.c\n
./cjit hello.c\n
As a result you will see CJIT starting and printing \"Hello World!\"
CJIT v0.8.12 by Dyne.org\nSource code:\n+ .\\hello.c\nExecution start\n---\nHello, World!\n
You can now play with hello.c
, change what you want and run it again!
Warning
When using a Windows Terminal configured in a language that is not English, beware it may be set to UTF-16: this will break the example code pasted from clipboard. Switch the terminal to UTF-8 encoding.
"},{"location":"#flying-donuts","title":"Flying Donuts","text":"This example will print an animated donut on the terminal!
Create the donut.c
file using the artful code below:
@\"\n i,j,k,x,y,o,N;\n main(){float z[1760],a\n #define R(t,x,y) f=x;x-=t*y\\\n ;y+=t*f;f=(3-x*x-y*y)/2;x*=f;y*=f;\n =0,e=1,c=1,d=0,f,g,h,G,H,A,t,D;char\n b[1760];for(;;){memset(b,32,1760);g=0,\nh=1;memset(z,0,7040);for(j=0;j<90;j++){\nG=0,H=1;for(i=0;i<314;i++){A=h+2,D=1/(G*\nA*a+g*e+5);t=G*A *e-g*a;x=40+30*D\n*(H*A*d-t*c);y= 12+15*D*(H*A*c+\nt*d);o=x+80*y;N =8*((g*a-G*h*e)\n*d-G*h*a-g*e-H*h *c);if(22>y&&y>\n 0&&x>0&&80>x&&D>z[o]){z[o]=D;b[o]=(N>0\n ?N:0)[\".,-~:;=!*#$@\"];}R(.02,H,G);}R(\n .07,h,g);}for(k=0;1761>k;k++)putchar\n (k%80?b[k]:10);R(.04,e,a);R(.02,d,\n c);usleep(15000);printf('\\n'+(\n \" donut.c! \\x1b[23A\"));}}\n /*no math lib needed\n .@a1k0n 2021.*/\n\"@| Out-File -FilePath \"donut.c\" -Encoding ASCII\n
cat << EOF > donut.c\n i,j,k,x,y,o,N;\n main(){float z[1760],a\n #define R(t,x,y) f=x;x-=t*y\\\n ;y+=t*f;f=(3-x*x-y*y)/2;x*=f;y*=f;\n =0,e=1,c=1,d=0,f,g,h,G,H,A,t,D;char\n b[1760];for(;;){memset(b,32,1760);g=0,\nh=1;memset(z,0,7040);for(j=0;j<90;j++){\nG=0,H=1;for(i=0;i<314;i++){A=h+2,D=1/(G*\nA*a+g*e+5);t=G*A *e-g*a;x=40+30*D\n*(H*A*d-t*c);y= 12+15*D*(H*A*c+\nt*d);o=x+80*y;N =8*((g*a-G*h*e)\n*d-G*h*a-g*e-H*h *c);if(22>y&&y>\n 0&&x>0&&80>x&&D>z[o]){z[o]=D;b[o]=(N>0\n ?N:0)[\".,-~:;=!*#$@\"];}R(.02,H,G);}R(\n .07,h,g);}for(k=0;1761>k;k++)putchar\n (k%80?b[k]:10);R(.04,e,a);R(.02,d,\n c);usleep(15000);printf('\\n'+(\n \" donut.c! \\x1b[23A\"));}}\n /*no math lib needed\n .@a1k0n 2021.*/\nEOF\n
cat << EOF > donut.c\n i,j,k,x,y,o,N;\n main(){float z[1760],a\n #define R(t,x,y) f=x;x-=t*y\\\n ;y+=t*f;f=(3-x*x-y*y)/2;x*=f;y*=f;\n =0,e=1,c=1,d=0,f,g,h,G,H,A,t,D;char\n b[1760];for(;;){memset(b,32,1760);g=0,\nh=1;memset(z,0,7040);for(j=0;j<90;j++){\nG=0,H=1;for(i=0;i<314;i++){A=h+2,D=1/(G*\nA*a+g*e+5);t=G*A *e-g*a;x=40+30*D\n*(H*A*d-t*c);y= 12+15*D*(H*A*c+\nt*d);o=x+80*y;N =8*((g*a-G*h*e)\n*d-G*h*a-g*e-H*h *c);if(22>y&&y>\n 0&&x>0&&80>x&&D>z[o]){z[o]=D;b[o]=(N>0\n ?N:0)[\".,-~:;=!*#$@\"];}R(.02,H,G);}R(\n .07,h,g);}for(k=0;1761>k;k++)putchar\n (k%80?b[k]:10);R(.04,e,a);R(.02,d,\n c);usleep(15000);printf('\\n'+(\n \" donut.c! \\x1b[23A\"));}}\n /*no math lib needed\n .@a1k0n 2021.*/\nEOF\n
Then make the donut fly with CJIT!
MS/WindowsApple/OSXGNU/Linux.\\cjit.exe .\\donut.c\n
./cjit donut.c\n
./cjit donut.c\n
Warning
With this example and other programs, just hit CTRL+C to quit.
The state of affairs in CJIT is well demonstrated by this example: right now the terminal is much slower on windows (rightmost donut).
"},{"location":"#game-of-life","title":"Game of Life","text":"Anothre fascinating example is the \"Game of Life,\" a cellular automaton devised by the British mathematician John Horton Conway in 1970. This zero-player game simulates the evolution of a grid of cells, showcasing complex behaviors emerging from simple rules.
Download the life.c
example pasting a command in the terminal
Invoke-WebRequest -OutFile \"life.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/life.c\" -Encoding ASCII\n
curl -sLo life.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/life.c\n
curl -sLo life.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/life.c\n
Then execute the life.c
source file passing it as argument to cjit
, the same way it was done for the flying donut.
Pretty cool stuff for some \"boring\" terminal session eh? Have a look around the life.c
file with your favorite text editor and feel free to change things and see what happens.
Now you are familiar with the way to execute CJIT! If you think that C is fun (and fast!) you are welcome to read the next chapter of this manual and discover one of many ways to run graphical applications.
"},{"location":"builtins/","title":"CJIT built-in extensions","text":"CJIT is equipped with a range of built-in extensions designed to enhance the capabilities of your C scripts. These extensions allow you to perform a variety of operations easily and efficiently, adding a layer of versatility to your coding experience. Whether you're manipulating data, handling complex computations, accessing 3D acceleration or drawing on the terminal or monitoring filesystem changes, our built-ins extensions provide additional function calls to make your scripting both powerful and fun.
Our selection of extension is guided by a choice of minimalism and portability. Below you'll see a list of what we ship and link to respective vendors.
"},{"location":"builtins/#filesystem-monitoring","title":"Filesystem monitoring","text":"The dmon built-in is designed for monitoring changes in the filesystem. This extension simplifies the process of tracking file modifications, deletions, and creations, allowing you to respond to these events in real time within your C scripts.
Here and in examples/dmon.c is some example code working on all platforms:
#include <stdio.h>\n#include <dmon.h>\n\nstatic void watch_callback(dmon_watch_id watch_id,\n dmon_action action,\n const char* rootdir,\n const char* filepath,\n const char* oldfilepath,\n void* user) {\n (void)(user);\n (void)(watch_id);\n switch (action) {\n case DMON_ACTION_CREATE:\n fprintf(stderr,\"CREATE: [%s]%s\\n\", rootdir, filepath);\n break;\n case DMON_ACTION_DELETE:\n fprintf(stderr,\"DELETE: [%s]%s\\n\", rootdir, filepath);\n break;\n case DMON_ACTION_MODIFY:\n fprintf(stderr,\"MODIFY: [%s]%s\\n\", rootdir, filepath);\n break;\n case DMON_ACTION_MOVE:\n fprintf(stderr,\"MOVE: [%s]%s -> [%s]%s\\n\", rootdir, oldfilepath, rootdir, filepath);\n break;\n }\n}\n\nint main(int argc, char* argv[]) {\n if (argc > 1) {\n dmon_init();\n puts(\"waiting for changes ..\");\n dmon_watch(argv[1], watch_callback, DMON_WATCHFLAGS_RECURSIVE, NULL);\n getchar();\n dmon_deinit();\n } else {\n puts(\"usage: test dirname\");\n }\n return 0;\n}\n
"},{"location":"builtins/#audio-playback-and-recording","title":"Audio playback and recording","text":"The (miniaudio.h)[https://miniaud.io] built-in handles audio playback and capture with ease. With this extension, you can seamlessly integrate audio functionality into your C scripts, creating immersive and interactive experiences for your users.
Miniaudio provides two main sources of documentation - A Programmer's manual - Various examples
Its full API reference is a work in progress. Miniaudio includes both low level and high level APIs. The low level API is good for those who want to do all of their mixing themselves and only require a light weight interface to the underlying audio device. The high level API is good for those who have complex mixing and effect requirements.
In miniaudio, objects are transparent structures. Unlike many other libraries, there are no handles to opaque objects which means you need to allocate memory for objects yourself.
A config/init pattern is used throughout the entire library. The idea is that you set up a config object and pass that into the initialization routine. The advantage to this system is that the config object can be initialized with logical defaults and new properties added to it without breaking the API.
Below and in examples/miniaudio.c is an example of sin wave synthesis that runs smoothly in CJIT:
#define MA_NO_DECODING\n#define MA_NO_ENCODING\n#define MINIAUDIO_IMPLEMENTATION\n#include <miniaudio.h>\n#include <stdio.h>\n#define DEVICE_FORMAT ma_format_f32\n#define DEVICE_CHANNELS 2\n#define DEVICE_SAMPLE_RATE 48000\n\nvoid data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) {\n ma_waveform* pSineWave;\n MA_ASSERT(pDevice->playback.channels == DEVICE_CHANNELS);\n pSineWave = (ma_waveform*)pDevice->pUserData;\n MA_ASSERT(pSineWave != NULL);\n ma_waveform_read_pcm_frames(pSineWave, pOutput, frameCount, NULL);\n (void)pInput; /* Unused. */\n}\n\nint main(int argc, char** argv) {\n ma_waveform sineWave;\n ma_device_config deviceConfig;\n ma_device device;\n ma_waveform_config sineWaveConfig;\n deviceConfig = ma_device_config_init(ma_device_type_playback);\n deviceConfig.playback.format = DEVICE_FORMAT;\n deviceConfig.playback.channels = DEVICE_CHANNELS;\n deviceConfig.sampleRate = DEVICE_SAMPLE_RATE;\n deviceConfig.dataCallback = data_callback;\n deviceConfig.pUserData = &sineWave;\n if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) {\n printf(\"Failed to open playback device.\\n\");\n return -4;\n }\n printf(\"Device Name: %s\\n\", device.playback.name);\n sineWaveConfig = ma_waveform_config_init(device.playback.format,\n device.playback.channels,\n device.sampleRate,\n ma_waveform_type_sine,\n 0.2, 220);\n ma_waveform_init(&sineWaveConfig, &sineWave);\n if (ma_device_start(&device) != MA_SUCCESS) {\n printf(\"Failed to start playback device.\\n\");\n ma_device_uninit(&device);\n return -5;\n }\n printf(\"Press Enter to quit...\\n\");\n getchar();\n ma_device_uninit(&device);\n (void)argc;\n (void)argv;\n return 0;\n}\n
"},{"location":"faq/","title":"Frequently Asked Questions about CJIT","text":"Here we try to answer the most asked questions.
"},{"location":"faq/#whats-different-between-tcc-run-and-cjit","title":"What's different betweentcc -run
and CJIT?","text":"The main difference is in usability.
CJIT improves three main UX aspects for now:
It works as a single executable file which embeds the TinyCC compiler, all its headers and its standard library. This way there is no need to install anything system wide, check paths and setup build folders.
It supports adding multiple files into one execution: can accept wildcards to ingest anything that is a C source, a pre-compiled object or a shared library. The symbols exported by each file will be visible to all during the same execution.
It finds automatically common system libraries for each target platform, avoiding the need to repeat these settings and look for the right paths.
We are happy to further the improve developer experience with CJIT, and your advice is welcome: open an issue!
"},{"location":"faq/#whats-different-between-libgccjit-and-cjit","title":"What's different betweenlibgccjit
and CJIT?","text":"CJIT is built as an command-line interpreter using the TinyCC backend for in-memory compilation. In the future it may also offer libgccjit
as backend, as long as it will be possible to embed it all inside a single executable file, which is a core feature of CJIT's vision for developer experience.
Detailed licensing information for CJIT is in the REUSE metadata file. We check correctness of these attributions at every single commit.
All CJIT's original code is licensed using GNU GPL v3 and will be updated to use future versions of this license published by the Free Software Foundation. All included licenses are compatible with this.
We grant to everyone the freedome to use, study, modify, and redistribute modifications of CJIT as long as such modifications are licensed with one of the licenses already present: MIT, GPL or LGPL.
"},{"location":"faq/#where-to-i-send-my-corrections-to-this-documentation","title":"Where to I send my corrections to this documentation?","text":"You are welcome to open an issue or a PR to the dyne/docs project.
The source of the CJIT manual is in the markdown formatted files in src/cjit/docs
inside the repository.
You are welcome to interact in public with Dyne.org hackers over any of our channels and social network acconts.
If you prefer to interact privately, write a mail to info@dyne.org.
"},{"location":"graphics/","title":"CJIT for graphical applications","text":"Be welcome to the exciting world of graphical C applications using SDL (Simple DirectMedia Layer). SDL, originally developed by Sam Lantinga in 1998, is a powerful, cross-platform library designed to provide low-level access to audio, keyboard, mouse, and graphics hardware via OpenGL and Direct3D. It is an ideal choice of free and open source library to create graphical applications that run seamlessly across different operating systems.
Whether you're developing games, simulations, or interactive tools, the combination of CJIT's simplicity in C code execution and SDL's cross-platform capabilities offers a solution for your graphical application needs.
As in the previous chapter, the following sections will guide you through practical usage examples, demonstrating how to create graphical applications. \ud83c\udf1f\ud83d\udcda
"},{"location":"graphics/#the-beauty-of-random","title":"The Beauty of Random","text":"First download SDL for your platform. In Windows we download and extract a zip archive, on other system we install the latest SDL from package managers.
MS/WindowsApple/OSXGNU/LinuxInvoke-WebRequest -Outfile SDL2-devel.zip -Uri https://github.com/libsdl-org/SDL/releases/download/release-2.30.9/SDL2-devel-2.30.9-mingw.zip\nunzip SDL2-devel.zip\n
brew install sdl2\n
sudo apt-get install libsdl2-dev\n
Then download the sdl2_noise.c example:
MS/WindowsApple/OSXGNU/LinuxInvoke-WebRequest -OutFile \"sdl2_noise.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/sdl2_noise.c\" -Encoding ASCII\n
curl -sLo sdl2_noise.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/sdl2_noise.c\n
curl -sLo sdl2_noise.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/sdl2_noise.c\n
Then as usual execute it passing the source file as argument to CJIT. Since we are calling functions shared by a library, we'll add some extra parameters:
MS/WindowsApple/OSXGNU/Linux.\\cjit.exe .\\sdl2_noise.c -I.\\SDL2-2.30.9\\x86_64-w64-mingw32\\include\\ -L.\\SDL2-2.30.9\\x86_64-w64-mingw32\\bin\\\n
./cjit ./sdl2_noise.c -lSDL2\n
./cjit ./sdl2_noise.c -lSDL2\n
Info
This preview looks blurred because video compression cannot deal well with randomness.
Have a look inside sdl2_noise.c, and at the beginning of the file you'll see some particular lines of code worth explaining:
"},{"location":"graphics/#the-hashbang","title":"The \"hashbang\"","text":"#!/usr/bin/env cjit\n
This line indicates that the source file is a script that can be executed using the cjit
interpreter when the executable bit is enabled and if the CJIT interpreter is found in PATH.
Warning
The hashbang works only on Apple/OSX and GNU/Linux, where any file can be made executable with chmod +x
#pragma comment(lib, \"SDL2\")\n
This line tells CJIT to link the SDL2
shared library (the one installed on the system or found inside an -L
path) and allows the source code to call functions provided by it. It is the equivaled of -lSDL2
on the commandline, with the only difference that it can be specified inside the source code.
Info
For Windows this means to look for SDL2.dll
in a path indicated by -L
. Another way to link libraries in Windows is to copy the dll
files inside the same folder of the source code and add their filename to the list of arguments.
#define SDL_DISABLE_IMMINTRIN_H 1\n#define SDL_MAIN_HANDLED 1\n
These lines tell SDL to disable some functionalities that break CJIT's execution. Without them defined before the #include <SDL2/SDL.h>
line Windows applications will crash.
To draw accelerated graphics and 3D objects we'll use OpenGL, short for Open Graphics Library: this is a cross-language, cross-platform API for rendering 2D and 3D vector graphics. Originally developed by Silicon Graphics Inc. (SGI) in 1992, OpenGL has become a widely adopted standard in the graphics industry.
Combining OpenGL with CJIT enables you to take full advantage of GPU accelerated graphics rendering while leveraging the dynamic capabilities of in-memory C code compilation, to swiftly prototype and test graphics-intensive applications.
Here is how to do it. First make sure you have OpenGL on your system: Windows users don't need to worry, it is there already.
MS/WindowsApple/OSXGNU/LinuxNothing to do.
Not sure (help testing this please!)
sudo apt-get install libopengl-dev\n
Then download the opengl.c example we ship in CJIT, adapted from this awesome opengl+SDL2 tutorial by Andrew Dailey.
MS/WindowsApple/OSXGNU/LinuxInvoke-WebRequest -OutFile \"opengl.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/opengl.c\" -Encoding ASCII\n
curl -sLo opengl.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/opengl.c\n
curl -sLo opengl.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/opengl.c\n
And execute it as usual, giving the opengl.c
file name as argument to CJIT. In case of windows you'll have to include also the path to the SDL2 library which was used in the previous example:
.\\cjit.exe ./opengl.c -DWINDOWS -I .\\SDL2-2.30.9\\x86_64-w64-mingw32\\include\\ -L.\\SDL2-2.30.9\\x86_64-w64-mingw32\\bin\n
./cjit ./opengl.c\n
./cjit ./opengl.c\n
Let's have a quick look at what is happening here: please note the -DWINDOWS
execution flag we use for Windows. Then look at the opengl.c
code:
// Taken from https://github.com/theandrew168/sdl2-opengl-demo\n//\n// Copyright (c) 2020 Andrew Dailey\n//\n// Slightly modified to be one-file and work in CJIT by Jaromil\n//\n// MIT License\n//\n// Tutorial explanation:\n// https://shallowbrooksoftware.com/posts/a-multi-platform-modern-opengl-demo-with-sdl2/\n\n#pragma comment(lib, \"SDL2\")\n\n#ifdef WINDOWS\n#pragma comment(lib, \"opengl32\")\n#elif LINUX\n#pragma comment(lib, \"OpenGL\")\n#else\n#pragma comment(lib, \"OpenGL\")\n#endif\n
Below the well deserved credits for this example there are different ways to link the OpenGL library, because the library file is named differently on different platforms. We solve the problem by using a #define
macro with symbol WINDOWS
to branch over a different #pragma
directive chosing the case-sensitive name of the library.
To understand the rest of the code make sure to read the multi-platform-modern-opengl-demo-with-sdl2 tutorial.
"},{"location":"graphics/#nuklear-widgets","title":"Nuklear widgets","text":"Nuklear is a minimal, immediate-mode graphical user interface toolkit written in ANSI C and licensed under public domain. It is designed to be lightweight and highly customizable, making it an ideal choice for developing user interfaces across different platforms.
With Nuklear, you can easily create a comprehensive set of widgets to enhance user experience (UX) in your applications. The library provides a wide range of components, including buttons, sliders, text input fields, and more, all of which can be integrated seamlessly with CJIT. This combination allows for rapid prototyping and real-time adjustments, fostering a dynamic development process.
Nuklear's simplicity and flexibility make it the perfect companion for CJIT, enabling you to design and implement intuitive and visually appealing interfaces that run consistently on GNU/Linux, MS/Windows, and Apple/OSX.
Let's dive in and discover how to create powerful and responsive interfaces with ease! \ud83c\udfa8\ud83d\udee0\ufe0f
The nuklear.h header is all what you need, download it together with CJIT's example source code.
MS/WindowsApple/OSXGNU/LinuxInvoke-WebRequest -OutFile \"nuklear.h\" -Uri \"https://raw.githubusercontent.com/Immediate-Mode-UI/Nuklear/refs/heads/master/nuklear.h\" -Encoding ASCII\nInvoke-WebRequest -OutFile \"nuklear.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear.c\" -Encoding ASCII\nmkdir nuklear\nInvoke-WebRequest -OutFile \"nuklear/calculator.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/calculator.c\" -Encoding ASCII\nInvoke-WebRequest -OutFile \"nuklear/canvas.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/canvas.c\" -Encoding ASCII\nInvoke-WebRequest -OutFile \"nuklear/node_editor.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/node_editor.c\" -Encoding ASCII\nInvoke-WebRequest -OutFile \"nuklear/overview.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/overview.c\" -Encoding ASCII\nInvoke-WebRequest -OutFile \"nuklear/style.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/style.c\" -Encoding ASCII\n
curl -sLo nuklear.h https://raw.githubusercontent.com/Immediate-Mode-UI/Nuklear/refs/heads/master/nuklear.h\ncurl -sLo nuklear.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear.c\nmkdir -p nuklear\ncurl -sLo nuklear/calculator.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/calculator.c\ncurl -sLo nuklear/canvas.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/canvas.c\ncurl -sLo nuklear/node_editor.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/node_editor.c\ncurl -sLo nuklear/overview.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/overview.c\ncurl -sLo nuklear/style.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/style.c\n
curl -sLo nuklear.h https://raw.githubusercontent.com/Immediate-Mode-UI/Nuklear/refs/heads/master/nuklear.h\ncurl -sLo nuklear.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear.c\nmkdir -p nuklear\ncurl -sLo nuklear/calculator.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/calculator.c\ncurl -sLo nuklear/canvas.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/canvas.c\ncurl -sLo nuklear/node_editor.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/node_editor.c\ncurl -sLo nuklear/overview.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/overview.c\ncurl -sLo nuklear/style.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/style.c\n
This will create a small directory structure with all the source code files needed for our example:
.\n\u251c\u2500\u2500 nuklear\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 calculator.c\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 canvas.c\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 node_editor.c\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 overview.c\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 style.c\n\u251c\u2500\u2500 nuklear.c\n\u2514\u2500\u2500 nuklear.h\n
In this multiple file setup we have the main code of our example which is nuklear.c call one or more example modules according to define flags. By default it will just start all modules, see around line 390:
/* ===============================================================\n *\n * EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n#define INCLUDE_ALL\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n #define INCLUDE_STYLE\n #define INCLUDE_CALCULATOR\n #define INCLUDE_CANVAS\n #define INCLUDE_OVERVIEW\n #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n #include \"nuklear/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n #include \"nuklear/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n #include \"nuklear/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n #include \"nuklear/overview.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n #include \"nuklear/node_editor.c\"\n#endif\n
Starting it up is simple as usual, this time we just need to add -I.
to tell CJIT it can look for headers in the current directory, so it will find nuklear.h
.\\cjit.exe ./nuklear.c -I. -I.\\SDL2-2.30.9\\x86_64-w64-mingw32\\include\\ -L.\\SDL2-2.30.9\\x86_64-w64-mingw32\\bin\n
./cjit ./nuklear.c -I.\n
./cjit ./nuklear.c -I.\n
And \ud83d\udca5Boom! enjoy Nuklear!
"},{"location":"graphics/#thats-all-for-now","title":"That's all for now!","text":"If you like this manual, give CJIt a star, let us know what you'd like to see next and consider making a donation to Dyne.org. Thanks!
"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Welcome to the CJIT Manual","text":"CJIT is a versatile C interpreter based on TinyCC, designed to compile C code in-memory and execute it live. This manual serves as a guide to the full potential of CJIT, empowering you to efficiently develop and test C programs in real-time.
CJIT is distributed as a small, all-in-one executable, ensuring a lightweight and portable solution for your coding needs. One of its standout features is the ability to call functions from any installed library, making it a robust tool for rapid prototyping and dynamic code execution on Linux, Windows, and macOS. \ud83d\udda5\ufe0f
The following sections will guide you through practical usage examples, helping you to swiftly integrate CJIT into your workflow. \ud83d\udcda\ud83d\udd27
"},{"location":"#hello-world","title":"Hello World!","text":"This classic example will make you create a hello.c
file and execute it with CJIT to print the string \"Hello World!\" in the terminal.
Please chose the right example code using tabs: MS/Windows, Apple/OSX or GNU/Linux
Info
All Windows based examples are made for the PowerShell terminal, if you are on WSL then chose GNU/Linux
Download CJIT pasting a command in the terminal
MS/WindowsApple/OSXGNU/LinuxInvoke-WebRequest -OutFile \"cjit.exe\" -Uri \"https://github.com/dyne/cjit/releases/latest/download/cjit.exe\"\n
curl -sLo cjit https://github.com/dyne/cjit/releases/latest/download/cjit-$(uname)-$(uname -m)\n
curl -sLo cjit https://github.com/dyne/cjit/releases/latest/download/cjit-$(uname)-$(uname -m)\n
Then create hello.c by pasting these lines in the terminal:
MS/WindowsApple/OSXGNU/Linux@\"\n#include <stdio.h>\n#include <stdlib.h>\nint main(int argc, char **argv) {\n fprintf(stderr,\"Hello, World!\\n\");\n exit(0);\n}\n\"@| Out-File -FilePath \"hello.c\" -Encoding ASCII\n
cat << EOF > hello.c\n#!/usr/bin/env cjit\n#include <stdio.h>\n#include <stdlib.h>\nint main(int argc, char **argv) {\n fprintf(stderr,\"Hello, World!\\n\");\n exit(0);\n}\nEOF\n
cat << EOF > hello.c\n#!/usr/bin/env cjit\n#include <stdio.h>\n#include <stdlib.h>\nint main(int argc, char **argv) {\n fprintf(stderr,\"Hello, World!\\n\");\n exit(0);\n}\nEOF\n
Finally execute hello.c using CJIT with:
MS/WindowsApple/OSXGNU/Linux.\\cjit.exe .\\hello.c\n
./cjit hello.c\n
./cjit hello.c\n
As a result you will see CJIT starting and printing \"Hello World!\"
CJIT v0.8.12 by Dyne.org\nSource code:\n+ .\\hello.c\nExecution start\n---\nHello, World!\n
You can now play with hello.c
, change what you want and run it again!
Warning
When using a Windows Terminal configured in a language that is not English, beware it may be set to UTF-16: this will break the example code pasted from clipboard. Switch the terminal to UTF-8 encoding.
"},{"location":"#flying-donuts","title":"Flying Donuts","text":"This example will print an animated donut on the terminal!
Create the donut.c
file using the artful code below:
@\"\n i,j,k,x,y,o,N;\n main(){float z[1760],a\n #define R(t,x,y) f=x;x-=t*y\\\n ;y+=t*f;f=(3-x*x-y*y)/2;x*=f;y*=f;\n =0,e=1,c=1,d=0,f,g,h,G,H,A,t,D;char\n b[1760];for(;;){memset(b,32,1760);g=0,\nh=1;memset(z,0,7040);for(j=0;j<90;j++){\nG=0,H=1;for(i=0;i<314;i++){A=h+2,D=1/(G*\nA*a+g*e+5);t=G*A *e-g*a;x=40+30*D\n*(H*A*d-t*c);y= 12+15*D*(H*A*c+\nt*d);o=x+80*y;N =8*((g*a-G*h*e)\n*d-G*h*a-g*e-H*h *c);if(22>y&&y>\n 0&&x>0&&80>x&&D>z[o]){z[o]=D;b[o]=(N>0\n ?N:0)[\".,-~:;=!*#$@\"];}R(.02,H,G);}R(\n .07,h,g);}for(k=0;1761>k;k++)putchar\n (k%80?b[k]:10);R(.04,e,a);R(.02,d,\n c);usleep(15000);printf('\\n'+(\n \" donut.c! \\x1b[23A\"));}}\n /*no math lib needed\n .@a1k0n 2021.*/\n\"@| Out-File -FilePath \"donut.c\" -Encoding ASCII\n
cat << EOF > donut.c\n i,j,k,x,y,o,N;\n main(){float z[1760],a\n #define R(t,x,y) f=x;x-=t*y\\\n ;y+=t*f;f=(3-x*x-y*y)/2;x*=f;y*=f;\n =0,e=1,c=1,d=0,f,g,h,G,H,A,t,D;char\n b[1760];for(;;){memset(b,32,1760);g=0,\nh=1;memset(z,0,7040);for(j=0;j<90;j++){\nG=0,H=1;for(i=0;i<314;i++){A=h+2,D=1/(G*\nA*a+g*e+5);t=G*A *e-g*a;x=40+30*D\n*(H*A*d-t*c);y= 12+15*D*(H*A*c+\nt*d);o=x+80*y;N =8*((g*a-G*h*e)\n*d-G*h*a-g*e-H*h *c);if(22>y&&y>\n 0&&x>0&&80>x&&D>z[o]){z[o]=D;b[o]=(N>0\n ?N:0)[\".,-~:;=!*#$@\"];}R(.02,H,G);}R(\n .07,h,g);}for(k=0;1761>k;k++)putchar\n (k%80?b[k]:10);R(.04,e,a);R(.02,d,\n c);usleep(15000);printf('\\n'+(\n \" donut.c! \\x1b[23A\"));}}\n /*no math lib needed\n .@a1k0n 2021.*/\nEOF\n
cat << EOF > donut.c\n i,j,k,x,y,o,N;\n main(){float z[1760],a\n #define R(t,x,y) f=x;x-=t*y\\\n ;y+=t*f;f=(3-x*x-y*y)/2;x*=f;y*=f;\n =0,e=1,c=1,d=0,f,g,h,G,H,A,t,D;char\n b[1760];for(;;){memset(b,32,1760);g=0,\nh=1;memset(z,0,7040);for(j=0;j<90;j++){\nG=0,H=1;for(i=0;i<314;i++){A=h+2,D=1/(G*\nA*a+g*e+5);t=G*A *e-g*a;x=40+30*D\n*(H*A*d-t*c);y= 12+15*D*(H*A*c+\nt*d);o=x+80*y;N =8*((g*a-G*h*e)\n*d-G*h*a-g*e-H*h *c);if(22>y&&y>\n 0&&x>0&&80>x&&D>z[o]){z[o]=D;b[o]=(N>0\n ?N:0)[\".,-~:;=!*#$@\"];}R(.02,H,G);}R(\n .07,h,g);}for(k=0;1761>k;k++)putchar\n (k%80?b[k]:10);R(.04,e,a);R(.02,d,\n c);usleep(15000);printf('\\n'+(\n \" donut.c! \\x1b[23A\"));}}\n /*no math lib needed\n .@a1k0n 2021.*/\nEOF\n
Then make the donut fly with CJIT!
MS/WindowsApple/OSXGNU/Linux.\\cjit.exe .\\donut.c\n
./cjit donut.c\n
./cjit donut.c\n
Warning
With this example and other programs, just hit CTRL+C to quit.
The state of affairs in CJIT is well demonstrated by this example: right now the terminal is much slower on windows (rightmost donut).
"},{"location":"#game-of-life","title":"Game of Life","text":"Anothre fascinating example is the \"Game of Life,\" a cellular automaton devised by the British mathematician John Horton Conway in 1970. This zero-player game simulates the evolution of a grid of cells, showcasing complex behaviors emerging from simple rules.
Download the life.c
example pasting a command in the terminal
Invoke-WebRequest -OutFile \"life.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/life.c\" -Encoding ASCII\n
curl -sLo life.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/life.c\n
curl -sLo life.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/life.c\n
Then execute the life.c
source file passing it as argument to cjit
, the same way it was done for the flying donut.
Pretty cool stuff for some \"boring\" terminal session eh? Have a look around the life.c
file with your favorite text editor and feel free to change things and see what happens.
Now you are familiar with the way to execute CJIT! If you think that C is fun (and fast!) you are welcome to read the next chapter of this manual and discover one of many ways to run graphical applications.
"},{"location":"builtins/","title":"CJIT built-in extensions","text":"CJIT is equipped with a range of built-in extensions designed to enhance the capabilities of your C scripts. These extensions allow you to perform a variety of operations easily and efficiently, adding a layer of versatility to your coding experience. Whether you're manipulating data, handling complex computations, accessing 3D acceleration or drawing on the terminal or monitoring filesystem changes, our built-ins extensions provide additional function calls to make your scripting both powerful and fun.
Our selection of extension is guided by a choice of minimalism and portability. Below you'll see a list of what we ship and link to respective vendors.
"},{"location":"builtins/#filesystem-monitoring","title":"Filesystem monitoring","text":"The dmon built-in is designed for monitoring changes in the filesystem. This extension simplifies the process of tracking file modifications, deletions, and creations, allowing you to respond to these events in real time within your C scripts.
Here and in examples/dmon.c is some example code working on all platforms:
#include <stdio.h>\n#include <dmon.h>\n\nstatic void watch_callback(dmon_watch_id watch_id,\n dmon_action action,\n const char* rootdir,\n const char* filepath,\n const char* oldfilepath,\n void* user) {\n (void)(user);\n (void)(watch_id);\n switch (action) {\n case DMON_ACTION_CREATE:\n fprintf(stderr,\"CREATE: [%s]%s\\n\", rootdir, filepath);\n break;\n case DMON_ACTION_DELETE:\n fprintf(stderr,\"DELETE: [%s]%s\\n\", rootdir, filepath);\n break;\n case DMON_ACTION_MODIFY:\n fprintf(stderr,\"MODIFY: [%s]%s\\n\", rootdir, filepath);\n break;\n case DMON_ACTION_MOVE:\n fprintf(stderr,\"MOVE: [%s]%s -> [%s]%s\\n\",\n rootdir, oldfilepath, rootdir, filepath);\n break;\n }\n}\n\nint main(int argc, char* argv[]) {\n if (argc > 1) {\n dmon_init();\n puts(\"waiting for changes ..\");\n dmon_watch(argv[1], watch_callback,\n DMON_WATCHFLAGS_RECURSIVE, NULL);\n getchar();\n dmon_deinit();\n } else {\n puts(\"usage: test dirname\");\n }\n return 0;\n}\n
"},{"location":"builtins/#audio-play-and-record","title":"Audio play and record","text":"The miniaudio built-in handles audio playback and capture with ease. With this extension, you can seamlessly integrate audio functionality into your C scripts, creating immersive and interactive experiences for your users.
Miniaudio provides two main sources of documentation
Miniaudio includes both low level and high level APIs. The low level API is good for those who want to do all of their mixing themselves and only require a light weight interface to the underlying audio device. The high level API is good for those who have complex mixing and effect requirements.
In miniaudio, objects are transparent structures. Unlike many other libraries, there are no handles to opaque objects which means you need to allocate memory for objects yourself.
A config/init pattern is used throughout the entire library. The idea is that you set up a config object and pass that into the initialization routine. The advantage to this system is that the config object can be initialized with logical defaults and new properties added to it without breaking the API.
Below and in examples/miniaudio.c is an example of sin wave synthesis that runs smoothly in CJIT:
#define MA_NO_DECODING\n#define MA_NO_ENCODING\n#define MINIAUDIO_IMPLEMENTATION\n#include <miniaudio.h>\n#include <stdio.h>\n#define DEVICE_FORMAT ma_format_f32\n#define DEVICE_CHANNELS 2\n#define DEVICE_SAMPLE_RATE 48000\n\nvoid data_callback(ma_device* pDevice,\n void* pOutput,\n const void* pInput,\n ma_uint32 frameCount) {\n ma_waveform* pSineWave;\n MA_ASSERT(pDevice->playback.channels == DEVICE_CHANNELS);\n pSineWave = (ma_waveform*)pDevice->pUserData;\n MA_ASSERT(pSineWave != NULL);\n ma_waveform_read_pcm_frames(pSineWave, pOutput, frameCount, NULL);\n (void)pInput; /* Unused in this example. */\n}\n\nint main(int argc, char** argv) {\n ma_waveform sineWave;\n ma_device_config deviceConfig;\n ma_device device;\n ma_waveform_config sineWaveConfig;\n deviceConfig = ma_device_config_init(ma_device_type_playback);\n deviceConfig.playback.format = DEVICE_FORMAT;\n deviceConfig.playback.channels = DEVICE_CHANNELS;\n deviceConfig.sampleRate = DEVICE_SAMPLE_RATE;\n deviceConfig.dataCallback = data_callback;\n deviceConfig.pUserData = &sineWave;\n if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) {\n printf(\"Failed to open playback device.\\n\");\n return -4;\n }\n printf(\"Device Name: %s\\n\", device.playback.name);\n sineWaveConfig = ma_waveform_config_init(device.playback.format,\n device.playback.channels,\n device.sampleRate,\n ma_waveform_type_sine,\n 0.2, 220);\n ma_waveform_init(&sineWaveConfig, &sineWave);\n if (ma_device_start(&device) != MA_SUCCESS) {\n printf(\"Failed to start playback device.\\n\");\n ma_device_uninit(&device);\n return -5;\n }\n printf(\"Press Enter to quit...\\n\");\n getchar();\n ma_device_uninit(&device);\n (void)argc;\n (void)argv;\n return 0;\n}\n
"},{"location":"builtins/#terminal-user-interface","title":"Terminal User Interface","text":"Believe it or not, one can draw a beautiful terminal user interface (also called TUI) on a text console, with colors and blinking lights too. Our built-in termbox2 allows this in an API that improves a lot on old approaches as ncurses or slang, by sucking much less :^)
Here is a quick synopsis:
#define TB_IMPL\n#include \"termbox2.h\"\n\nint main(int argc, char **argv) {\n struct tb_event ev;\n int y = 0;\n\n tb_init();\n\n tb_printf(0, y++, TB_GREEN, 0, \"hello from termbox\");\n tb_printf(0, y++, 0, 0, \"width=%d height=%d\",\n tb_width(), tb_height());\n tb_printf(0, y++, 0, 0, \"press any key...\");\n tb_present();\n\n tb_poll_event(&ev);\n\n y++;\n tb_printf(0, y++, 0, 0, \"event type=%d key=%d ch=%c\",\n ev.type, ev.key, ev.ch);\n tb_printf(0, y++, 0, 0, \"press any key to quit...\");\n tb_present();\n\n tb_poll_event(&ev);\n tb_shutdown();\n\n return 0;\n}\n
The termbox2 basic API is self explanatory:
int tb_init();\nint tb_shutdown();\n\nint tb_width();\nint tb_height();\n\nint tb_clear();\nint tb_present();\n\nint tb_set_cursor(int cx, int cy);\nint tb_hide_cursor();\n\nint tb_set_cell(int x, int y, uint32_t ch,\n uintattr_t fg, uintattr_t bg);\n\nint tb_peek_event(struct tb_event *event,\n int timeout_ms);\nint tb_poll_event(struct tb_event *event);\n\nint tb_print(int x, int y,\n uintattr_t fg, uintattr_t bg,\n const char *str);\nint tb_printf(int x, int y,\n uintattr_t fg, uintattr_t bg,\n const char *fmt, ...);\n
To see a demo of what it can do, see the examples/termbox.c example which will draw a keyboard on your terminal and show the keys you are pressing in real-time. Its code is a great source of knowledge about what termbox2 can do!
"},{"location":"faq/","title":"Frequently Asked Questions about CJIT","text":"Here we try to answer the most asked questions.
"},{"location":"faq/#whats-different-between-tcc-run-and-cjit","title":"What's different betweentcc -run
and CJIT?","text":"The main difference is in usability.
CJIT improves three main UX aspects for now:
It works as a single executable file which embeds the TinyCC compiler, all its headers and its standard library. This way there is no need to install anything system wide, check paths and setup build folders.
It supports adding multiple files into one execution: can accept wildcards to ingest anything that is a C source, a pre-compiled object or a shared library. The symbols exported by each file will be visible to all during the same execution.
It finds automatically common system libraries for each target platform, avoiding the need to repeat these settings and look for the right paths.
We are happy to further the improve developer experience with CJIT, and your advice is welcome: open an issue!
"},{"location":"faq/#whats-different-between-libgccjit-and-cjit","title":"What's different betweenlibgccjit
and CJIT?","text":"CJIT is built as an command-line interpreter using the TinyCC backend for in-memory compilation. In the future it may also offer libgccjit
as backend, as long as it will be possible to embed it all inside a single executable file, which is a core feature of CJIT's vision for developer experience.
Detailed licensing information for CJIT is in the REUSE metadata file. We check correctness of these attributions at every single commit.
All CJIT's original code is licensed using GNU GPL v3 and will be updated to use future versions of this license published by the Free Software Foundation. All included licenses are compatible with this.
We grant to everyone the freedome to use, study, modify, and redistribute modifications of CJIT as long as such modifications are licensed with one of the licenses already present: MIT, GPL or LGPL.
"},{"location":"faq/#where-to-i-send-my-corrections-to-this-documentation","title":"Where to I send my corrections to this documentation?","text":"You are welcome to open an issue or a PR to the dyne/docs project.
The source of the CJIT manual is in the markdown formatted files in src/cjit/docs
inside the repository.
You are welcome to interact in public with Dyne.org hackers over any of our channels and social network acconts.
If you prefer to interact privately, write a mail to info@dyne.org.
"},{"location":"graphics/","title":"CJIT for graphical applications","text":"Be welcome to the exciting world of graphical C applications using SDL (Simple DirectMedia Layer). SDL, originally developed by Sam Lantinga in 1998, is a powerful, cross-platform library designed to provide low-level access to audio, keyboard, mouse, and graphics hardware via OpenGL and Direct3D. It is an ideal choice of free and open source library to create graphical applications that run seamlessly across different operating systems.
Whether you're developing games, simulations, or interactive tools, the combination of CJIT's simplicity in C code execution and SDL's cross-platform capabilities offers a solution for your graphical application needs.
As in the previous chapter, the following sections will guide you through practical usage examples, demonstrating how to create graphical applications. \ud83c\udf1f\ud83d\udcda
"},{"location":"graphics/#the-beauty-of-random","title":"The Beauty of Random","text":"First download SDL for your platform. In Windows we download and extract a zip archive, on other system we install the latest SDL from package managers.
MS/WindowsApple/OSXGNU/LinuxInvoke-WebRequest -Outfile SDL2-devel.zip -Uri https://github.com/libsdl-org/SDL/releases/download/release-2.30.9/SDL2-devel-2.30.9-mingw.zip\nunzip SDL2-devel.zip\n
brew install sdl2\n
sudo apt-get install libsdl2-dev\n
Then download the sdl2_noise.c example:
MS/WindowsApple/OSXGNU/LinuxInvoke-WebRequest -OutFile \"sdl2_noise.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/sdl2_noise.c\" -Encoding ASCII\n
curl -sLo sdl2_noise.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/sdl2_noise.c\n
curl -sLo sdl2_noise.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/sdl2_noise.c\n
Then as usual execute it passing the source file as argument to CJIT. Since we are calling functions shared by a library, we'll add some extra parameters:
MS/WindowsApple/OSXGNU/Linux.\\cjit.exe .\\sdl2_noise.c -I.\\SDL2-2.30.9\\x86_64-w64-mingw32\\include\\ -L.\\SDL2-2.30.9\\x86_64-w64-mingw32\\bin\\\n
./cjit ./sdl2_noise.c -lSDL2\n
./cjit ./sdl2_noise.c -lSDL2\n
Info
This preview looks blurred because video compression cannot deal well with randomness.
Have a look inside sdl2_noise.c, and at the beginning of the file you'll see some particular lines of code worth explaining:
"},{"location":"graphics/#the-hashbang","title":"The \"hashbang\"","text":"#!/usr/bin/env cjit\n
This line indicates that the source file is a script that can be executed using the cjit
interpreter when the executable bit is enabled and if the CJIT interpreter is found in PATH.
Warning
The hashbang works only on Apple/OSX and GNU/Linux, where any file can be made executable with chmod +x
#pragma comment(lib, \"SDL2\")\n
This line tells CJIT to link the SDL2
shared library (the one installed on the system or found inside an -L
path) and allows the source code to call functions provided by it. It is the equivaled of -lSDL2
on the commandline, with the only difference that it can be specified inside the source code.
Info
For Windows this means to look for SDL2.dll
in a path indicated by -L
. Another way to link libraries in Windows is to copy the dll
files inside the same folder of the source code and add their filename to the list of arguments.
#define SDL_DISABLE_IMMINTRIN_H 1\n#define SDL_MAIN_HANDLED 1\n
These lines tell SDL to disable some functionalities that break CJIT's execution. Without them defined before the #include <SDL2/SDL.h>
line Windows applications will crash.
To draw accelerated graphics and 3D objects we'll use OpenGL, short for Open Graphics Library: this is a cross-language, cross-platform API for rendering 2D and 3D vector graphics. Originally developed by Silicon Graphics Inc. (SGI) in 1992, OpenGL has become a widely adopted standard in the graphics industry.
Combining OpenGL with CJIT enables you to take full advantage of GPU accelerated graphics rendering while leveraging the dynamic capabilities of in-memory C code compilation, to swiftly prototype and test graphics-intensive applications.
Here is how to do it. First make sure you have OpenGL on your system: Windows users don't need to worry, it is there already.
MS/WindowsApple/OSXGNU/LinuxNothing to do.
Not sure (help testing this please!)
sudo apt-get install libopengl-dev\n
Then download the opengl.c example we ship in CJIT, adapted from this awesome opengl+SDL2 tutorial by Andrew Dailey.
MS/WindowsApple/OSXGNU/LinuxInvoke-WebRequest -OutFile \"opengl.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/opengl.c\" -Encoding ASCII\n
curl -sLo opengl.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/opengl.c\n
curl -sLo opengl.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/opengl.c\n
And execute it as usual, giving the opengl.c
file name as argument to CJIT. In case of windows you'll have to include also the path to the SDL2 library which was used in the previous example:
.\\cjit.exe ./opengl.c -DWINDOWS -I .\\SDL2-2.30.9\\x86_64-w64-mingw32\\include\\ -L.\\SDL2-2.30.9\\x86_64-w64-mingw32\\bin\n
./cjit ./opengl.c\n
./cjit ./opengl.c\n
Let's have a quick look at what is happening here: please note the -DWINDOWS
execution flag we use for Windows. Then look at the opengl.c
code:
// Taken from https://github.com/theandrew168/sdl2-opengl-demo\n//\n// Copyright (c) 2020 Andrew Dailey\n//\n// Slightly modified to be one-file and work in CJIT by Jaromil\n//\n// MIT License\n//\n// Tutorial explanation:\n// https://shallowbrooksoftware.com/posts/a-multi-platform-modern-opengl-demo-with-sdl2/\n\n#pragma comment(lib, \"SDL2\")\n\n#ifdef WINDOWS\n#pragma comment(lib, \"opengl32\")\n#elif LINUX\n#pragma comment(lib, \"OpenGL\")\n#else\n#pragma comment(lib, \"OpenGL\")\n#endif\n
Below the well deserved credits for this example there are different ways to link the OpenGL library, because the library file is named differently on different platforms. We solve the problem by using a #define
macro with symbol WINDOWS
to branch over a different #pragma
directive chosing the case-sensitive name of the library.
To understand the rest of the code make sure to read the multi-platform-modern-opengl-demo-with-sdl2 tutorial.
"},{"location":"graphics/#nuklear-widgets","title":"Nuklear widgets","text":"Nuklear is a minimal, immediate-mode graphical user interface toolkit written in ANSI C and licensed under public domain. It is designed to be lightweight and highly customizable, making it an ideal choice for developing user interfaces across different platforms.
With Nuklear, you can easily create a comprehensive set of widgets to enhance user experience (UX) in your applications. The library provides a wide range of components, including buttons, sliders, text input fields, and more, all of which can be integrated seamlessly with CJIT. This combination allows for rapid prototyping and real-time adjustments, fostering a dynamic development process.
Nuklear's simplicity and flexibility make it the perfect companion for CJIT, enabling you to design and implement intuitive and visually appealing interfaces that run consistently on GNU/Linux, MS/Windows, and Apple/OSX.
Let's dive in and discover how to create powerful and responsive interfaces with ease! \ud83c\udfa8\ud83d\udee0\ufe0f
The nuklear.h header is all what you need, download it together with CJIT's example source code.
MS/WindowsApple/OSXGNU/LinuxInvoke-WebRequest -OutFile \"nuklear.h\" -Uri \"https://raw.githubusercontent.com/Immediate-Mode-UI/Nuklear/refs/heads/master/nuklear.h\" -Encoding ASCII\nInvoke-WebRequest -OutFile \"nuklear.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear.c\" -Encoding ASCII\nmkdir nuklear\nInvoke-WebRequest -OutFile \"nuklear/calculator.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/calculator.c\" -Encoding ASCII\nInvoke-WebRequest -OutFile \"nuklear/canvas.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/canvas.c\" -Encoding ASCII\nInvoke-WebRequest -OutFile \"nuklear/node_editor.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/node_editor.c\" -Encoding ASCII\nInvoke-WebRequest -OutFile \"nuklear/overview.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/overview.c\" -Encoding ASCII\nInvoke-WebRequest -OutFile \"nuklear/style.c\" -Uri \"https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/style.c\" -Encoding ASCII\n
curl -sLo nuklear.h https://raw.githubusercontent.com/Immediate-Mode-UI/Nuklear/refs/heads/master/nuklear.h\ncurl -sLo nuklear.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear.c\nmkdir -p nuklear\ncurl -sLo nuklear/calculator.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/calculator.c\ncurl -sLo nuklear/canvas.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/canvas.c\ncurl -sLo nuklear/node_editor.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/node_editor.c\ncurl -sLo nuklear/overview.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/overview.c\ncurl -sLo nuklear/style.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/style.c\n
curl -sLo nuklear.h https://raw.githubusercontent.com/Immediate-Mode-UI/Nuklear/refs/heads/master/nuklear.h\ncurl -sLo nuklear.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear.c\nmkdir -p nuklear\ncurl -sLo nuklear/calculator.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/calculator.c\ncurl -sLo nuklear/canvas.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/canvas.c\ncurl -sLo nuklear/node_editor.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/node_editor.c\ncurl -sLo nuklear/overview.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/overview.c\ncurl -sLo nuklear/style.c https://raw.githubusercontent.com/dyne/cjit/refs/heads/main/examples/nuklear/style.c\n
This will create a small directory structure with all the source code files needed for our example:
.\n\u251c\u2500\u2500 nuklear\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 calculator.c\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 canvas.c\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 node_editor.c\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 overview.c\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 style.c\n\u251c\u2500\u2500 nuklear.c\n\u2514\u2500\u2500 nuklear.h\n
In this multiple file setup we have the main code of our example which is nuklear.c call one or more example modules according to define flags. By default it will just start all modules, see around line 390:
/* ===============================================================\n *\n * EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n#define INCLUDE_ALL\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n #define INCLUDE_STYLE\n #define INCLUDE_CALCULATOR\n #define INCLUDE_CANVAS\n #define INCLUDE_OVERVIEW\n #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n #include \"nuklear/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n #include \"nuklear/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n #include \"nuklear/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n #include \"nuklear/overview.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n #include \"nuklear/node_editor.c\"\n#endif\n
Starting it up is simple as usual, this time we just need to add -I.
to tell CJIT it can look for headers in the current directory, so it will find nuklear.h
.\\cjit.exe ./nuklear.c -I. -I.\\SDL2-2.30.9\\x86_64-w64-mingw32\\include\\ -L.\\SDL2-2.30.9\\x86_64-w64-mingw32\\bin\n
./cjit ./nuklear.c -I.\n
./cjit ./nuklear.c -I.\n
And \ud83d\udca5Boom! enjoy Nuklear!
"},{"location":"graphics/#thats-all-for-now","title":"That's all for now!","text":"If you like this manual, give CJIt a star, let us know what you'd like to see next and consider making a donation to Dyne.org. Thanks!
"}]} \ No newline at end of file