25

This is closely related to my previous question, which was about using CMake to build a static library on the iPhone. I got that to work setting the CMAKE_OSX_SYSROOT.

However, this doesn't work to build an app. My CMakeLists.txt looks like:

project(TEST)

set(CMAKE_OSX_SYSROOT iphoneos2.2.1)
set(CMAKE_OSX_ARCHITECTURES "$(ARCHS_STANDARD_32_BIT)")
set(CMAKE_EXE_LINKER_FLAGS
"-framework Foundation -framework OpenGLES -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework OpenAL"
)

set(SRC --my files--)

add_executable(iphone-test MACOSX_BUNDLE ${SRC})

A few notes:

  • I'm explicitly giving the -framework linking option because find_library didn't work for all of the frameworks (it found most of them, but not OpenGLES). I don't understand why, since they're all in the same folder ${SDK}/System/Library/Frameworks. This leads me to believe that I was doing something wrong, but I don't know what.
  • I added MACOSX_BUNDLE to the add_executable command so that the product type generated would be com.apple.product-type.application instead of com.apple.product-type.tool, which apparently doesn't exist on the iPhone.

In any case, the app compiles and links correctly, but when I run it in the simulator, I get the dreaded

Failed to launch simulated application: Unknown error.

There are lots of reported instances of this problem on google and stackoverflow, but all of the solutions involve cleaning up or creating a new project and moving files; but I'm compiling a fresh copy after CMake does its work, so none of that applies.

I found this thread on the CMake mailing list, but it only reports a success in building a library, and then peters out.

Community
  • 1
  • 1
Jesse Beder
  • 33,081
  • 21
  • 109
  • 146

3 Answers3

43

I finally figured out how to do this. Here's what my CMakeLists.txt file looks like:

project(test)
set(NAME test)

file(GLOB headers *.h)
file(GLOB sources *.cpp)

set(CMAKE_OSX_SYSROOT iphoneos2.2.1)
set(CMAKE_OSX_ARCHITECTURES $(ARCHS_STANDARD_32_BIT))
set(CMAKE_CXX_FLAGS "-x objective-c++")
set(CMAKE_EXE_LINKER_FLAGS
    "-framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit"
)
link_directories(\${HOME}/\${SDKROOT}/lib)

set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.mycompany.\${PRODUCT_NAME:identifier}")
set(APP_TYPE MACOSX_BUNDLE)

add_executable(${NAME}
    ${APP_TYPE}
    ${headers}
    ${sources}
)

target_link_libraries(${NAME}
    # other libraries to link
)

# code signing
set_target_properties(${NAME} PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer: My Name")

Obviously, change mycompany to your company name, and change My Name to your name. I found it's very useful to add the link directory \${HOME}/\${SDKROOT}/lib as above, so that if your app links to a static library (especially a generic (non-iPhone) library), you can build separate iPhoneOS and iPhoneSimulator libraries and easily link to the right one, instead of worrying about a universal binary.

Also, Xcode doesn't seem to properly add resources when you build the project using CMake, so I added this piece to the CMakeLists.txt file. It copies the entire folder /data into my resources folder (as if I had added a "blue" folder link in Xcode).

# copy resource phase

set(APP_NAME \${TARGET_BUILD_DIR}/\${FULL_PRODUCT_NAME})
set(RES_DIR ${test_SOURCE_DIR}/data)
add_custom_command(
    TARGET ${NAME}
    POST_BUILD
    COMMAND /Developer/Library/PrivateFrameworks/DevToolsCore.framework/Resources/pbxcp -exclude .DS_Store -exclude CVS -exclude .svn -resolve-src-symlinks ${RES_DIR} ${APP_NAME}
)
Jesse Beder
  • 33,081
  • 21
  • 109
  • 146
  • I found your answer very helpful - I was really lost with CMake and Xcode. I tried using a slightly modified version of your CMakeLists file. However, I ran into some weird problems. Could you perhaps take a look at my question? http://stackoverflow.com/questions/5473448/cmake-and-xcode-cannot-find-interface-declaration-for-nsobject Thanks in advance :) – Shade Mar 29 '11 at 14:11
  • 2
    There is another way for the resources now, see here: http://cmake.org/gitweb?p=cmake.git;a=blob;f=Tests/iOSNavApp/CMakeLists.txt However, this removes the directory hierarchy, so duplicate filenames are a problem... – Jan Rüegg Jun 27 '13 at 14:58
9

For frameworks, I found this message http://www.mail-archive.com/cmake@cmake.org/msg24659.html I grabbed enough information for this:

SET(TARGETSDK iPhoneOS3.1.2.sdk)
SET(CMAKE_OSX_SYSROOT /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/${TARGETSDK})
macro(ADD_FRAMEWORK fwname appname)
    find_library(FRAMEWORK_${fwname}
        NAMES ${fwname}
        PATHS ${CMAKE_OSX_SYSROOT}/System/Library
        PATH_SUFFIXES Frameworks
        NO_DEFAULT_PATH)
    if( ${FRAMEWORK_${fwname}} STREQUAL FRAMEWORK_${fwname}-NOTFOUND)
        MESSAGE(ERROR ": Framework ${fwname} not found")
    else()
        TARGET_LINK_LIBRARIES(${appname} ${FRAMEWORK_${fwname}})
        MESSAGE(STATUS "Framework ${fwname} found at ${FRAMEWORK_${fwname}}")
    endif()
endmacro(ADD_FRAMEWORK)

Instead of setting CMAKE_EXE_LINKER_FLAGS, now I do:

ADD_FRAMEWORK(AudioToolbox MyApp)
ADD_FRAMEWORK(CoreGraphics MyApp)
ADD_FRAMEWORK(QuartzCore MyApp)
ADD_FRAMEWORK(UIKit MyApp)

This does work for OpenGLES as well.

mtoy
  • 583
  • 1
  • 5
  • 13
  • This seems to add the frameworks in the "Other Linker Flags" AKA OTHER_LDFLAGS but it doesn't add anything to the header "Header Search Paths" AKA HEADER_SEARCH_PATHS so my code can't find UIKit/UIKit.h. Suggestions? – Emmanuel Sep 19 '13 at 17:48
1

Recent CMake versions pass .m and .mm files to the C++ compiler, which detects the language through the extension, so you don't need to add "-x objective-c++" to the flags explicitly.

  • 2
    Oh yeah, that's just incidental to the script. I actually have mostly .cpp files (since I'm cross-compiling), so I do need that. – Jesse Beder Jul 08 '09 at 02:29
  • @JesseBeder: Why do you compile `.cpp` files as objective-C++? We compile `.cpp` files as C++ and have a handful of `.mm` files with the platform-specific functionality that needs to interact with Cocoa. – Jan Hudec Apr 23 '12 at 10:51
  • @JanHudec, some of my `.cpp` files conditionally include Objective-C (with an `#ifdef`), so when compiled for the iPhone, they do interact with Objective-C (and so should be considered Objective-C++), but when compiled for PC, they don't (so should be considered C++). – Jesse Beder Apr 23 '12 at 17:20