Build SDL2 projects for iOS with Xcode 11

I created a cross-platform video game. It’s runs well on Windows, Mac, Linux, Android, and iOS. If you want to play the game, it is called Pimple Frenzy, it is super fun, and can be installed from the App Store or Google Play:

   

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