Programatically checking for NSBundle in macOS - objective-c

I am building my application for macOS using CMake. My application can either be MACOSX_BUNDLE i.e. generated as a .app through CMake or it can even be a Unix-style executable.
Is there a programmatic way in Obj-C to check if the executable is Unix-Style or NSBundle?

Assuming you use Foundation and Objective-C in both binaries it is possible to check using NSBundle properties, because bundle instance itself will created on both cases (it just references to folder around executing binary), but bundle info will be present only on macOS.
So here is possible approach:
if (nil != [[NSBundle mainBundle] bundleIdentifier]) {
// macOS code here
} else {
// linux code here
}

Related

Linphone SDK OS X - vcard_grammar

I’m trying to integrate linphone-sdk-Mac from https://download.linphone.org/releases/macosx/sdk/ to my objective c app.
Basically what I’m doing is extracting zip file and import framework files to my project and then change all frameworks to “embed and sign” and then compile.
Program runs fine until I try to create the core, even using “ linphone_factory_create_core_with_config_3” or “ linphone_factory_create_core_3”, they all crash with the same error, that is “could not load grammar vcard_grammar because the file could not be located”.
Already tried to put grammar files in several places of the project, on different versions, including last one, but with no luck.
Anyone know anyway to solve this?
Sample code:
LinphoneFactory *factory = linphone_factory_get();
NSString *linphonecfg = [LinphoneManager bundleFile:#"linphonerc"];
NSString *fileStr = [NSString stringWithContentsOfFile:linphonecfg encoding:NSUTF8StringEncoding error:nil];
configDb = linphone_config_new_from_buffer(fileStr.UTF8String);
theLinphoneCore = linphone_factory_create_core_with_config_3(factory, configDb, NULL);
Already tried to compile linphone-desktop but that is failing in random places every time I try to compile it, so could not solve that way.
Thanks
So after a lot of tinkering with the SDK, I've figured out to fix the vCard issue and compile properly without it on macOS with Swift/Objective-C (for arm64 and x86_x64).
Compiling SDK
Install the following dependencies with homebrew:
brew install pkg-config cmake doxygen nasm yasm
Install pip3/python3 (if you haven't already) and it's dependencies:
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python3 get-pip.py
pip3 install pystache
pip3 install six
Clone the latest Linphone SDK and it's dependencies recursively
git clone --recursive https://gitlab.linphone.org/BC/public/linphone-sdk
Make and set the build directory (-DENABLE_VCARD=OFF is the key here):
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_VCARD=OFF ..
cmake --build .
Xcode Integration
(if the build succeeded, hopefully)
In your build folder, go into your linphone-sdk/desktop folder
You should see a couple of different folder but the most important ones are Frameworks and share
Add the Frameworks and share folder into your Xcode project with the following options checked:
If you're using Swift, you will need to create a Objective-C bridging header with the following lines to avoid a giant list of errors in your LinphoneWrapper.swift in the share/linphonesw folder:
#import "linphone/factory.h"
#import "linphone/types.h"
#import "linphone/core.h"
#import "linphone/call.h"
#import "linphone/tunnel.h"
#import "linphone/wrapper_utils.h"
#import "linphone/core_utils.h"
#import "linphone/vcard.h"
#import "belle-sip/object.h"
#import "bctoolbox/list.h"
#import "mediastreamer2/msfactory.h"
In the Frameworks, Libraries, and Embedded Content section of your apps target, every framework should be "Embed & Sign".
Try compiling and accessing Core, Factory, etc... in a Swift file and it should work, if it doesn't, comment below and I'll try to help you out!

`[[NSBundle mainBundle] bundleIdentifier]` is nil when running XCTest

Even when it is defined in the "...Tests" target Info.plist, the identifier remains nil. I need it to have a valid value for a third party lib.
This is because unit tests don't load your application bundle or even the unit test bundle as the main bundle.
For more info on this see
NSURL to file path in test bundle with XCTest
XCTest fails when calling [NSBundle mainBundle]
Now we can hack around this by including a category on NSBundle in your unit test project. The Objective-C category hack also works for swift unit tests because Bundle is bridged to NSBundle, just make sure you have a bridged header for your unit test project.
You can then have it search for the correct main bundle, but if you just want a quick and dirty way to have a valid bundle identifier then use the following
#interface NSBundle (BundleIdentifier)
-(NSString *)bundleIdentifier;
#end
#implementation NSBundle (BundleIdentifier)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
-(NSString *)bundleIdentifier
{
return #"com.yourcompany.yourapp.unitTests";
}
#pragma clang diagnostic pop
#end
Now all that is left is to include the header file in your unit test so that the category loads up.

Qt5 can't seem to find Objective-C libraries: unknown type name 'NSAutoreleasePool', etc

I have a Qt4.8.4 desktop application that builds and runs fine on my Macbook Pro, running Mountain Lion with Xcode 5.0.2, using Qt Creator 2.7.0 with Qt 4.8.4 and GCC (x86 64bit). I am trying to port my application to Qt 5.2.1. My code is C++ with some Objective-C.
I built Qt5.2.1 on my same Macbook pro with this configuration:
./configure -prefix $PWD/qtbase -debug-and-release -developer-build -no-c++11 -opensource -plugin-sql-sqlite -nomake tests -confirm-license
and it configured and built fine.
When I try to build my application in Qt Creator 2.7.0 using Qt 5.2.1 and either GCC (x86 64bit) or Clang (x86 64bit), I get lots of errors that seem to me to indicate that the Objective-C parts of my application can't find the libraries they need. For example:
/Users/david/dev/svn/map_creator3/src/widgets/mac_toolbar_button_proxy.mm:15: warning: instance method '-selectedSegment' not found (return type defaults to 'id') [-Wobjc-method-access]
target_->TriggerAction([sender selectedSegment]);
^~~~~~~~~~~~~~~
/Users/david/dev/svn/map_creator3/src/common/locations_mac.mm:34: error: use of undeclared identifier 'NSWorkspace'
[[NSWorkspace sharedWorkspace]
^
/Users/david/dev/svn/map_creator3/src/widgets/mac_toolbar_button_control.mm:30: error: unknown type name 'NSAutoreleasePool'
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
^
and lots more like that. Is there some magic setting somewhere that I need to add, to use Object-C in a C++ Qt5 desktop application?
Merlin069 got me on the right track in the comments on my question (thanks!), and I found an example here. These build errors (and a number of others) disappeared when I added
LIBS += -framework Cocoa
and in my .mm files that were complaining,
#include <Cocoa/Cocoa.h>

OSX Bundle Architecture

I need to compare the architecture of a bundle and compare it to the machines architecture from an installer; if they match the installation will proceed else it will abort.
Getting the architecture is easy by using macros; I would like to know if there is a way of checking the architecture of the bundle to be installed.
From the shell, you can do
otool -hv <path to mach-o image>
Images are usually in Contents/MacOS in applications or Versions/Current in frameworks
This will determine if the current application (or whatever bundle determined to be the mainBundle) shares a common architecture with the target bundle. Requires Mac OS X 10.5 for NSBundle's executableArchitectures method.
NSArray *targetArch = p[NSBundle bundleWithPath:#"/path/to/bundle.bundle"] executableArchitectures];
NSArray *thisArch = [[NSBundle mainBundle] executableArchitectures];
if ([targetArch firstObjectInCommonWithArray:thisArch])
{
// target bundle has architecture which matches current application
}

Unable to Compile Objective C using Gnustep on windows

Hi i am a beginner learning objective c.
i am finding an error "hello.m:1:34: Foundation/Foundation.h: No such file or directory"
i came to know that i need to make a make file
may i know how to make the make file please
No need to create a makefile. If you start MinGW from "All Programs -> GNUstep -> Shell" as Pax indicates above, you can just compile your .m file.
My GNUstep installation is in c:\GNUstep\GNUstep\System. If yours is different, you should change the import of Foundation.h accordingly.
I did this:
Create c:\myprogs\obj-c\hello\hello.m that looks like this:
//---------- Hello.m
#import <../../GNUstep/System/Library/Headers/Foundation/Foundation.h>
int main(int argc, const char* argv[])
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSLog(#"Hello from Hello.m!");
[pool release];
return 0;
}
//----------
Start MinGW shell. (See above.)
On shell command line, change to directory where program code is located. (Note that, since this is not Unix, the Windows drive letter must be included.):
cd /c/myprogs/obj-c/hello
Compile the program:
gcc -o hello hello.m -I/c/GNUstep/GNUstep/System/Library/Headers \
-L /c/GNUstep/GNUstep/System/Library/Libraries -lobjc -lgnustep-base \
-fconstant-string-class=NSConstantString
(Note that "\" character allows us to extend command to multiple lines.)
I get the following informational messages when I compile:
Info: resolving ___objc_class_name_NSAutoreleasePool by linking to __imp____objc_class_name_NSAutoreleasePool (auto-import)
Info: resolving ___objc_class_name_NSConstantString by linking to __imp____objc_class_name_NSConstantString (auto-import)
Running resulting hello.exe gives me this:
2009-06-03 14:44:59.483 hello[1240] Hello from Hello.m!
That problem just looks like you haven't instructed gcc on where to find the relevant include files (i.e., the directory in which Foundation/Foundation.h resides).
Are you running gcc from under MinGW or from the command prompt. You should have a "All Programs -> GNUstep -> Shell" on your Start menu which brings up this shell.
A makefile for this should be as simple as:
include $(GNUSTEP_MAKEFILES)/common.make
TOOL_NAME = YourProg
YourProg_OBJC_FILES = source_code.m
include $(GNUSTEP_MAKEFILES)/tool.make
If you will put your source codes into home directory in GNUStep, you don't need to provide relative location of Foundation framework.
Using a makefile such as the one specified by paxdiablo is probably the easiest, because rather than trying to remember an arcane command line each time, you set up the makefile and then call make from the source folder.
However, my experience under Windows suggested that GNUStep and Windows, even with the shell, won't build using that because it can't find all the make files it needs - add an environment variable GNUSTEP_MAKEFILES with a value of /GNUstep/System/Library/Makefiles and restart that shell, and then any errors from it being unable to find the standard makefiles should be history.
(I had tried using full paths to the makefiles, but found that this included the specific makefiles but then failed when trying to include further ones, hence going the easy route and adding an environment variable.)