Build SDL2 projects for iOS with Xcode 11

I’m working on a cross-platform video game. It’s currently running nicely on Windows, Mac, Linux, Android, and iOS. I’m using a fairly generic SDL2 configuration, so I thought I would share it in case anyone else is looking for a clean and easy approach to compiling your SDL2 project for iPhones and iPads. Thanks to LazyFoo’s tutorial for getting me headed in the right direction. See below for step-by-step instructions. If you want to customize the name of your project, just replace “sdlproject” with your project name in each step.

  • Now start up Xcode and open ~/projects/sdlproject.xcodeproj
  • Select the Build target and go to General and change the Display Name to sdlproject, and the Bundle Identifier to com.companyname.sdlproject.
  • Where it says ___PROJECTNAME___ in the build targets to the right of the Play and Stop buttons, select ___PROJECTNAME___ and select “Manage Schemes”
  • From the Manage Schemes window, click on the ___PROJECTNAME___ scheme, wait a few seconds, then click on it again to rename it. Rename it to sdlproject and press enter to apply the change. This should change the build target name from ___PROJECTNAME___ to sdlproject.

  • Remove SDL.xcodeproj from Sources
  • Remove main.c from sources
  • Add each .c and .h file from ~/projects/sdlproject (a directory containing your SDL source files) to Sources

You should end up with something like this:

  • Right click “Sources” -> Add Files -> Select the “Create groups” option for Added folders and add SDL2-2.x.x/Xcode-iOS/SDL/SDL.xcodeproj to Sources

  • Similarly, add SDL2_image-2.x.x/Xcode-iOS/SDL/SDL.xcodeproj to Sources with option, “Added folders:Create groups”
  • (do the same for SDL2_mixer-2.x.x and SDL2_ttf-x.x)
  • Set the build target to libSDL-ios and from the menu, select Product-> Build. You should see “Build Succeeded”.

  • Set the build target to libSDL_image-ios
  • Sources->SDL_image.xcodeproj->Public Headers->add SDL2-2.x.x/includes as group

  • from the menu, select Product-> Build. You should see “Build Succeeded”.
  • Do the same for SDL_ttf and SDL_mixer (add the SDL2 includes folder to the library’s Public Headers, select the build target to the library, then Build). You should end up with something like this:

  • Right click “Sources” and add the SDL2 include directory as group

  • Right click Sources and add sdl_ttf.h, sdl_image.h, and sdl_mixer.h from each of the respective libraries

  • Select the sdlproject build target, then select the top sdlproject:

  • Select the general tab.
    • Configure settings as needed. In my case I configure Target device->iPhone, iPad, iOS 8. Landscape Left, Hide Status bar, requires full screen
    • Under Frameworks, Libraries, and Embedded Content, add the following if they are not already listed (note that you may need slightly different libraries depending on what your code requires):

  • Under sdlproject->Signing and Capabilities, 
      • Select the Team for code signing (you may need to configure this first) and Set the Bundle Identifier: com.companyname.sdlproject
  • Add any needed data directories or folders to Resources, taking care to select the “folder reference” option (instead of the “create groups” option we’ve been using for most other additions).
  • You may want to edit the existing images in Resources to be something appropriate for your project:
  • Select the sdlproject build target, and a device. In my case, I’m testing on an iPad.

  • From the menu select Product->Build. If you get Build Succeeded, Select Product->Run to run the program on your iOS device. With any luck you’re in business!

Troubleshooting Missing Libraries

You will see the following if you didn’t include AudioToolbox.framework:
Undefined symbol: _AudioQueueNewInput
Undefined symbol: _AudioQueueSetProperty
Undefined symbol: _AudioQueueAllocateBuffer
Undefined symbol: _AudioQueueNewOutput
Undefined symbol: _AudioQueueEnqueueBuffer
Undefined symbol: _AudioQueueDispose
Undefined symbol: _AudioQueueStart
Undefined symbol: _AudioQueuePause

You will see the following if you didn’t include AVFoundation.framework:
Undefined symbol: OBJC_CLASS$_AVAudioSession
Undefined symbol: _AVAudioSessionCategoryPlayAndRecord
Undefined symbol: _AVAudioSessionCategoryRecord
Undefined symbol: _AVAudioSessionInterruptionTypeKey
Undefined symbol: _AVAudioSessionCategoryAmbient
Undefined symbol: _AVAudioSessionModeDefault
Undefined symbol: _AVAudioSessionInterruptionNotification
Undefined symbol: _AVAudioSessionCategorySoloAmbient
Undefined symbol: _AVAudioSessionCategoryPlayback

