Issues with porting Xcode MacOS game template to СMake - objective-c

I want to integrate basic Objective-C and Metal code to my cross-platform C++ framework to allow MacOS target. I tried to port MacOS Game template to CMake as it is a build system that I use and I have no experience with Metal and Objective-C. I tried to do it manually and using this tool and able to generate similar Xcode project and here the best result that I've got so far.
cmake_minimum_required (VERSION 3.4)
project( ConvertTest C)
set( PROJECT_HEADERS
ConvertTest/AppDelegate.h
ConvertTest/GameViewController.h
ConvertTest/ShaderTypes.h
ConvertTest/Renderer.h
)
set( SOURCES
ConvertTest/AppDelegate.m
ConvertTest/GameViewController.m
ConvertTest/Renderer.m
ConvertTest/main.m
)
set( STATIC_DEPENDENCIES
)
if( NOT SKIP_FIND_FOUNDATION_LIBRARY)
find_library( FOUNDATION_LIBRARY Foundation)
message( STATUS "FOUNDATION_LIBRARY is ${FOUNDATION_LIBRARY}")
endif()
set( DEPENDENCIES
${FOUNDATION_LIBRARY}
)
set( GLOBAL_RESOURCES
ConvertTest/Assets.xcassets
)
set( BASE_RESOURCES
ConvertTest/Base.lproj/Main.storyboard
ConvertTest/Shaders.metal
)
set( RESOURCES
${GLOBAL_RESOURCES}
${BASE_RESOURCES}
)
##
## ConvertTest
##
add_executable( ConvertTest MACOSX_BUNDLE
${SOURCES}
${PUBLIC_HEADERS}
${PROJECT_HEADERS}
${PRIVATE_HEADERS}
${RESOURCES}
)
target_link_libraries( ConvertTest
${STATIC_DEPENDENCIES}
${DEPENDENCIES}
)
set_source_files_properties(
${RESOURCES}
PROPERTIES
MACOSX_PACKAGE_LOCATION
Resources
)
if (APPLE)
set_target_properties( ConvertTest PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ConvertTest-Info.plist.in"
)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} \
-framework AppKit \
-framework Metal \
-framework MetalKit \
-framework ModelIO"
)
endif()
And Plist template:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE
plist
PUBLIC
"-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd"
>
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSMainStoryboardFile</key>
<string>Main</string>
</dict>
</plist>
There are 2 differences with CMake-generated project in runtime:
In template project NSError *error; pointers are initialised with nil and with garbage value in CMake-generated project. Obviously, I can initialise it manually, but what makes the difference?
Then it fails on loading ColorMap texture. It is in Assets.xcassets in both projects and I can't find what is wrong in CMake-generated one. The error message is:
Error creating texture Could not get asset catalog from supplied bundle
Internal structure of bundles looks the same.

Okay, I found solution for the first issue:
target_compile_options( ConvertTest PUBLIC "-fobjc-arc" )
For the second the culprit was in empty MACOSX_BUNDLE_GUI_IDENTIFIER and MACOSX_BUNDLE_BUNDLE_NAME variables required for plist generation.

Related

Build helloworld GUI with QtCreator and CMAKE

I have build a hello world GUI with QtCreator using a qmake and .pro file.
I want to build the same hello world with QtCreator but with a CMAKE file
I followed this and was able to build the application successfully.
But when I run the program it does not show the main window GUI. In the application output it looks as following.
21:52:36: Starting /home/mavbot/qtopen3d/build-guiCMake-Desktop_Qt_5_12_0_GCC_64bit-Default/guiCMake...
Where am I missing out..please help. My CMAKE file looks as follows:
cmake_minimum_required(VERSION 3.1.0)
project(guiCMake)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
if(CMAKE_VERSION VERSION_LESS "3.7.0")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
endif()
find_package(Qt5 COMPONENTS Widgets Core REQUIRED)
add_executable(guiCMake
mainwindow.ui
mainwindow.cpp
main.cpp
)
target_link_libraries(guiCMake Qt5::Core Qt5::Widgets)

