Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/TinyCC/tinycc/llms.txt

Use this file to discover all available pages before exploring further.

After compilation and linking, you can either run the code in memory or generate an output file.

Memory relocation

tcc_relocate

Performs all relocations needed to run the compiled code in memory. This must be called before using tcc_get_symbol().
int tcc_relocate(TCCState *s);
s
TCCState*
required
The compilation context.
return
int
Returns 0 on success, negative value on error.
Example:
if (tcc_relocate(s) < 0) {
    fprintf(stderr, "Relocation failed\n");
    return 1;
}

// Now you can get symbols
void (*func)(void) = tcc_get_symbol(s, "my_function");
Do not call tcc_relocate() if you’re using tcc_output_file() or tcc_run(). Those functions handle relocation internally.

Running code directly

tcc_run

Compiles, links, and runs the main() function directly. Do not call tcc_relocate() before this.
int tcc_run(TCCState *s, int argc, char **argv);
s
TCCState*
required
The compilation context.
argc
int
required
Number of command-line arguments to pass to main().
argv
char**
required
Array of command-line arguments.
return
int
Returns the value returned by the compiled main() function.
Example:
TCCState *s = tcc_new();
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);

const char *code = 
    "#include <stdio.h>\n"
    "int main() {\n"
    "    printf(\"Hello from compiled code!\\n\");\n"
    "    return 0;\n"
    "}\n";

tcc_compile_string(s, code);

// Run main() with no arguments
int exit_code = tcc_run(s, 0, NULL);

printf("Program exited with code: %d\n", exit_code);
tcc_delete(s);

Getting compiled symbols

tcc_get_symbol

Returns a pointer to a symbol (function or variable) from the compiled code. You must call tcc_relocate() first.
void *tcc_get_symbol(TCCState *s, const char *name);
s
TCCState*
required
The compilation context.
name
const char*
required
Name of the symbol to retrieve.
return
void*
Pointer to the symbol, or NULL if not found.
Example:
TCCState *s = tcc_new();
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);

const char *code = 
    "int add(int a, int b) { return a + b; }\n"
    "int multiply(int a, int b) { return a * b; }\n";

tcc_compile_string(s, code);
tcc_relocate(s);

// Get function pointers
int (*add_func)(int, int) = tcc_get_symbol(s, "add");
int (*mul_func)(int, int) = tcc_get_symbol(s, "multiply");

if (!add_func || !mul_func) {
    fprintf(stderr, "Failed to get symbols\n");
    return 1;
}

// Call the functions
printf("%d + %d = %d\n", 5, 3, add_func(5, 3));
printf("%d * %d = %d\n", 5, 3, mul_func(5, 3));

tcc_delete(s);

tcc_list_symbols

Lists all global symbols and their values via a callback function.
void tcc_list_symbols(TCCState *s, void *ctx,
    void (*symbol_cb)(void *ctx, const char *name, const void *val));
s
TCCState*
required
The compilation context.
ctx
void*
User data pointer passed to the callback.
symbol_cb
void (*)(void*, const char*, const void*)
required
Callback function called for each symbol.
Example:
void print_symbol(void *ctx, const char *name, const void *val) {
    printf("Symbol: %s at %p\n", name, val);
}

const char *code = 
    "int var1 = 10;\n"
    "int var2 = 20;\n"
    "void func1(void) {}\n"
    "void func2(void) {}\n";

tcc_compile_string(s, code);
tcc_relocate(s);

// List all symbols
tcc_list_symbols(s, NULL, print_symbol);

// Output:
// Symbol: var1 at 0x...
// Symbol: var2 at 0x...
// Symbol: func1 at 0x...
// Symbol: func2 at 0x...

Advanced execution patterns

Plugin system

// Plugin interface
typedef struct {
    const char* name;
    void (*init)(void);
    void (*execute)(void);
    void (*cleanup)(void);
} Plugin;