You will see the following if you didn’t include CoreBluetooth.framework:
Undefined symbol: OBJC_CLASS$_CBCentralManager
Undefined symbol: OBJC_CLASS$_CBUUID
Undefined symbol: _CBAdvertisementDataLocalNameKey

You will see the following if you didn’t include CoreGraphics.framework:
Undefined symbol: _CGRectZero
Undefined symbol: _CGRectEqualToRect
Undefined symbol: _CGImageGetAlphaInfo
Undefined symbol: _CGContextDrawImage
Undefined symbol: _CGImageGetHeight
Undefined symbol: _CGImageGetBytesPerRow
Undefined symbol: _CGColorSpaceGetNumberOfComponents
Undefined symbol: _CGColorSpaceGetBaseColorSpace
Undefined symbol: _CGColorSpaceGetColorTable
Undefined symbol: _CGContextRelease
Undefined symbol: _CGImageGetDataProvider
Undefined symbol: _CGColorSpaceCreateDeviceRGB
Undefined symbol: _CGColorSpaceGetColorTableCount
Undefined symbol: _CGColorSpaceRelease
Undefined symbol: _CGImageGetWidth
Undefined symbol: _CGImageGetColorSpace
Undefined symbol: _CGDataProviderCopyData
Undefined symbol: _CGBitmapContextCreate
Undefined symbol: _CGColorSpaceGetModel
Undefined symbol: _CGImageGetBitsPerPixel
Undefined symbol: _CGDataProviderCreateSequential
Undefined symbol: _CGDataProviderRelease

You will see the following if you didn’t include CoreMotion.framework:
Undefined symbol: OBJC_CLASS$_CMMotionManager

You will see the following if you didn’t include CoreServices.framework:
Undefined symbol: _UTTypeConformsTo
Undefined symbol: _kUTTypePNG
Undefined symbol: _kUTTypeJPEG
Undefined symbol: _kUTTypeTIFF
Undefined symbol: _kUTTypeGIF

You will see the following if you didn’t include Foundation.framework:
Undefined symbol: OBJC_CLASS$_NSMapTable
Undefined symbol: objc_destroyWeak
Undefined symbol: _objc_storeWeak
Undefined symbol: _OBJC_CLASS$_NSArray
Undefined symbol: OBJC_CLASS$_NSMutableArray
Undefined symbol: NSFoundationVersionNumber
Undefined symbol: _OBJC_CLASS$_NSDate
Undefined symbol: OBJC_CLASS$_NSObject
Undefined symbol: NSDefaultRunLoopMode
Undefined symbol: _OBJC_CLASS$_NSException
Undefined symbol: objc_sync_enter
Undefined symbol: __objc_empty_cache
Undefined symbol: _CFStringCreateWithCString
Undefined symbol: _objc_sync_exit
Undefined symbol: _CFRunLoopRunInMode
Undefined symbol: _OBJC_CLASS$_NSNumber
Undefined symbol: NSLog
Undefined symbol: _kCFRunLoopDefaultMode
Undefined symbol: _OBJC_CLASS$_NSBundle
Undefined symbol: kCFTypeDictionaryValueCallBacks
Undefined symbol: _OBJC_METACLASS$_NSObject
Undefined symbol: CFRunLoopGetCurrent
Undefined symbol: _OBJC_CLASS$_NSData
Undefined symbol: OBJC_CLASS$_NSRunLoop
Undefined symbol: OBJC_CLASS$_NSString
Undefined symbol: objc_retainAutoreleaseReturnValue
Undefined symbol: _objc_autoreleaseReturnValue
Undefined symbol: _objc_storeStrong
Undefined symbol: _objc_alloc
Undefined symbol: _objc_autoreleasePoolPush
Undefined symbol: _objc_autorelease
Undefined symbol: _objc_msgSendSuper2
Undefined symbol: _objc_release
Undefined symbol: _CFDictionaryCreate
Undefined symbol: _objc_retainAutorelease
Undefined symbol: _objc_loadWeakRetained
Undefined symbol: _objc_retainAutoreleasedReturnValue
Undefined symbol: _objc_getProperty
Undefined symbol: _objc_retain
Undefined symbol: _CFURLCreateWithFileSystemPath
Undefined symbol: _CFRelease
Undefined symbol: _objc_autoreleasePoolPop
Undefined symbol: _objc_end_catch
Undefined symbol: ___CFConstantStringClassReference
Undefined symbol: ___objc_personality_v0
Undefined symbol: _objc_begin_catch
Undefined symbol: _OBJC_CLASS$_NSFileManager
Undefined symbol: objc_msgSend
Undefined symbol: _objc_setProperty_nonatomic_copy
Undefined symbol: _objc_enumerationMutation
Undefined symbol: _OBJC_CLASS$_NSNotificationCenter
Undefined symbol: kCFTypeDictionaryKeyCallBacks
Undefined symbol: _OBJC_CLASS$_NSDictionary
Undefined symbol: OBJC_EHTYPE$_NSException