Setting path to Clang library in CMake

I build llvm from git and want to use the libraries in a project, especially the libclang.
The "makefiles" are generated by means of CMake and for the LLVM part I found the setting LLVM_DIR to reroute the path for the llvm libraries, but for Clang I cannot find such a variable and I still see in my link line (it is a Cygwin system):
/usr/lib/libclang.dll.a /usr/lib/libclangTooling.dll.a.
Question: which environment variable do I set to get the right build Clang libraries?
The variable is Clang_DIR.
Just in case, I attach a minimalistic example of CMakeLists.txt file as well.
cmake_minimum_required(VERSION 3.12)
# Find CMake file for Clang
find_package(Clang REQUIRED)
# Add path to LLVM modules
set(CMAKE_MODULE_PATH
${CMAKE_MODULE_PATH}
"${LLVM_CMAKE_DIR}"
)
# import LLVM CMake functions
include(AddLLVM)
include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${CLANG_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
add_definitions(${CLANG_DEFINITIONS})
add_llvm_executable(myTool main.cpp)
set_property(TARGET myTool PROPERTY CXX_STANDARD 11)
target_link_libraries(myTool PRIVATE clangTooling)

How can I link a library to my executable in cmake?

I have 2 libs and 1 executable in my CMakeList.txt. I would like everything linked into the executable.
cmake_minimum_required( VERSION 2.8 )
# Mark the language as C so that CMake doesn't try to test the C++
# cross-compiler's ability to compile a simple program because that will fail
project( jsos C ASM )
set( CMAKE_EXECUTABLE_OUTPUT_PATH "./build/" )
# We had to adjust the CMAKE_C_FLAGS variable in the toolchain file to make sure
# the compiler would work with CMake's simple program compilation test. So unset
# it explicitly before re-setting it correctly for our system
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0" )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g" )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostartfiles" )
# Set the linker flags so that we use our "custom" linker script
set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${PROJECT_SOURCE_DIR}/etc/linker.ld" )
add_library(duktape STATIC
src/libs/duktape/duktape.c
)
add_library(fdlibm STATIC
src/libs/fdlibm/e_acos.c
src/libs/fdlibm/e_acosh.c
src/libs/fdlibm/e_asin.c
MORE FILES
)
add_executable(kernel
src/start.S
src/kernel.c
src/cstartup.c
src/cstubs.c
src/rpi-gpio.c
src/rpi-interrupts.c
src/rpi-armtimer.c
src/rpi-systimer.c
)
add_dependencies(kernel fdlibm duktape)
target_link_libraries(kernel fdlibm duktape)
add_custom_command(
TARGET kernel POST_BUILD
COMMAND ${CMAKE_OBJCOPY} ./kernel${CMAKE_EXECUTABLE_SUFFIX} -O binary ./kernel.img
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Convert the ELF output file to a binary image"
)
At the moment when I link these together I get a bunch of errors like:
[100%] Linking C executable kernel
libduktape.a(duktape.c.obj): In function `duk_double_trunc_towards_zero':
src/libs/duktape/duktape.c:12102: undefined reference to `fabs'
src/libs/duktape/duktape.c:12102: undefined reference to `floor'
But fabs and floor are in fdlibm. duk_double_trunc_towards_zero is in the duktape library so that seemed to link OK. What am I doing wrong?
In your statement:
target_link_libraries(kernel fdlibm duktape)
the external referece symbols to be resolved are searched from the ordered list of libs provided (fdlibm duktape in this case) in this way:
starting from the library being linked;
searching the symbols on the libraries on the right of it;
In your case, when resolving external symbols of duktape (which some are in fdlibm), fdlibm is not even used for this search, and the symbols duktape requires are not found. Just putting fdlibm after duktape will let the symbols to be found.
For example, if you had a fdlibm depending on some symbols defined in duktape, and also the other way around, you should use:
target_link_libraries(kernel fdlibm duktape fdlibm)
so that symbols are always resolved.

how to use framework using Cmake?

For Macos, I'd like to link to some framework. In windows, I would like to link to some library.
For example, OpenGL Framework, how to express this requirement using cmake?
You could try the following code:
target_link_libraries(<target name>
"-framework AVFoundation"
"-framework CoreGraphics"
"-framework CoreMotion"
"-framework Foundation"
"-framework MediaPlayer"
"-framework OpenGLES"
"-framework QuartzCore"
"-framework UIKit"
)
To tell CMake that you want to link to OpenGL, add the following to your CMakeLists.txt:
find_package(OpenGL REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR})
target_link_libraries(<your program name> ${OPENGL_LIBRARIES})
find_package will look for OpenGL and tell the rest of the script where OpenGL is by setting some OPENGL* variables. include_directories tells your compiler where to find OpenGL headers. target_link_libraries instructs CMake to link in OpenGL.
The following code will do different actions based on the operating system:
if(WIN32)
#Windows specific code
elseif(APPLE)
#OSX specific code
endif()
You could try the following macro code:
macro(ADD_OSX_FRAMEWORK fwname target)
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(${target} PUBLIC "${FRAMEWORK_${fwname}}/${fwname}")
MESSAGE(STATUS "Framework ${fwname} found at ${FRAMEWORK_${fwname}}")
endif()
endmacro(ADD_OSX_FRAMEWORK)
Example
ADD_OSX_FRAMEWORK(Foundation ${YOUR_TARGET}) # Add the foundation OSX Framework
You can find this example code here
For custom framework
cmake version 3.20.1
https://github.com/Sunbreak/cli-breakpad.trial/blob/master/CMakeLists.txt#L10-L12
if(APPLE)
find_library(BREAKPAD_CLIENT Breakpad "${CMAKE_CURRENT_SOURCE_DIR}/breakpad/mac/")
target_link_libraries(cli-breakpad PRIVATE ${BREAKPAD_CLIENT})

CMakeLists.txt for an Objective-C Project

I am working on simply creating a hello world executable on macOS using Objective-C and CMake. I understand that CMake does not natively support building Objective-C. You must first add the
set(CMAKE_C_FLAGS "-x objective-c")
or
set(CMAKE_CXX_FLAGS "-x objective-c++")
for the Makefile to even be created. The part where I'm getting stuck is how to appropriately link the existing frameworks. I've followed both the instructions in this post as well as the tutorial it's based off of: Can't link MacOS frameworks with CMake
I've also tried linking the libraries with:
set(CMAKE_EXE_LINKER_FLAGS "-framework fm1-framework fm2…")
I can now get a successful CMake generated Xcode project, but when I open the project, none of the frameworks I specified in the CMakeLists.txt file are in the 'resources' folder. Using this Xcode project, I can get the project to compile, but when I run the executable I get the error:
"2014-01-06 18:02:35.859 HelloWorld[62641:303] No Info.plist file in application bundle or no NSPrincipalClass in the Info.plist file, exiting
Program ended with exit code: 1"
I also tried manually running the makefile made by CMake in the terminal and got many many warnings (during linking) all saying:
CMakeFiles/HelloWorld.dir/AppDelegate.m.o:3:2252: warning: null character
ignored [-Wnull-character]
...
CMakeFiles/HelloWorld.dir/AppDelegate.m.o:3:2263: warning: null character
ignored [-Wnull-character]
...
And 7 errors (during linking):
CMakeFiles/HelloWorld.dir/AppDelegate.m.o:1:1: error: expected unqualified-id
<U+0007>
CMakeFiles/HelloWorld.dir/AppDelegate.m.o:3:90: error: expected unqualified-id
...H<89>uH<89>U]fffff.<U+000F><U+001F><84>
CMakeFiles/HelloWorld.dir/AppDelegate.m.o:3:121: error: extraneous closing brace
('}')
...}H<89>uH<8B>uH<8B>=
CMakeFiles/HelloWorld.dir/AppDelegate.m.o:3:122: error: expected unqualified-id
...H<89>uH<8B>uH<8B>=
CMakeFiles/HelloWorld.dir/AppDelegate.m.o:3:169: error: extraneous closing brace
('}')
...}H<89>uH<89>UH<8B>uH<8B>=
CMakeFiles/HelloWorld.dir/AppDelegate.m.o:3:170: error: expected unqualified-id
...H<89>uH<89>UH<8B>uH<8B>=
CMakeFiles/HelloWorld.dir/AppDelegate.m.o:3:2246: error: expected unqualified-id
...16#0:8
Any ideas on what I'm during wrong? I've spent the better portion of the day looking for answers and the post I referenced had the most useful information, but it still didn't fix my problem. Is it because the original program is also written in Xcode? And somehow that's messing up the CMake?
Here's the code for my HelloWorld app:
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[])
{
return NSApplicationMain(argc, argv);
}
And the code for the CMakeLists.txt file:
cmake_minimum_required(VERSION 2.8)
project(HelloWorld)
set(src_files
AppDelegate.h
AppDelegate.m
main.m
)
set(CMAKE_C_FLAGS "-x objective-c")
set(CMAKE_CXX_FLAGS "-x objective-c++")
set(CMAKE_EXE_LINKER_FLAGS "-framework Cocoa -framework AppKit -framework CoreData - framework Foundation")
add_executable(HelloWorld
${src_files}
)
Indirectly thanks to ruslo and the source code located here: https://github.com/forexample/cocoa-app I figured out the problem. It appears for CMake to work with a plist generated by Xcode, one MUST use the command line instructions specified in the README.md in the above mentioned repo. The GUI implementation of CMake will NOT work because the GUI has trouble interpreting the plist file. For clarity, I'll list them here:
cd to the directory containing the CMakeLists.txt file.
cmake -H. -B_OutputDirectory -GXcode
cmake --build _OutputDirectory/
open _OutputDirectory/HelloWorld.xcodeproj/
The other issue I encountered was that my plist and MainWindow.xib weren't included in my original CMake file. After adding the MainWindow.xib and the HelloWorld-info.plist necessary code, I was able to generate a usable Xcode project. Here's the code for reference:
cmake_minimum_required(VERSION 2.8)
project(HelloWorld)
set(NAME HelloWorld)
set(CMAKE_C_FLAGS "-x objective-c")
set(HEADER_FILES
./uhdplayerengine/HelloWorld/HelloWorld/AppDelegate.h
)
set(SOURCE_FILES
./uhdplayerengine/HelloWorld/HelloWorld/AppDelegate.m
./uhdplayerengine/HelloWorld/HelloWorld/main.m
)
set(XIB_FILE
./uhdplayerengine/HelloWorld/HelloWorld/Base.lproj/MainMenu.xib
)
add_executable(
${NAME}
MACOSX_BUNDLE
${HEADER_FILES}
${SOURCE_FILES}
${XIB_FILE}
)
set_source_files_properties(
${XIB_FILE}
PROPERTIES
MACOSX_PACKAGE_LOCATION
Resources
)
set_target_properties(
${NAME}
PROPERTIES
MACOSX_BUNDLE_INFO_PLIST
./uhdplayerengine/HelloWorld/HelloWorld/HelloWorld-Info.plist
)
target_link_libraries(${NAME}
"-framework Cocoa"
"-framework AppKit"
"-framework CoreData"
"-framework Foundation"
)
I hope this saves someone else a headache! Thanks ruslo!
Actually cmake support both objc and objc++ starting from 3.16 (check release notes)
You can use CMAKE_OBJCXX_FLAGS and CMAKE_OBJC_FLAGS to specify specific flags.
Also don't forget to call enable_language(OBJC) or enable_language(OBJCXX)
P.S. Here is related PR https://gitlab.kitware.com/cmake/cmake/-/merge_requests/3811