[cmake-developers] iOS: direction to official support and questions

Raffi Enficiaud raffi.enficiaud at mines-paris.org
Tue Aug 15 20:45:21 EDT 2017


Le 10.08.17 à 17:04, Brad King a écrit :
> On 08/08/2017 08:08 AM, Raffi Enficiaud wrote:
>> I have looked a bit to the Android toolchains, and I have to say I found
>> those quite complicated as a first reading :)
>
> This note may help:
>
>  https://gitlab.kitware.com/cmake/cmake/issues/16708#note_300971

Hi,
Thanks for the link and the answers!


> I don't think iOS will need all the toolchain and stl selection logic.
>
> Ideally CMake would gain iOS platform modules such that one could
> set CMAKE_SYSTEM_NAME to `iOS`.
>
>> set(CMAKE_FIND_ROOT_PATH
>>      ${CMAKE_IOS_DEVELOPER_ROOT}
>>      ${CMAKE_IOS_SDK_ROOT}
>>      ${CMAKE_PREFIX_PATH}
>>      /path/to/boost_1_64_0_build/install
>>      CACHE string  "iOS find search path root")
>> ```
>>
>> where this path is hard coded, and points to the fat static libraries
>> prefix path of boost. If I remove this path, FindBoost does not find the
>> boost libraries anymore (of course I am passing BOOST_ROOT). In
>> addition, I have this:
>>
>> set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
>> set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
>> set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
>
> These last three lines tell the find commands to only look at
> paths re-rooted under CMAKE_FIND_ROOT_PATH and CMAKE_SYSROOT.
> If boost is not under one of those then it won't be found.
>
>> set(CMAKE_MACOSX_BUNDLE YES)
>
> Is it possible to build any binary of any form on iOS without this?

You're right, I do not think this is possible.

> If not then the iOS platform modules should set something to tell
> the generators that this should always be enabled.
>
>> set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO")
>
> Similarly for this, but perhaps only during `try_compile`.

What I understand from this variable is that, it sets the default of 
CODE_SIGNING_REQUIRED to "NO", and this can be overriden per target by 
setting the XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED target property to 
something else.

Is that correct?

I believe that for iOS developments, the default should rather be the 
opposite, and the try_compile should be informed of not trying to sign 
the app, via "some mechanism" as you suggested.

Concerning this "some mechanism" part, what do you have in mind? Would 
it be an extra variable like 
CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED_IN_TRY_COMPILE ?

What I fail to understand here, is the purpose of the "try_compile" that 
is performed at the beginning. Isn't this try_compile supposed to 
compile source files only, without trying to link nor bundle anything? 
If this is the case, signing the result is irrelevant, and I do not 
understand why this fails.

If you have an idea, good, otherwise I believe this is secondary right now.

> I'm not familiar enough with iOS development to answer the rest of
> your questions.

Me neither :)

Currently the main issue I am seeing is the multiarch/multisysroot 
target of XCode that is kind of lost when using CMake. By 
multiarch/multisysroot, I mean that Xcode is able to switch from 
iPhoneSimulatorXY to iPhoneXY without changing the project, and within 
the same view.

The switching means changing the target architecture, as well as 
changing the SYSROOT. I checked the command lines emitted by XCode, and 
it changes the "-isysroot" flag based on the type of target.

 From the posts I can read online, this is causing a lot of troubles, 
especially when linking with libraries.

For users' libraries, the workaround is to have fat libraries by 
combining all the target archs into one with lipo. The compilation is 
done with different "-isysroot" then. What I understood is that Apple is 
discouraging this, and this is for me not a proper solution neither, but 
might work.

The real problem seems to be when linking to system libraries, those 
that are under sysroot, and I cannot find a good answer to this.

Example:

Suppose in the toolchain file, we have something like this, where 
CMAKE_IOS_SDK_ROOT depends on the fact that we use the simulator or not:

'''
set(CMAKE_FIND_ROOT_PATH
     ${CMAKE_IOS_DEVELOPER_ROOT}
     ${CMAKE_IOS_SDK_ROOT}
     ${CMAKE_PREFIX_PATH}
     /some/other/path
     CACHE string  "iOS find search path root")

# set up the default search directories for frameworks
set (CMAKE_SYSTEM_FRAMEWORK_PATH
	${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks
	${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks
	${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks
)
'''

and later in our CMakeLists, we have eg.

'''
find_package(ZLIB REQUIRED)
'''

The selection of the SYSROOT is done then on the cmd line given to 
CMake, and set up once.

The library that is found by ZLIB are related to CMAKE_IOS_SDK_ROOT, 
that is a constant in a build tree. Although Xcode can reroot the 
SYSROOT depending on the target device/arch (simulator/non-simulator).

Even if later XCode is able to switch sysroots on the command line, 
depending on the target, the libraries we are linking to are constant, 
and not honoring the dynamically determined sysroot anymore.

I believe this problem is going beyond XCode itself, as eg. Visual 
starts integrating more technologies (Xamarin, Android, Arduino, etc) to 
their IDE, and at some point the developers will want to use a simulator 
for those developments.

My current concerns are about the design of CMake. Do you think the 
current design of CMake can possibly address this issue nicely, or the 
only possibilities are workarounds?

* The fact that we have nice generator expressions can be used to
   change the location of external libraries (and the overall link
   interface) on the fly. I believe that might be used, we need to
   intercept the IDE variable that encodes the current target, and
   we might be able to use that variable jointly with the generator
   expressions.
* can we teach find_package/find_library to look for all
   similar libraries in a set of sysroots? taking back the same
   example of find_package(ZLIB), if I have, several sysroots:

   CMAKE_FIND_ROOT_PATH_IOS = /sysroot/1
   CMAKE_FIND_ROOT_PATH_IOS_SIMULATOR = /sysroot/2

   and a new variable listing all the target platforms:

   CMAKE_SYSROOT_NAMES = "IOS;IOS_SIMULATOR"

   I can think of a mechanism that teaches find_library to look
   for the same library in all of those SYSROOTS.


Concerning the variable sent by the IDE and that might encode the 
current target, we have for instance this as a prelude to the 
compilation shell script:

* for iPhone SDK
   export 
PATH="/Applications/Xcode8.1.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Applications/Xcode8.1.app/Contents/Developer/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"

* for iPhoneSimulatorSDK:
   export 
PATH="/Applications/Xcode8.1.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:/Applications/Xcode8.1.app/Contents/Developer/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"

That is a poor solution for finding out for what current target platform 
we are compiling, and I hope it would be possible to retrieve the 
current ZLIB library we should link to based on $PATH. But I do not know 
if generator expressions are that flexible. This happens right before 
the compiler is executed, and cmake cannot be involved or called there. 
I am not even sure that we can modify the scripts that XCode generate 
for compilation.

As you can see, those problems are not that Xcode or iOS specific, and 
maybe there is an elegant solution already in place, but I cannot find any.

Thanks,
Raffi



More information about the cmake-developers mailing list