Plugin* load_plugin(const char *source_code) {
    TCCState *s = tcc_new();
    tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
    
    // Compile plugin
    if (tcc_compile_string(s, source_code) < 0) {
        tcc_delete(s);
        return NULL;
    }
    
    if (tcc_relocate(s) < 0) {
        tcc_delete(s);
        return NULL;
    }
    
    // Get plugin interface
    Plugin *plugin = tcc_get_symbol(s, "plugin");
    if (!plugin) {
        tcc_delete(s);
        return NULL;
    }
    
    return plugin;
}

// Use plugin
Plugin *p = load_plugin(
    "#include <stdio.h>\n"
    "void my_init() { printf(\"Init\\n\"); }\n"
    "void my_exec() { printf(\"Execute\\n\"); }\n"
    "void my_cleanup() { printf(\"Cleanup\\n\"); }\n"
    "Plugin plugin = {\n"
    "    .name = \"MyPlugin\",\n"
    "    .init = my_init,\n"
    "    .execute = my_exec,\n"
    "    .cleanup = my_cleanup\n"
    "};\n");

if (p) {
    p->init();
    p->execute();
    p->cleanup();
}

Expression evaluator

double eval_expression(const char *expr) {
    TCCState *s = tcc_new();
    tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
    
    char code[1024];
    snprintf(code, sizeof(code),
        "#include <math.h>\n"
        "double evaluate() {\n"
        "    return %s;\n"
        "}\n", expr);
    
    if (tcc_compile_string(s, code) < 0) {
        tcc_delete(s);
        return 0.0;
    }
    
    tcc_add_library(s, "m");
    
    if (tcc_relocate(s) < 0) {
        tcc_delete(s);
        return 0.0;
    }
    
    double (*evaluate)(void) = tcc_get_symbol(s, "evaluate");
    double result = evaluate();
    
    tcc_delete(s);
    return result;
}

// Usage
printf("2 + 2 = %f\n", eval_expression("2 + 2"));
printf("sqrt(16) = %f\n", eval_expression("sqrt(16)"));
printf("sin(3.14159/2) = %f\n", eval_expression("sin(3.14159/2)"));

Hot code reloading

typedef struct {
    TCCState *state;
    void (*update)(float dt);
    void (*render)(void);
} GameModule;

GameModule* reload_module(GameModule *old, const char *source) {
    // Clean up old module
    if (old) {
        tcc_delete(old->state);
        free(old);
    }
    
    // Create new module
    GameModule *module = malloc(sizeof(GameModule));
    module->state = tcc_new();
    tcc_set_output_type(module->state, TCC_OUTPUT_MEMORY);
    
    if (tcc_compile_string(module->state, source) < 0) {
        free(module);
        return NULL;
    }
    
    if (tcc_relocate(module->state) < 0) {
        tcc_delete(module->state);
        free(module);
        return NULL;
    }
    
    module->update = tcc_get_symbol(module->state, "update");
    module->render = tcc_get_symbol(module->state, "render");
    
    return module;
}

// Main game loop
GameModule *game = NULL;
while (running) {
    // Check if source file changed
    if (source_file_modified()) {
        char *new_source = load_source_file("game.c");
        GameModule *new_game = reload_module(game, new_source);
        if (new_game) {
            game = new_game;
            printf("Hot reload successful!\n");
        }
        free(new_source);
    }
    
    if (game) {
        game->update(delta_time);
        game->render();
    }
}

Error handling

void *get_symbol_safe(TCCState *s, const char *name) {
    void *sym = tcc_get_symbol(s, name);
    if (!sym) {
        fprintf(stderr, "Error: Symbol '%s' not found\n", name);
        fprintf(stderr, "Available symbols:\n");
        tcc_list_symbols(s, NULL, print_symbol);
    }
    return sym;
}

// Usage
int (*func)(int) = get_symbol_safe(s, "my_function");
if (!func) {
    // Handle error
    return 1;
}

Build docs developers (and LLMs) love