Using multiple Objective-C header files in Swift project - c

I would like to use the AAPLRendererUtils and AAPLMathUtilities files from the following Apple sample code in a Swift project.
I have created a bridging header where I have imported "APPLMathUtilities.h" and it works just fine. However, when I try to import "AAPLRendererUtils.h" I run into issues.
AAPLRendererUtils.h is a header-only file and does not follow the usual Objective-C #interface and #implementation pattern.
AAPLRendererUtils.h also imports APPLMathUtilities.h so maybe this dependency is an issue?
#import "AAPLMathUtilities.h"
//----------------------------------------------------------------------------------------
struct Camera
{
vector_float3 position;
vector_float3 target;
float rotation;
float aspectRatio; // width/height
float fovVert_Half; // half of vertical field of view, in radians
float distanceNear;
float distanceFar;
matrix_float4x4 GetViewMatrix () const
{
return matrix_look_at_left_hand(position, target, (vector_float3){0,1,0});
}
matrix_float4x4 GetProjectionMatrix_LH () const
{
return matrix_perspective_left_hand (
fovVert_Half * 2.f,
aspectRatio,
distanceNear,
distanceFar);
}
};
Interestingly, if I comment out the function declarations the code runs but if I leave them in I get the following error:
field 'GetViewMatrix' declared as a function
Since you cannot have functions in structs in C am I correct in thinking that Xcode is interpreting this file as a C file?

