1

In an iOS c++/Qt application, I need to ship a few files and to keep them in their directory structure.

For the Android version, we bundle a zip which we unzip on the target before creating the QApplication.

On iOS, it seems that CMake is not capable of bundling files in a tree: https://cmake.org/cmake/help/latest/prop_tgt/RESOURCE.html#prop_tgt:RESOURCE https://cmake.org/cmake/help/latest/prop_sf/MACOSX_PACKAGE_LOCATION.html

I am not sure if this is a limitation of cmake or if this is a global limitation on iOS. From the docs about iOS bundles:

It uses a relatively flat structure with few extraneous directories in an effort to save disk space and simplify access to the files.

What would be the preferred approach?

  1. Is there a solution to ship the files from CMake directly?
  2. If not, how can I achieve this so that they are available before the QApplication is created?

The xcode command

Thanks to @Cy-4AH, I added the folder in Xcode and could get the command to do this:

CpResource _PATH_TO_DIRECTORY_ _APP_BUNDLE_DIRECTORY_/_RESOURCE_DIR_NAME_
cd /Users/denis/opt/qfield/ios/QField
export PATH="....."
builtin-copy -exclude .DS_Store -exclude CVS -exclude .svn -exclude .git -exclude .hg -strip-debug-symbols -strip-tool /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip -resolve-src-symlinks _PATH_TO_DIRECTORY_ _APP_BUNDLE_DIRECTORY_

But how can I create this from cmake? builtin-copyis an xcode command.


Simple system copy command

From an old (2008) discussion, we could use simple cp commands. This works up to signing, but then I get an error unsealed contents present in the bundle root.

From this answer, it seems related that I cannot simply add folders in the resource directory. From the docs anatomy of framework bundles: Nonlocalized resources reside at the top level of the Resources directory

Denis Rouzaud
  • 2,412
  • 2
  • 26
  • 45
  • 1
    Just put in app bundle ‍♂️. You can look in xcode build logs how it copy files into bundle and make same calls with `CMake` – Cy-4AH Nov 23 '20 at 09:27
  • Thanks a lot @Cy-4AH, this brought me further. But the question still remain on how I can trigger this from cmake without actually doing this in xcode. – Denis Rouzaud Nov 24 '20 at 05:31
  • I don't entirely remember how we solved this issue, years back, but I remember I added the files as under source_group in CMake. and from objective-c, I just access it without files so something like [[NSBundle mainBundle] pathForResource:@"test" ofType:@"txt"]; – Hady Nourallah Nov 26 '20 at 00:08

3 Answers3

1

(Disclaimer: I'm not a CMake user, and there may be a more CMake-ey way to do this)

If you can set up post-build action, the following terminal script can efficiently sync files into your bundle from another location. I use it in my game engine because it only copies updated or new files upon subsequent builds, and preserves directory structure:

mkdir -p PATHTO/ORIGINFOLDERNAME
mkdir -p PATHTOBUILDFOLDER/PROJECTNAME.app/Contents/Resources/DESTINATIONFOLDERNAME
rsync -avu --delete --exclude=".*" PATHTO/ORIGINFOLDERNAME/ PATHTOBUILDFOLDER/PROJECTNAME.app/Contents/Resources/DESTINATIONFOLDERNAME

The mkdir commands are only to ensure that the folders are generated, if they were deleted.

  • That is actually what is doing Xcode behind its builtin-copy. This would be an acceptable solution. But in the end the cmake command is working will with directories. I am giving you the bounty as this would be a solution. Thanks! – Denis Rouzaud Nov 30 '20 at 07:18
  • 1
    Oh man, thanks for the bounty! It's my pleasure! – theOtherMichael Dec 01 '20 at 04:03
0

So apparently the CMake method also works for directories.

target_sources(${QT_IOS_TARGET} PRIVATE ${_resource})
set_source_files_properties(${_resource} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)

It will just be added at the root directory of the bundle and not within the Resources.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Denis Rouzaud
  • 2,412
  • 2
  • 26
  • 45
0

If the embedded file is not too big, you might consider :

  • in your source tree, generating a C++ file embedding that file as a constant array. For example, if your file contains just hello, world with a new line, you could have something like

    /// file contents.cc
    const char file_contents[] = "hello, world\n";
    

and at the beginning of your program (perhaps in your main function, before your QApplication) call a C++ function which writes such a file (perhaps in /tmp/).

  • in your build automation (e.g your Makefile or your qmake things), have something which generates the C++ contents.cc file from the genuine source

This is with a POSIX/Linux point of view, adapt my answer to your iOS.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • This seems quite clumsy. A similar approach would be to join a zip file in the resource and unzip it (to embed several files and a directory structure). Cheers. – Denis Rouzaud Nov 30 '20 at 07:19