How to create a MacOS app bundle with cmake - macos

This can be considered as a follow-up to CMake MacOS X bundle with BundleUtiliies for Qt application
I want to create a MACOS bundle on CI which can be used by users for an open source project.
What I have:
Main executable
Updater executable
icon file
helper script calling updater then main
data files in a folder (translations etc, some generated at build time)
plugin shared libs
What I've done so far:
add MACOSX_BUNDLE to the executable
add icon to its sources and to RESOURCE property
set MACOSX_BUNDLE_* properties
install everything in a cross-platform way (regular install(TARGETS calls and install(FILES for the resources)
But now I'm stuck on how to get those into the bundle w/o to much manual work.
From the linked question I got something like this:
set(APPS "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}.app")
set(LIBS )
set(DIRS "${CMAKE_BINARY_DIR}")
# Path used for searching by FIND_XXX(), with appropriate suffixes added
if(CMAKE_PREFIX_PATH)
foreach(dir ${CMAKE_PREFIX_PATH})
list(APPEND DIRS "${dir}/bin" "${dir}/lib")
endforeach()
endif()
install(CODE "include(BundleUtilities)
fixup_bundle(\"${APPS}\" \"${LIBS}\" \"${DIRS}\")")
But:
Why do I need to pass the *.app path manually? CMake does already know it, doesn't it?
LIBS should contain my plugins, shouldn't it? But what? Paths? Target names?
DIRS is also a mystery to me. No documentation even in CMake 3.12 (I'm still using 2.8.12 though :( )
How to add my generated and regular data files? Probably same or similar to the icon? But what about the generated ones?
Help, pointers to examples, full CMakeLists doing that etc. very welcome.
Note: I'm cross-compiling from linux on the CI and NOT using Qt so e.g. macdeployqt or so is out of question.

Just got stuck on the same issue and google brought me here.
This worked for me:
set(CUR_TARGET myappname)
add_executable(${CUR_TARGET} MACOSX_BUNDLE ${MY_SRC})
set_target_properties(${CUR_TARGET} PROPERTIES
BUNDLE True
MACOSX_BUNDLE_GUI_IDENTIFIER my.domain.style.identifier.${CUR_TARGET}
MACOSX_BUNDLE_BUNDLE_NAME ${CUR_TARGET}
MACOSX_BUNDLE_BUNDLE_VERSION "0.1"
MACOSX_BUNDLE_SHORT_VERSION_STRING "0.1"
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/customtemplate.plist.in
)
The file customtemplate.plist.in is based on the cmake template from the cmake dir subfolder at your_cmake_install_dir/share/cmake/Modules/MacOSXBundleInfo.plist.in

Related

Run make install command in cmake from another cmake file

We have multiple libraries in different folder, The main application needs to build those libraries in other folders and install them to output folder and then the main application needs to link to libraries to build executable.
I am able to build the libraries present in other folders using add_subdirectory() in a loop, but I am not able to install them to output folder by main cmake file. Could anyone help me out on this.
The main application needs to build those libraries in other folders and install them to output folder and then the main application needs to link to libraries to build executable.
It is not necessary in CMake to install libraries in order to link to them. You can build the libraries and have your main executable link to them without installing the libraries. When you need to install your application as a whole, you can install libraries along with the executable if needed i.e. if the libraries are shared ones and not static ones.
One example of how you can organize things: assume you have the following structure in your project:
CMakeLists.txt # root of project
|
|--lib
| |--CMakeLists.txt # library subproject
|
|--app
|--CMakeLists.txt # app subproject
Then your root CMakeLists.txt can look like this:
project(MyProject)
add_subdirectory(lib)
add_subdirectory(app)
The lib subproject's CMakeLists.txt can look like this:
project(MyLib)
set(SOURCES <...>) # specify library's sources
add_library(${PROJECT_NAME} ${SOURCES})
set(MyLib ${PROJECT_NAME} CACHE INTERNAL "")
The last line in the snippet above is aimed to make MyLib variable available everywhere within the project. I found this trick here and used it successfully in my projects. Maybe there are better options here, if anyone knows them, feel free to suggest.
The app's CMakeLists.txt can then look like this:
project(MyApp)
set(SOURCES <...>) # specify app's sources
add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} ${MyLib})
I haven't covered the installation here but it's actually straightforward: if your libraries are static ones, you only need to install the executable using install TARGETS. If your libraries are shared ones, you need to install them along with the executable.

Visual studio and dlib: "cannot open include file: 'zlib.h': No such file or directory"

For my thesis I want to use Dlib's face_landmark_detection, but I keep running into these errors (for both Visual studio 2013 as well as 2015):
"cannot open include file: 'zlib.h': No such file or directory"
and
"'F77_INT': undeclared identifier".
It repeats itself so I have 36 errors based on these two problems.
My supervisor has given me some steps to follow to set up the project:
add dlib-master and dlib-master\examples to VC++ directories -> include directories
add dlib-master\dlib\external\libjpeg and dlib-master\dlib\entropy_decoder to C/C++ -> General -> Additional include directories
add all folders and items from dlib-master\dlib\external (cblas, libjpeg, libpng and zlib) to the project source folder
add the dlib source file (from dlib-master\dlib\all) and add face_landmark_detection (from dlib-master\examples) to the project source folder.
and according to him this has worked on every other computer so far, but on my laptop it just won't. We checked to project, but zlib.h is in the zlib folder in the project. Does anyone here have an idea on what might be going wrong?
If I didn't give enough info, please ask. I don't know what else might be needed to solve this.
I have just come about this same problem and wanted to post my solution since I have found so much conflicting documentation on the subject.
The folder containing the dlib folder as well as the libpng, libjpeg, and zlib folders from dlib/external need to be added to the additional include directories list in the solution settings.
dlib/all/source.cpp as well as the source files for libpng, libjpeg, and zlib also need to be added to the project.
Note that CBLAS should not be added to the project in any way, because it needs Fortran to compile, and it is very difficult to get this to compile from Visual Studio.
Finally, make sure to add DLIB_PNG_SUPPORT and DLIB_JPEG_SUPPORT as preprocessor defines in the project settings.
I also attempted to use a cmake generated solution, however, for some reason it had trouble with png support.
It is probably easiest to use CMake to configure your project which uses dlib. It avoids setting all those paths manually. During CMake configure step you can disable usage of libraries like zlib which you don't have/want/need. Here is an example CMakeLists.txt which works for me:
cmake_minimum_required(VERSION 2.6)
PROJECT(DatasetClassifier CXX C)
set(dlib_DIR "" CACHE PATH "Path to dlib") # http://dlib.net/
include(${dlib_DIR}/dlib/cmake)
ADD_EXECUTABLE(DatasetClassifier DatasetClassifier.cpp)
TARGET_LINK_LIBRARIES(DatasetClassifier ${dlib_LIBRARIES})

Where does mac osx app require dependent libraries?

I have built a Qt project under mac, but I have problems executing.
Its dependencies have several dylib .
When building the project, the make tool only asks for one of the libs (for example lib.1.0.0,dylib out of lib.1.dylib, lib.1.0.dylib, lib.1.0.0.dylib, lib.1.0.0.0.dylib) - so I know to put it in the .pro file
Some look like links - but it is not always the lib version that looks like a file that is required as a dependency.
But at run time, I don't know which dylib I need, and where to put it.
I tried to place all 4 lib versions in the folder where the app was created - the project folder - but the app didn't execute.
Having done the same in Linux, I had to put the libs in a place set on path - like /usr/local/libs
Where does mac like its libs (shared libs ?) in order to run ?
You should read this document on deploying Qt applications. It will answer your questions. Moving your libraries to a system library path is usually not a good idea.
http://qt-project.org/doc/qt-5/macosx-deployment.html
To sum this up though you need to change the binaries to tell them where the libs are using the otool command.

How to get a path of the app bundle in a CMake script to supply it to the fixup_bundle()?

I have a cross-platform application for the Win and Mac OSX platforms written in C++, Qt and a little bit of Objective C. After a period of supporting two unrelated platform specific projects (VS 2010 and xCode) we decided to create a single CMake script. We generate a platform specific project and work with it.
After a pretty long delving I have managed to compile and link my application. But there are still plenty problems with creating a proper bundle (without any efforts xCode just creates a binary). After setting a few variables xCode compiles and creates a dummy bundle without a plist file and app's executable. So I need to copy all required frameworks and resources to the bundle.
I've tried a few approaches to create a bundle. The first one was to use SET_SOURCE_FILES_PROPERTIES( ${resourcePath} PROPERTIES MACOSX_PACKAGE_LOCATION ${pathInsideBundle} ) and adding them (frameworks\resources) to ADD_EXECUTABLE like this: ADD_EXECUTABLE( FranchiseTracker MACOSX_BUNDLE ${headers} ${sources} ${form_headers} ${resources_rcc} ${thirdparty_sources} ${BUNDLE_COPY_RESOURCES} ). And it worked out - I've managed to copy an icon and the Sparkle framework to the bundle, but the problem was that I couldn't copy the Qt frameworks, because FIND_PACKAGE left the ${QT_LIBRARIES} variable empty, so I couldn't get the paths to copy frameworks "manually".
Now I'm gonna use the "fix_bundle" approach because it promises me to copy all required resources without my intervention. So, here is my code related to fixup_bundle():
# Fixup bundle, copy dynamic libraries into app bundle
SET( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/out )
SET( APPS "\${CMAKE_CURRENT_BINARY_DIR}/out/${APP_NAME}.app" ) # paths to executables
SET( DIRS "${CMAKE_SOURCE_DIR}/osx/FRP/vendors/libraries/lib" ) # directories to search for prerequisites
INSTALL( CODE "
include(BundleUtilities)
fixup_bundle(\"${APPS}\" \"\" \"${DIRS}\")
")
Now I'm stumped by a little refinement. The thing is stubborn xCode persists to generate and write my bundle in ${CMAKE_CURRENT_BINARY_DIR}/out/Debug and thus fixup_bundle can't find any bundle at all.
My specific question (as in the title): How can I get the correct path (with Debug) in the CMake script? I wanna avoid to hardcode the path with Debug, because that will be wrong in a case of archiving.
My more common question: Is there an easier way of creating bundles for a Qt application with CMake? Maybe the whole my approach is wrong?
P.S. I have posted the full script to Code Review here.
P.P.S. For those who will consider my question as too verbose. The reason I've posted the full script and written my attempts (except I want to get it working) is that there is little info on the internet about working with Mac OSX frameworks, bundles, etc in CMake. I had to read a lot of mailing lists because I couldn't find any structured tutorials or at least a decent documentation. And the only source to learn were other scripts written by other people. So I hope my script and explanations will help someone.
I've finished with using only the macdeployqt utility on the Mac OSX platform. I use xCode to build my application, so I've solved the path issue with xCode's macros ${CONFIGURATION} like that:
....
elseif( APPLE )
ADD_EXECUTABLE( FranchiseTracker MACOSX_BUNDLE ${headers} ${sources} ${form_headers} ${resources_rcc} ${thirdparty_sources} ${BUNDLE_COPY_RESOURCES} )
SET_TARGET_PROPERTIES( FranchiseTracker PROPERTIES OUTPUT_NAME ${APP_NAME} )
SET_TARGET_PROPERTIES( FranchiseTracker PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/osx/FRP/info.plist") #or else you'll get an auto generated plist
# Fixup bundle, copy dynamic libraries into app bundle
ADD_CUSTOM_COMMAND( TARGET FranchiseTracker COMMAND macdeployqt ARGS ${CMAKE_CURRENT_BINARY_DIR}/\${CONFIGURATION}/${APP_NAME}.app ) # add -dmg for an image
endif( WIN32 )
Pay attention to escaping the $ character to prevent ${CONFIGURATION} from being expanded as a CMake variable.
P.S. The code I've posted to CodeReview is a little bit outdated, so if anybody stumbles the same issue (with creating a bundle on OSX) and wants to see the full working variant, just let me know and I'll post it somewhere (maybe update my post on CodeReview).

Linking Macports libraries to XCode application

I'm trying to distribute my app's dependencies with the app.
I've got the macports packages librsvg, boost, and cairo installed 64-bit-only on my Snow Leopard system. When I create an .app bundle of my program, it does not work on machines without macports and the relevant libraries installed because they are not included with the app, which searches for the libraries in /opt.
I have tried the --static flag for static linking, but that caused libcrt0 errors.
What's the best method for linking MacPorts libraries and their dependencies to an OSX application suitable for lone distribution?
You'll want to copy the libraries into your application bundle, using a Copy Files Build Phase. dylibs should be put in the Frameworks directory in the app bundle. You'll also have to add the libraries to your Xcode project.
Try using py2app to create a stand-alone app.
I had to just do this for jsoncpp. What I did was I went to linker settings under the project > Build Phases > Link Binary With Libraries then used the add other to go to my library's path and add the library from the folder which would be under opt/local/lib in the default setup for macport
getting the header files was a bit more complicated. In this case I had ended up going to usr/Include finding the file/folder with the headers, copying it into my project and in the cpp file I added the include line with quotation marks ("")
e.g., moved /usr/Include/json directory into the RestTemplate Project folder using copy. then added to main.cpp
#include "json/json.h"

Resources