[SDL3.x] SDL_Appxxx(…) Compile programs

I have already seen several demo programs, including the SDL3 tests, which use functions like SDL_Appxxx(…) .
Does anyone have any idea how to compile such programs?

gcc main.c -o main -lSDL3

it does not work. Then he complains that the main() is missing.

It works for me. Did you remember to define the macro SDL_MAIN_USE_CALLBACKS before including <SDL3/SDL_main.h>? It’s all explained here.

1 Like

Thanks to your link I have come one step further.
This line is very important.

#define SDL_MAIN_USE_CALLBACKS

I wanted to try the following examples and they are missing everywhere.

Now it can be compiled as follows.

g++ main_GLSE.c -lSDL3 -lGL

It just doesn’t seem to work with pure c.

Is there also a way to make it work with gcc?

8Observer8’s examples are written in C++ which is why you have to use g++ rather than gcc.

I banned all the C++ stuff, now it works with simple C too.

//  g++ main.c -o main -lSDL3

#define SDL_MAIN_USE_CALLBACKS

#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>

struct AppContext {
    SDL_Window* window;
    SDL_Renderer* renderer;
    SDL_bool app_quit;
} appContext;

int SDL_Fail(){
    SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Error %s", SDL_GetError());
    return -1;
}

int SDL_AppInit(void** appstate, int argc, char* argv[]) {
    // init the library, here we make a window so we only need the Video capabilities.
    if (SDL_Init(SDL_INIT_VIDEO)){
        return SDL_Fail();
    }
    
    // create a window
    SDL_Window* window = SDL_CreateWindow("Window", 352, 430, SDL_WINDOW_RESIZABLE);
    if (!window){
        return SDL_Fail();
    }
    
    SDL_Renderer* renderer = SDL_CreateRenderer(window, NULL);
    if (!renderer){
        return SDL_Fail();
    }
    
    // print some information about the window
    SDL_ShowWindow(window);
    {
        int width, height, bbwidth, bbheight;
        SDL_GetWindowSize(window, &width, &height);
        SDL_GetWindowSizeInPixels(window, &bbwidth, &bbheight);
        SDL_Log("Window size: %ix%i", width, height);
        SDL_Log("Backbuffer size: %ix%i", bbwidth, bbheight);
        if (width != bbwidth){
            SDL_Log("This is a highdpi environment.");
        }
    }

    appContext.window = window;
    appContext.renderer = renderer;
    appContext.app_quit=SDL_FALSE;

    *appstate = &appContext;

    SDL_Log("Application started successfully!");

    return 0;
}

int SDL_AppEvent(void *appstate, const SDL_Event* event) {
    struct AppContext *app = appstate;

    if (event->type == SDL_EVENT_QUIT) {
        app->app_quit = SDL_TRUE;
    }

    return 0;
}

int SDL_AppIterate(void *appstate) {
    struct AppContext *app = appstate;

    // draw a color
    float time = SDL_GetTicks() / 1000.f;
    int red = (SDL_sin(time) + 1) / 2.0 * 255;
    int green = (SDL_sin(time / 2) + 1) / 2.0 * 255;
    int blue = (SDL_sin(time) * 2 + 1) / 2.0 * 255;
    
    SDL_SetRenderDrawColor(app->renderer, red, green, blue, SDL_ALPHA_OPAQUE);
    SDL_RenderClear(app->renderer);
    SDL_RenderPresent(app->renderer);

    return app->app_quit;
}

void SDL_AppQuit(void* appstate) {
    struct    AppContext *app = appstate;
    if (app) {
        SDL_DestroyRenderer(app->renderer);
        SDL_DestroyWindow(app->window);
    }

    SDL_Quit();
    SDL_Log("Application quit successfully!");
}

If I understand correctly, somewhere in the libSDL3 is the main(…) ?
In which there is an SDL_EnterAppMainCallbacks(…) and which calls my functions?

Yes, SDL_main.h includes SDL_main_impl.h which defines the main function.

I took a closer look at SDL_main_impl.h.

This can be seen in the various start routines such as main() or WinMain(), which all call SDL_RunApp.

I still noticed an extreme difference between SDL2 and SDL3. With SDL3, a simple main() also works under Windows and SDL2 requires a WinMain().

It’s probably better that you read the docs if you want to know how it’s supposed to be used because that particular header uses a lot of macro magic.

SDL2 does not require you to define WinMain. That’s the whole point behind SDL_main.

The headers might look widely different in SDL2 and SDL3 but the way you use them is very similar.

In both SDL2 and SDL3, you define your main function as:

int main(int argc, char *argv[])

The difference is:

  • In SDL2 you just include SDL.h like normal but you have to link the SDL2_main library on Windows.
  • In SDL3 you have to include SDL_main.h in the file that contains the main function but you don’t need to link any additional libraries.

Basically, how it works is that SDL defines a macro named main that expands to SDL_main so when you define your main function you are actually defining a function named SDL_main. SDL defines it’s own main function (main, WinMain, or whatever the platform requires) that calls SDL_main (The SDL_RunApp function that you saw calls SDL_main internally).

If you define SDL_MAIN_USE_CALLBACKS in SDL3 then SDL will define its own SDL_main function that calls SDL_EnterAppMainCallbacks with the callbacks that you have defined.