You will see the following if you didn’t include GameController.framework:
Undefined symbol: OBJC_CLASS$_GCController
Undefined symbol: _GCControllerDidConnectNotification
Undefined symbol: _GCControllerDidDisconnectNotification

You will see the following if you didn’t include ImageIO.framework:
Undefined symbol: _CGImageSourceCreateWithURL
Undefined symbol: _CGImageSourceCreateWithDataProvider
Undefined symbol: _CGImageSourceCreateImageAtIndex
Undefined symbol: _kCGImageSourceTypeIdentifierHint
Undefined symbol: _CGImageSourceGetType

You will see the following if you didn’t include libc++.tbd:
Undefined symbol: operator new[](unsigned long)
Undefined symbol: operator new(unsigned long)
Undefined symbol: operator delete
Undefined symbol: ___gxx_personality_v0
Undefined symbol: operator delete(void*)

You will see the following if you didn’t include Metal.framework:
Undefined symbol: OBJC_CLASS$_MTLSamplerDescriptor
Undefined symbol: OBJC_CLASS$_MTLTextureDescriptor
Undefined symbol: OBJC_CLASS$_MTLRenderPassDescriptor
Undefined symbol: OBJC_CLASS$_MTLVertexDescriptor
Undefined symbol: OBJC_CLASS$_MTLRenderPipelineDescriptor
Undefined symbol: _MTLCreateSystemDefaultDevice

You will see the following if you didn’t include OpenGLES.framework:
Undefined symbol: glBlitFramebuffer
Undefined symbol: _glRenderbufferStorage
Undefined symbol: _glLabelObjectEXT
Undefined symbol: _glBufferSubData
Undefined symbol: _kEAGLColorFormatSRGBA8
Undefined symbol: _glBindRenderbuffer
Undefined symbol: _OBJC_METACLASS$_EAGLContext
Undefined symbol: glRenderbufferStorageMultisample
Undefined symbol: _glFinish
Undefined symbol: _glRotatef
Undefined symbol: _glTranslatef
Undefined symbol: _glDeleteFramebuffers
Undefined symbol: _glPushMatrix
Undefined symbol: _glCheckFramebufferStatusOES
Undefined symbol: _kEAGLColorFormatRGB565
Undefined symbol: _glBlendEquationSeparate
Undefined symbol: _glFramebufferTexture2DOES
Undefined symbol: _kEAGLDrawablePropertyColorFormat
Undefined symbol: _glBindFramebuffer
Undefined symbol: _glBindFramebufferOES
Undefined symbol: _glTexParameteriv
Undefined symbol: _glInvalidateFramebuffer
Undefined symbol: _glFramebufferRenderbuffer
Undefined symbol: _glDrawTexfOES
Undefined symbol: _glBufferData
Undefined symbol: _glReadPixels
Undefined symbol: _glBindBuffer
Undefined symbol: _glBlendEquationSeparateOES
Undefined symbol: _glDeleteBuffers
Undefined symbol: _glBlendFunc
Undefined symbol: _glGetBooleanv
Undefined symbol: _glGenBuffers
Undefined symbol: _glGenFramebuffersOES
Undefined symbol: _glGetAttribLocation
Undefined symbol: _glUseProgram
Undefined symbol: _glUniformMatrix4fv
Undefined symbol: _glUniform4f
Undefined symbol: _glUniform1i
Undefined symbol: _glTexSubImage2D
Undefined symbol: _glBlendFuncSeparate
Undefined symbol: _glShaderSource
Undefined symbol: _glShaderBinary
Undefined symbol: _kEAGLColorFormatRGBA8
Undefined symbol: _glGetUniformLocation
Undefined symbol: _glGetProgramiv
Undefined symbol: _glBindTexture
Undefined symbol: _glGetIntegerv
Undefined symbol: _glCreateProgram
Undefined symbol: _glDeleteTextures
Undefined symbol: _kEAGLDrawablePropertyRetainedBacking
Undefined symbol: _glDrawArrays
Undefined symbol: _glGetShaderiv
Undefined symbol: _glGetString
Undefined symbol: _glGetError
Undefined symbol: _glColor4f
Undefined symbol: _glResolveMultisampleFramebufferAPPLE
Undefined symbol: _glLoadIdentity
Undefined symbol: _glDisable
Undefined symbol: _glDiscardFramebufferEXT
Undefined symbol: _glLinkProgram
Undefined symbol: _glDeleteShader
Undefined symbol: _glDeleteProgram
Undefined symbol: _glBindAttribLocation
Undefined symbol: _glMatrixMode
Undefined symbol: _glVertexAttribPointer
Undefined symbol: _glEnableVertexAttribArray
Undefined symbol: _glActiveTexture
Undefined symbol: _glDeleteFramebuffersOES
Undefined symbol: _glClear Undefined symbol: _OBJC_CLASS$_EAGLContext
Undefined symbol: _glGenTextures
Undefined symbol: _glOrthof
Undefined symbol: _glPopMatrix
Undefined symbol: _glDisableClientState
Undefined symbol: _glDeleteRenderbuffers
Undefined symbol: _glBlendFuncSeparateOES
Undefined symbol: _glTexCoordPointer
Undefined symbol: _glViewport
Undefined symbol: _glDisableVertexAttribArray
Undefined symbol: _glCreateShader
Undefined symbol: _glTexImage2D
Undefined symbol: _glVertexPointer
Undefined symbol: _glBlendEquationOES
Undefined symbol: _glClearColor
Undefined symbol: _glGetRenderbufferParameteriv
Undefined symbol: _glFramebufferTexture2D
Undefined symbol: _glCompileShader
Undefined symbol: _glGetShaderInfoLog
Undefined symbol: _glAttachShader
Undefined symbol: _glEnable
Undefined symbol: _glScissor
Undefined symbol: _glCheckFramebufferStatus
Undefined symbol: _glEnableClientState
Undefined symbol: _glGenFramebuffers
Undefined symbol: _glTexParameteri
Undefined symbol: _glGenRenderbuffers
Undefined symbol: _glTexEnvf
Undefined symbol: _glPixelStorei
Undefined symbol: _glGetProgramInfoLog

