MacOS下源码安装SDL3并运行hello.c示例程序最近准备学习FFmepg、SDL、Qt等软件时想使用自己的MacMin4运行一下已故博主雷霄骅的一些FFmepg和SDL相关示例程序其相关博客和github仓库地址如下https://blog.csdn.net/leixiaohua1020https://github.com/leixiaohua1020https://github.com/leixiaohua1020/leixiaohua1020.github.io/tree/master/batch批量脚本simplest_ffmpeg_demos_git_clone_all.shsimplest_ffmpeg_demos_compile_gcc_all.sh这里像雷神致敬下载SDL最新源代码SDL目前已经更新到3.x版本了其官网地址为https://www.libsdl.org/其Github仓库地址为https://github.com/libsdl-org/SDL首先我们运行如下命令下载SDL最新代码gitclone https://github.com/libsdl-org/SDL.git或者gitclone gitgithub.com:libsdl-org/SDL.git当然前提是我们在我们的MacOs系统中提前安装好git软件可以使用brew install git命令安装即可。或者直接在Github上面下载对应的源代码zip包也可以。在MacOS中编译SDL源代码在MacOS中编译SDL源代码和Linux中一样分别进入到SDL源代码目录分别执行如下命令即可mkdirbuild cmake..makesudomakeinstall最终默认安装目录为/usr/local我们可以使用pkg-config工具查看sdl3的头文件和库文件安装目录pkg-config --cflags --libs sdl3如下所示192:build-scripts john$ pkg-config --cflags --libs sdl3 -I/usr/local/include -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lSDL3192:build-scripts john$ls/usr/local/include/SDL3/ SDL.h SDL_events.h SDL_main_impl.h SDL_platform.h SDL_test_crc32.h SDL_assert.h SDL_filesystem.h SDL_messagebox.h SDL_platform_defines.h SDL_test_font.h SDL_asyncio.h SDL_gamepad.h SDL_metal.h SDL_power.h SDL_test_fuzzer.h SDL_atomic.h SDL_gpu.h SDL_misc.h SDL_process.h SDL_test_harness.h SDL_audio.h SDL_guid.h SDL_mouse.h SDL_properties.h SDL_test_log.h SDL_begin_code.h SDL_haptic.h SDL_mutex.h SDL_rect.h SDL_test_md5.h SDL_bits.h SDL_hidapi.h SDL_oldnames.h SDL_render.h SDL_test_memory.h SDL_blendmode.h SDL_hints.h SDL_opengl.h SDL_revision.h SDL_thread.h SDL_camera.h SDL_init.h SDL_opengl_glext.h SDL_scancode.h SDL_time.h SDL_clipboard.h SDL_intrin.h SDL_opengles.h SDL_sensor.h SDL_timer.h SDL_close_code.h SDL_iostream.h SDL_opengles2.h SDL_stdinc.h SDL_touch.h SDL_copying.h SDL_joystick.h SDL_opengles2_gl2.h SDL_storage.h SDL_tray.h SDL_cpuinfo.h SDL_keyboard.h SDL_opengles2_gl2ext.h SDL_surface.h SDL_version.h SDL_dialog.h SDL_keycode.h SDL_opengles2_gl2platform.h SDL_system.h SDL_video.h SDL_dlopennote.h SDL_loadso.h SDL_opengles2_khrplatform.h SDL_test.h SDL_vulkan.h SDL_egl.h SDL_locale.h SDL_openxr.h SDL_test_assert.h SDL_endian.h SDL_log.h SDL_pen.h SDL_test_common.h SDL_error.h SDL_main.h SDL_pixels.h SDL_test_compare.h192:build-scripts john$ls/usr/local/lib/SDL.* ls: /usr/local/lib/SDL.*: No suchfileor directory192:build-scripts john$ls/usr/local/lib/libSDL3.* /usr/local/lib/libSDL3.0.dylib /usr/local/lib/libSDL3.dylib192:build-scripts john$/usr/local/lib/pkgconfig/sdl3.pc文件内容如下prefix/usr/localexec_prefix${prefix}libdir${prefix}/libincludedir${prefix}/include Name: sdl3 Description: Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer. URL: https://www.libsdl.org/ Version:3.5.0 Requires.private: Conflicts: Libs: -L${libdir}-Wl,-rpath,${libdir}-lSDL3 Libs.private: -Wl,-framework,CoreMedia -Wl,-framework,CoreVideo -Wl,-framework,Cocoa -Wl,-weak_framework,UniformTypeIdentifiers -Wl,-framework,IOKit -Wl,-framework,ForceFeedback -Wl,-framework,Carbon -Wl,-framework,CoreAudio -Wl,-framework,AudioToolbox -Wl,-framework,AVFoundation -Wl,-framework,Foundation -Wl,-framework,GameController -Wl,-framework,Metal -Wl,-framework,QuartzCore -Wl,-weak_framework,CoreHaptics -lpthread -lm Cflags: -I${includedir}运行官方的hello.c源代码SDL官方提供的hello.c源代码下载地址为https://raw.githubusercontent.com/libsdl-org/SDL/refs/heads/main/docs/hello.c其内容如下/* Copyright (C) 1997-2026 Sam Lantinga sloukenlibsdl.org This software is provided as-is, without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely. */#defineSDL_MAIN_USE_CALLBACKS1/* use the callbacks instead of main() */#includeSDL3/SDL.h#includeSDL3/SDL_main.hstaticSDL_Window*windowNULL;staticSDL_Renderer*rendererNULL;/* This function runs once at startup. */SDL_AppResultSDL_AppInit(void**appstate,intargc,char*argv[]){/* Create the window */if(!SDL_CreateWindowAndRenderer(Hello World,800,600,SDL_WINDOW_FULLSCREEN,window,renderer)){SDL_Log(Couldnt create window and renderer: %s,SDL_GetError());returnSDL_APP_FAILURE;}returnSDL_APP_CONTINUE;}/* This function runs when a new event (mouse input, keypresses, etc) occurs. */SDL_AppResultSDL_AppEvent(void*appstate,SDL_Event*event){if(event-typeSDL_EVENT_KEY_DOWN||event-typeSDL_EVENT_QUIT){returnSDL_APP_SUCCESS;/* end the program, reporting success to the OS. */}returnSDL_APP_CONTINUE;}/* This function runs once per frame, and is the heart of the program. */SDL_AppResultSDL_AppIterate(void*appstate){constchar*messageHello World!;intw0,h0;floatx,y;constfloatscale4.0f;/* Center the message and scale it up */SDL_GetRenderOutputSize(renderer,w,h);SDL_SetRenderScale(renderer,scale,scale);x((w/scale)-SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE*SDL_strlen(message))/2;y((h/scale)-SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE)/2;/* Draw the message */SDL_SetRenderDrawColor(renderer,0,0,0,255);SDL_RenderClear(renderer);SDL_SetRenderDrawColor(renderer,255,255,255,255);SDL_RenderDebugText(renderer,x,y,message);SDL_RenderPresent(renderer);returnSDL_APP_CONTINUE;}/* This function runs once at shutdown. */voidSDL_AppQuit(void*appstate,SDL_AppResult result){}刚开始看上面的代码感觉很奇怪传统的main()主函数入口不见了。为什么这些函数使用SDL3框架后没有看到main函数都是回调注册吗是的这段代码使用了SDL3框架并且通过回调函数的方式实现了程序的逻辑而不是传统的main函数。这是因为代码中定义了SDL_MAIN_USE_CALLBACKS宏并且实现了SDL3的应用程序回调函数接口。代码逻辑分析宏定义#defineSDL_MAIN_USE_CALLBACKS1这行代码告诉SDL3库程序将使用回调函数的方式来实现应用程序的逻辑而不是通过传统的main函数。SDL3会在内部调用这些回调函数来管理应用程序的生命周期。回调函数的实现SDL3提供了一组标准的回调函数接口用于替代main函数。这些回调函数分别在应用程序的不同阶段被调用SDL_AppInitSDL_AppResultSDL_AppInit(void**appstate,intargc,char*argv[])这是应用程序的初始化函数类似于传统main函数中的初始化部分。在这里代码通过SDL_CreateWindowAndRenderer创建了一个窗口和渲染器。如果窗口和渲染器创建失败会记录错误日志并返回SDL_APP_FAILURE表示初始化失败。SDL_AppEventSDL_AppResultSDL_AppEvent(void*appstate,SDL_Event*event)这个函数在每次事件如键盘输入、鼠标点击、窗口关闭等发生时被调用。代码中检查了事件类型如果是SDL_EVENT_KEY_DOWN按键按下或SDL_EVENT_QUIT退出事件则返回SDL_APP_SUCCESS表示程序应该结束。SDL_AppIterateSDL_AppResultSDL_AppIterate(void*appstate)这是程序的核心逻辑每一帧都会调用一次。代码中绘制了一个“Hello World!”的消息先清空屏幕然后设置绘制颜色最后调用SDL_RenderDebugText绘制文本并通过SDL_RenderPresent将内容呈现到窗口。SDL_AppQuitvoidSDL_AppQuit(void*appstate,SDL_AppResult result)这是程序退出时调用的清理函数。目前代码中没有实现任何清理逻辑但可以在这里释放资源比如销毁窗口和渲染器。没有main函数的原因SDL3在检测到SDL_MAIN_USE_CALLBACKS宏定义后会自动调用这些回调函数来管理程序的生命周期。SDL3内部有一个默认的main函数它会初始化SDL库然后依次调用SDL_AppInit、SDL_AppEvent、SDL_AppIterate和SDL_AppQuit从而实现程序的运行。回调函数的优点模块化将程序的不同阶段分离到不同的回调函数中逻辑更加清晰。框架管理SDL3框架负责调用这些回调函数开发者只需专注于实现具体的逻辑。跨平台支持SDL3的这种设计可以更好地适配不同平台的启动方式而开发者无需关心底层细节。总结这段代码通过定义SDL_MAIN_USE_CALLBACKS宏使用了SDL3的回调机制来替代传统的main函数。SDL3框架会自动调用这些回调函数来管理程序的生命周期。这种设计方式使得代码更加模块化便于维护和跨平台开发。运行hello.c在MacOS下安装完SDL3后运行hello.c就很简单了直接执行如下命令即可gcc hello.c -o hellopkg-config --cflags --libs sdl3./hello运行hello可执行程序后默认是全屏显示窗口显示了Hello World!字符串白色字体并且按键盘中任意键或者ESC就会退出窗口。为了容易演示运行结果和截图我们可以把hello.c源代码中的第23行中的代码if(!SDL_CreateWindowAndRenderer(Hello World,800,600,SDL_WINDOW_FULLSCREEN,window,renderer)){其中的SDL_WINDOW_FULLSCREEN表示全屏显示可以使用其他的参数如下// SDL_WINDOW_MINIMIZED // SDL_WINDOW_MAXIMIZED // SDL_WINDOW_ALWAYS_ON_TOP // SDL_WINDOW_FULLSCREEN其完整的窗口的标志/usr/local/include/SDL3/SDL_video.h如下/** * The flags on a window. * * These cover a lot of true/false, or on/off, window state. Some of it is * immutable after being set through SDL_CreateWindow(), some of it can be * changed on existing windows by the app, and some of it might be altered by * the user or system outside of the apps control. * * When creating windows with SDL_WINDOW_RESIZABLE, SDL will constrain * resizable windows to the dimensions recommended by the compositor to fit it * within the usable desktop space, although some compositors will do this * automatically without intervention as well. Use SDL_SetWindowResizable * after creation instead if you wish to create a window with a specific size. * * \since This datatype is available since SDL 3.2.0. * * \sa SDL_GetWindowFlags */typedefUint64 SDL_WindowFlags;#defineSDL_WINDOW_FULLSCREENSDL_UINT64_C(0x0000000000000001)/** window is in fullscreen mode */#defineSDL_WINDOW_OPENGLSDL_UINT64_C(0x0000000000000002)/** window usable with OpenGL context */#defineSDL_WINDOW_OCCLUDEDSDL_UINT64_C(0x0000000000000004)/** window is occluded */#defineSDL_WINDOW_HIDDENSDL_UINT64_C(0x0000000000000008)/** window is neither mapped onto the desktop nor shown in the taskbar/dock/window list; SDL_ShowWindow() is required for it to become visible */#defineSDL_WINDOW_BORDERLESSSDL_UINT64_C(0x0000000000000010)/** no window decoration */#defineSDL_WINDOW_RESIZABLESDL_UINT64_C(0x0000000000000020)/** window can be resized */#defineSDL_WINDOW_MINIMIZEDSDL_UINT64_C(0x0000000000000040)/** window is minimized */#defineSDL_WINDOW_MAXIMIZEDSDL_UINT64_C(0x0000000000000080)/** window is maximized */#defineSDL_WINDOW_MOUSE_GRABBEDSDL_UINT64_C(0x0000000000000100)/** window has grabbed mouse input */#defineSDL_WINDOW_INPUT_FOCUSSDL_UINT64_C(0x0000000000000200)/** window has input focus */#defineSDL_WINDOW_MOUSE_FOCUSSDL_UINT64_C(0x0000000000000400)/** window has mouse focus */#defineSDL_WINDOW_EXTERNALSDL_UINT64_C(0x0000000000000800)/** window not created by SDL */#defineSDL_WINDOW_MODALSDL_UINT64_C(0x0000000000001000)/** window is modal */#defineSDL_WINDOW_HIGH_PIXEL_DENSITYSDL_UINT64_C(0x0000000000002000)/** window uses high pixel density back buffer if possible */#defineSDL_WINDOW_MOUSE_CAPTURESDL_UINT64_C(0x0000000000004000)/** window has mouse captured (unrelated to MOUSE_GRABBED) */#defineSDL_WINDOW_MOUSE_RELATIVE_MODESDL_UINT64_C(0x0000000000008000)/** window has relative mode enabled */#defineSDL_WINDOW_ALWAYS_ON_TOPSDL_UINT64_C(0x0000000000010000)/** window should always be above others */#defineSDL_WINDOW_UTILITYSDL_UINT64_C(0x0000000000020000)/** window should be treated as a utility window, not showing in the task bar and window list */#defineSDL_WINDOW_TOOLTIPSDL_UINT64_C(0x0000000000040000)/** window should be treated as a tooltip and does not get mouse or keyboard focus, requires a parent window */#defineSDL_WINDOW_POPUP_MENUSDL_UINT64_C(0x0000000000080000)/** window should be treated as a popup menu, requires a parent window */#defineSDL_WINDOW_KEYBOARD_GRABBEDSDL_UINT64_C(0x0000000000100000)/** window has grabbed keyboard input */#defineSDL_WINDOW_FILL_DOCUMENTSDL_UINT64_C(0x0000000000200000)/** window is in fill-document mode (Emscripten only), since SDL 3.4.0 */#defineSDL_WINDOW_VULKANSDL_UINT64_C(0x0000000010000000)/** window usable for Vulkan surface */#defineSDL_WINDOW_METALSDL_UINT64_C(0x0000000020000000)/** window usable for Metal view */#defineSDL_WINDOW_TRANSPARENTSDL_UINT64_C(0x0000000040000000)/** window with transparent buffer */#defineSDL_WINDOW_NOT_FOCUSABLESDL_UINT64_C(0x0000000080000000)/** window should not be focusable */比如说改成if(!SDL_CreateWindowAndRenderer(Hello World,800,600,SDL_WINDOW_ALWAYS_ON_TOP,window,renderer)){我们再次编译并运行hello.c程序可以发现窗口置顶到最前台如下图所示当然hello.c在其他系统平台上运行的方法可以参考https://github.com/libsdl-org/SDL/blob/main/INSTALL.mdIntroduction to SDL with XcodeIntroduction to SDL with Visual StudioIntroduction to SDL with CMakeIntroduction to SDL with Android StudioIntroduction to SDL with MinGW