This is not a C header, it is a C++ header. The files that this gets included in, in the sample document, all have the ".mm" extension which is Objective-C++. C++ does allow structs to have methods (it's basically a class where all the members are public, IIRC). I know a couple of years ago, Swift was not very good at working with C++ files. I don't know if that's changed. You could probably separate the methods from the struct to make a C file and a header if you are diligent enough.

Related

Calling C function with Bitmap data from Flutter

My mission is to take a picture using the camera, send the pixels to C function, and provide a message to the user if the function returns an indication of a problematic image (e.g.: poor focus, picture too dark, etc).
I want to call a C function and send a pointer to the function which includes the pixels (and other parameters like image width/height). The idea is to use the C code and check the image quality.
The C code is ready. I found samples how to bind it into Flutter. But I do not know how to get the Bitmap data and pixels and send them to the C function.
You can do that binding to native code using dart:ffi.
Imagine that you have a C function that returns the sum of two numbers with this code:
#include <stdint.h>
extern "C" __attribute__((visibility("default"))) __attribute__((used))
int32_t native_add(int32_t x, int32_t y) {
return x + y;
}
And this C Makefile
cmake_minimum_required(VERSION 3.4.1) # for example
add_library( native_add
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
../native_add.cpp )
Now you need to encapsulate this CMake file into the externalNativeBuild inside build.gradle, this could be an example:
android {
// ...
externalNativeBuild {
// Encapsulates your CMake build configurations.
cmake {
// Provides a relative path to your CMake build script.
path "CMakeLists.txt"
}
}
// ...
}
Now that you have the library and you have encapsulated the code you can load the code using the FFI library like this:
import 'dart:ffi'; // For FFI
import 'dart:io'; // For Platform.isX
final DynamicLibrary nativeAddLib = Platform.isAndroid
? DynamicLibrary.open("libnative_add.so")
: DynamicLibrary.process();
And with a handle to an enclosing library you can resolve the native_add symbol as we do here:
final int Function(int x, int y) nativeAdd =
nativeAddLib
.lookup<NativeFunction<Int32 Function(Int32, Int32)>>("native_add")
.asFunction();
Now you could use it on your application calling the nativeAdd function, here you have an example:
body: Center(
child: Text('1 + 2 == ${nativeAdd(1, 2)}'),
),
You can learn how flutter native code binding works in the following url: flutter docs c-interop

Setting file path in imported C function inside Swift Framework

I am trying to use C library source files inside my Cocoa Framework which has function named
void swe_set_ephe_path(char *path);
Which will basically be
swe_set_ephe_path(”C:\\SWEPH\\EPHE”);
for windows.
This library contains other data files which only work after this function is set.
When imported to Swift the function looks like this
swe_set_ephe_path(path: UnsafeMutablePointer<Int8!>)
Since i want to bundle up all the data files in framework and use it in my application, i have done something like this
public class SwissEphemeris {
public init() {
let path = Bundle.main.bundlePath
let swePath = UnsafeMutablePointer<Int8>(mutating: (path as NSString).utf8String)
swe_set_ephe_path(swePath)
}
}
But it seems it's not working and the functions which needs data to be searched in files are not able to operate.
If anybody interested to look into Swiss library documentation, check here for the link,
https://www.astro.com/swisseph/swephprg.htm#_Toc505244836
There are two problems:
First, the resource files are in the “Resources” subdirectory of the framework, not in the top-level framework directory. You can obtain a path to that directory with
let resourcePath = Bundle(identifier: "com.Abhi.SwissFramework")!.resourcePath!
or with
let resourcePath = Bundle(for: type(of: self)).resourcePath!
I suggest to force-unwrap the optionals because you know that the bundle and the resources directory exist. A failure would indicate a build problem which should be detected early.
Second, the C function takes a char * argument even though it does not mutate the passed string. Here you can use the approach from UnsafeMutablePointer<Int8> from String in Swift:
resourcePath.withCString {
swe_set_ephe_path(UnsafeMutablePointer(mutating: $0))
}
Even better: use the dedicated method withUnsafeFileSystemRepresentation() to get the file system representation of the resource path as a C string:
let resourceURL = Bundle(for: type(of: self)).resourceURL!
resourceURL.withUnsafeFileSystemRepresentation {
swe_set_ephe_path(UnsafeMutablePointer(mutating: $0))
}

c2hs bind both typedef and function

I am trying to properly create haskell bindings for function in C, that is split up in 2 files.
file1.h: typedef const char* fmi2GetTypesPlatformTYPE(void);
file2.h: __declspec(dllexport) fmi2GetTypesPlatformTYPE fmi2GetTypesPlatform;
To match this in Haskell I have created a similar structure, but this is where the trouble is.
file1.chs: type fmi2GetTypesPlatformTYPE = {#type fmi2GetTypesPlatformTYPE#}
How do I create a Haskell function pointer using this type? I have imported the file with {#import file1 #}, but I am lost on how to accomplish the last part.
See https://github.com/haskell/c2hs/issues/142
I will post the answer once resolved (unless Ian-ross beats me to it :) )

Make Eclipse list (only) all enum entries on assignment of variable of enum type

The Eclipse <CTRL>+<SPACE> code completion assist feature doesn't work with enums the way I want to. Can anyone tell me how to configure it so that I get the follow:
In my C (not C++) project I'm using typedef enums and would like that Eclipse provides a list of all enum entries on <CTRL>+<SPACE> (or maybe another key combination) if I'm typing an assignment of a variable of this enum type.
Example:
typedef enum {
CONSTANT_A = 0,
CONSTANT_B = 1,
CONSTANT_C = 2,
} myenumtype_t;
void func(void)
{
myenumtype_t myenumvar;
myenumvar = <CTRL>+<SHIFT>
}
It should list CONSTANT_A, CONSTANT_B, CONSTANT_C and allow me to choose one.
If it's list other enum variables of the exact same enum type then this is also ok, but I don't like any other variable in the suggestion list.
However, at the moment my Eclipse is listing basically all global and local variables indendent of their type, which isn't very useful.
PS: My Eclipse variant is Arctic Studio 5.0.0 which is basically Eclipse CDT 8.3.0.
This is not exactly what you asked for, but definitely serves the purpose.
You can type a clue, may be "CON" in your specific case, and then press ctrl + space

Does this function IOHIDManagerRegisterDeviceMatchingCallback operate under the cocoa environment?

I am struggling to implement an HID control with a Mac : I cannot send the expected function as depicted here below:
IOHIDManagerRegisterDeviceMatchingCallback( gIOHIDManagerRef, Handle_DeviceMatchingCallback, NULL );
with : gIOHIDManagerRef -> the valid HID manager dedicated to this routine
Handle_DeviceMatchingCallback --> the routine that will be called back when the HID
device is attached to the USB port
NUUL --> not used here, contain data from the USB
The issue is that Handle_DeviceMatchingCallback must be a pointer to the routine, but how can I send a pointer ?
On the other hand, all the examples , from the Apple source, are based on C, not on cocoa.
Well, does that means that I must rework my program in C ??? Or is it possible to have fraction of the program in C under the cocoa environment?
Sorry for so "stupid" question queries, but, although I have some background in the field of electronic an programming, I am very newbees with cocoa.
Your comments will be very appreciated !
Michael
Objective-C is mostly a super-set of C. In order to combine C and Objective-C code, you simply compile your C code as if it were Objective-C code. The easiest way to do this in Xcode is to ensure the file in question has a .m extension.
To route handling back to the Objective-C world, you need a pointer to an Obj-C object. Many callback-based APIs allow you to provide a generic pointer (void *) that they then pass back to you when they callback. This argument has several common names:
context or ctx
refcon (for "reference constant")
userData
userInfo
If the callback API does not allow this, you'll need some uglier way to dispatch the callback to your object, such as a global pointer or a lookup table.
The API you're using does let you provide a context pointer. When it calls back to your code, it provides you with the pointer you used when you registered for the callback. Here is an example of registering the callback from an object of type MyObjCClass (see the -registerMatching method below) and then using the context pointer to route the callback back to the object that registered the callback for handling (see the Handle_DeviceMatchingCallback function's use of the context pointer).
/*! #file C-ObjC-Callbacks.m
* Demonstrates routing a C callback to an Obj-C object
* using the callback's context pointer.
*/
#import <Cocoa/Cocoa.h>
#import <IOKit/hid/IOHIDManager.h>
// Global HID manager reference.
IOHIDManagerRef gIOHIDManager;
// HID callback
void Handle_DeviceMatchingCallback(void *context,
IOReturn result,
void *sender,
IOHIDDeviceRef device);
#interface MyObjCClass : NSObject {
}
- (void)registerMatching;
- (void)handleMatchingDevice:(IOHIDDeviceRef)device
sender:(void *)sender
result:(IOReturn)result;
#end
#implementation MyObjCClass
- (void)registerMatching {
// Assume gIOHIDManager has already been created.
// Set up a device matching callback, providing a pointer to |self| as the context.
IOHIDManagerRegisterDeviceMatchingCallback(gIOHIDManager,
Handle_DeviceMatchingCallback,
(void *)self);
}
- (void)handleMatchingDevice:(IOHIDDeviceRef)device
sender:(void *)sender
result:(IOReturn)result {
// Do something...
}
#end
void
Handle_DeviceMatchingCallback(void *context,
IOReturn result,
void *sender,
IOHIDDeviceRef device); {
MyObjCClass *const myObject = (MyObjCClass *const)context;
[myObject handleMatchingDevice:device sender:sender result:result];
}
Handle_DeviceMatchingCallback must be a pointer to the routine, but how
can I send a pointer ?
If you want to pass in a function functionName, you can pass it as
&functionName.
On the other hand, all the examples , from the Apple source, are based on
C, not on cocoa. Well, does that means that I must rework my program in C
??? Or is it possible to have fraction of the program in C under the cocoa
environment?
You can mix C and Objective-C at will. As long as you pass it a function,
and not a method attached to an object, it should work.

Resources