如何设置CMake以构建iPhone应用程序

25

这与我之前的问题密切相关,那个问题是关于如何使用CMake在iPhone上构建静态库。通过设置CMAKE_OSX_SYSROOT,我已经成功地实现了该目标。

然而,这并不适用于构建应用程序。我的CMakeLists.txt看起来像:

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})

几点说明:

  • 我明确给出-framework链接选项,因为find_library未能找到所有的框架(它发现了大部分,但未找到OpenGLES)。我不明白为什么,因为它们都在同一个文件夹${SDK}/System/Library/Frameworks中。这让我相信我做错了什么,但我不知道是什么。
  • 我在add_executable命令中添加了MACOSX_BUNDLE,以便生成的产品类型为com.apple.product-type.application而不是com.apple.product -type.tool ,后者显然在iPhone上不存在。

无论如何,该应用程序编译和链接正确,但当我在模拟器中运行它时,会遇到可怕的...

Failed to launch simulated application: Unknown error.

在谷歌和stackoverflow上有很多关于这个问题的报告,但所有的解决方案都涉及清理或创建新项目并移动文件;但我在CMake完成工作后编译一个全新的副本,所以这些都不适用。

我在CMake邮件列表中发现了这个主题,但它只报告了构建库的成功情况,然后就停滞了。

3个回答

43

我最终弄清楚了如何做到这一点。这是我的 CMakeLists.txt 文件的样子:

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")

显然,将mycompany更改为您的公司名称,将My Name更改为您的名字。我发现将链接目录\${HOME}/\${SDKROOT}/lib添加到上面非常有用,这样如果您的应用程序链接到静态库(特别是通用(非iPhone)库),您可以构建单独的iPhoneOS和iPhoneSimulator库并轻松链接到正确的库,而无需担心通用二进制文件的问题。

此外,当使用CMake构建项目时,Xcode似乎无法正确添加资源,因此我在CMakeLists.txt文件中添加了这一段代码。它将整个/data文件夹复制到我的资源文件夹中(就像我在Xcode中添加了“blue”文件夹链接一样)。

# 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}
)

我发现你的回答非常有帮助 - 我在使用CMake和Xcode时真的很迷茫。我尝试使用稍微修改过的CMakeLists文件,但是遇到了一些奇怪的问题。你能否看一下我的问题?http://stackoverflow.com/questions/5473448/cmake-and-xcode-cannot-find-interface-declaration-for-nsobject 先谢谢了 :) - Shade
2
现在有另一种获取资源的方法,请参见此处:http://cmake.org/gitweb?p=cmake.git;a=blob;f=Tests/iOSNavApp/CMakeLists.txt。然而,这会移除目录层次结构,因此重复的文件名是一个问题... - Jan Rüegg

9

针对框架,我找到了这个信息 http://www.mail-archive.com/cmake@cmake.org/msg24659.html 我摘录了足够的信息:

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)

现在我不再设置CMAKE_EXE_LINKER_FLAGS,而是这样做:

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

这也适用于OpenGLES。

这似乎将框架添加到“其他链接器标志”即OTHER_LDFLAGS,但它不会添加任何内容到头文件“头文件搜索路径”即HEADER_SEARCH_PATHS,因此我的代码找不到UIKit / UIKit.h。有什么建议吗? - Emmanuel

1

最近的CMake版本将.m和.mm文件传递给C++编译器,通过扩展名检测语言,因此您不需要显式地添加“-x objective-c ++”标志。


2
哦,那只是脚本的附带问题。实际上我主要有 .cpp 文件(因为我在交叉编译),所以我确实需要它。 - Jesse Beder
@JesseBeder: 为什么您会将.cpp文件编译为Objective-C++呢?我们将.cpp文件编译为C++,并且有一些.mm文件,其中包含需要与Cocoa交互的特定于平台的功能。 - Jan Hudec
@JanHudec,我的一些.cpp文件在条件编译时包含Objective-C(使用#ifdef),因此在编译iPhone时,它们会与Objective-C交互(因此应视为Objective-C ++),但在PC上编译时不会(因此应视为C ++)。 - Jesse Beder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接