You will see the following if you didn’t include QuartzCore.framework:
Undefined symbol: OBJC_CLASS$_CAEAGLLayer
Undefined symbol: OBJC_CLASS$_CAMetalLayer
Undefined symbol: OBJC_CLASS$_CADisplayLink

You will see the following if you didn’t include UIKit.framework:
Undefined symbol: UIApplicationWillResignActiveNotification
Undefined symbol: _OBJC_METACLASS$_UIView
Undefined symbol: OBJC_CLASS$_UIKeyCommand
Undefined symbol: OBJC_CLASS$_UITextField
Undefined symbol: UIKeyInputEscape
Undefined symbol: _UIKeyboardWillShowNotification
Undefined symbol: _UIKeyboardWillHideNotification
Undefined symbol: _UIApplicationWillEnterForegroundNotification
Undefined symbol: _UITextFieldTextDidChangeNotification
Undefined symbol: _OBJC_CLASS$_UIPasteboard
Undefined symbol: OBJC_CLASS$_UIApplication
Undefined symbol: OBJC_CLASS$_UIAlertAction
Undefined symbol: OBJC_CLASS$_UIAlertController
Undefined symbol: UIWindowLevelAlert
Undefined symbol: _OBJC_METACLASS$_UIWindow
Undefined symbol: OBJC_CLASS$_UIWindow
Undefined symbol: OBJC_CLASS$_UIImage
Undefined symbol: OBJC_CLASS$_UIStoryboard
Undefined symbol: OBJC_CLASS$_UIDevice
Undefined symbol: UIKeyboardFrameEndUserInfoKey
Undefined symbol: _UIApplicationDidBecomeActiveNotification
Undefined symbol: _UIWindowLevelNormal
Undefined symbol: _UIKeyInputDownArrow
Undefined symbol: _OBJC_CLASS$_UIView
Undefined symbol: UIKeyInputRightArrow
Undefined symbol: _OBJC_CLASS$_UIImageView
Undefined symbol: OBJC_CLASS$_UIScreen
Undefined symbol: OBJC_METACLASS$_UIViewController
Undefined symbol: OBJC_CLASS$_UIViewController
Undefined symbol: _UIKeyInputUpArrow
Undefined symbol: _CGSizeFromString
Undefined symbol: _UIKeyInputLeftArrow
Undefined symbol: _UITrackingRunLoopMode
Undefined symbol: _UIApplicationMain

Leave a Reply