[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Swift calling into GNUStep Progress
From: |
dr_clow |
Subject: |
Re: Swift calling into GNUStep Progress |
Date: |
Sun, 20 Aug 2023 16:09:50 -0500 |
I'm not familiar (yet) with StepTalk. I will look into it.
> On Aug 17, 2023, at 6:03 PM, Ondrej Florian <onflapp@yahoo.com> wrote:
>
> I am just wondering, would it make sense to make this part of
> https://github.com/onflapp/libs-steptalk ?
> I was able to get quite far with it.
> It is even possible to create GUI app now (see
> https://github.com/onflapp/libs-steptalk/blob/master/Examples/AppKit/app.st)
>
> On 2023-08-11 03:35:22 +0200 dr_clow@me.com wrote:
>
>> Hello Friends,
>> I just wanted to give you a little update regarding my progress. All of this
>> can also be viewed on my GitHub at
>> <https://github.com/austintatiousness/GNUStepSwiftBridge/>
>> NSObjects and Subclassing
>> I have two classes that help bridge Swift classes to Objective-C (1)
>> GNUStepNSObjectWrapper and (2) GNUStepNSObjectSubclassConstructor. The
>> former
>> is used to simply wrap Objective-C NSObjects and the latter is used to
>> register subclasses with the GNUStep Objective-C runtime. All classes crated
>> with GNUStepNSObjectSubclassConstructor get a special Ivar '___swiftPtr '
>> intended to hold a reference back the Swift. Once you use
>> GNUStepNSObjectSubclassConstructor to create a new subclass, you can then
>> wrap it using GNUStepNSObjectWrapper.
>> I've actually had to do this already, within the Swift AppKit API, I've
>> subclassed NSButton as "NSButtonForSwift" but expose it as NSButton to the
>> Swift API. This allows me to use closures instead of target/selectors.
>> I don not currently like how I am using ___swiftPtr to hold a reference to
>> the Swift object created with any class registered with
>> GNUStepNSObjectSubclassConstructor, but it is the best solution I could come
>> up keep track of who owns the Objective-C object.
>> I understand that on Apple platforms, Swift actually emits Objective-C
>> compatible Swift objects when @objc or inheriting from NSObject occurs,
>> which
>> allows them casted on either side correctly.
>> NSString, NSArray and NSDictionary are all going to be problematic types
>> because there is currently no way to share storage like in Apple's Swift
>> implementation. I think that some work needs to be done here to figure this
>> out. That is beyond my abilities. For now, I am just going to be copying
>> data
>> between them.
>>
>> Currently, variables for like NSButton 'var title: String' take a String
>> type
>> and I just convert between NSString when getting and setting (I wish we
>> could
>> offer both, but Swift doesn't allow that) ; but when we have functions like
>> "func setTitle(string: String)" I plan to also offer "func setTitle(string:
>> NSString)" so we do not have to do any copying.
>> Additionally, NSArray and NSDictionary are only going to be able to store
>> Objective-C types. On Apple Platforms,
>>
>> Regarding Sending Messages / Calling Method: I've to figure out how to use
>> objc_msgSend and objc_msgSend_stret from Swift, so instead I am now using
>> class_getMethodImplementation. Which has been incredibly successful. I
>> created some helper swift functions called objc_smart_getIMP to aid in
>> setting these up better.
>> API Bridging Update:
>> I've gotten some of the the GUI objects going: NSWindow, NSButton, NSImage,
>> NSImageView, NSFont, NSColor. You can get and set frames. It's pretty cool.
>>
>>
>>
>>
>>
>>> On Aug 8, 2023, at 8:56 PM, dr_clow@me.com wrote:
>>
>>> UPDATE: SUCCESS!
>>
>>> Since I sent that last email. I had a little break through.
>>> Then GNUStep ObjC function class_getMethodImplementation (Apple also has
>>> function class_getMethodImplementation_stret that is evidently not used in
>>> GNUStep and is just a stub) and allows one to look up the C function that
>>> is precisely used with the function.
>>> So I created a nice Swift version of this lookup. public func
>>> objc_smart_getIMP<T>(object: GNUStepNSObjectWrapper, selector: String) ->
>>> T? {
>>> let c = object_getClass(&object._nsobjptr!.pointee)
>>> let v = class_getMethodImplementation(c, sel_getUid(selector))
>>> let rt: T? = unsafeBitCast(v, to: T.self)
>>> return rt
>>> }
>>
>>> And then in the the var frame property of my NSView wrapper the following
>>> public var frame: CGRect {
>>> get {
>>> var imp: (@convention(c) (id, SEL) -> (CGRect))? =
>>> objc_smart_getIMP(object: self, selector: "frame")
>>> if let rtn = imp?(&self._nsobjptr!.pointee,
>>> sel_getUid("frame")) {
>>> return rtn
>>> }
>>> return .init(x: 0, y: 0, width: 0, height: 0)
>>> }
>>> set {
>>> guard let selfPtr = self._nsobjptr else {return}
>>> let _: Any? = objc_smart_sendMessage(object: self,
>>> selector:
>>> "setFrame:", value1: newValue)
>>> }
>>> }
>>
>>> RESULT: It worked!
>>
>>> When Swift Macros are working on Linux, this could be a Macro that
>>> generates everything we need. Maybe @GNUStepPropertyWrapper("frame",
>>> "getFrame") We could also have @GNUStepMethodWrapper that automatically
>>> wraps the method callers.
>>
>>
>>>> On Aug 8, 2023, at 7:48 PM, dr_clow@me.com wrote:
>>
>>>> One of the issues that I am identifying is trying to manage the functions
>>>> `objc_msgSend ` and `objc_msgSend_stret `. I did a write up on my GitHub
>>>> for this project, and (as of right now) am trying to come up with
>>>> solutions to getting the right memory out of calls to `objc_msgSend ` and
>>>> `objc_msgSend_stret `.
>>>> Basically I need a way to make objc_msgSend_stret more generic.
>>>> Also what datatype size does objc_msgSend_stret service vs objc_msgSend. I
>>>> am assuming, that objc_msgSend is good for pointers and datives that are
>>>> the size of pointers?
>>
>>>> You can view my evolving discussion with myself at
>>>> https://github.com/austintatiousness/GNUStepSwiftBridge
>>
>>>> - Austin
>>>> objc_msgSend and objc_msgSend_stret
>>
>>>> objc_msgSend() is a c function used by the Objective-C runtime to send
>>>> messages. Unfortunately it has a variable arguments which cannot be
>>>> imported into Swift. To overcome this, I have created some specialized
>>>> versions of of objc_msgSend that have different number of arguments. These
>>>> can be found in the ObjCSwiftInterop.c file.
>>
>>>> Ultimately, I would like a swift version of this which more intelligently
>>>> decides how to map the values. I started work on this, in the AppKit.swift
>>>> file called func objc_smart_sendMessage<T>(object:
>>>> NSObjectGNUStepSwiftBridge, selector: String, value1: Any?, value2: Any?,
>>>> value3: Any?, value4: Any?, value5: Any?, value6: Any?, value7: Any?,
>>>> value8: Any?, value9: Any?) -> T?
>>
>>>> This solves the problem that we have to send messages of arbitrary side,
>>>> but it does not solve the issues around casting, and that two separate
>>>> functions objc_msgSend and objc_msgSend_stret depending on which type we
>>>> are going to get back from.
>>
>>>>
>>>> <https://github.com/austintatiousness/GNUStepSwiftBridge/blob/main/README.md#casting>CASTING
>>
>>>> Just some thoughts and notes: Please correct me where I am wrong or
>>>> misunderstanding.
>>
>>>> objc_msgSend and objc_msgSend_stret are very difficult functions to
>>>> properly import into Swift. objc_msgSend is used for messages that return
>>>> Objective-C classes, and simple data values that have the same size as id
>>>> . From what I understand, both require the the function to be properly
>>>> cast to work and because they are implemented in assembly and they are
>>>> doing some magic with the registers to properly get the result.
>>>> objc_msgSend returns void* but objc_msgSend_stret on GNUStep's runtime
>>>> returns void. Before you can use objc_msgSend_stret, you have to cast it
>>>> to a function that returns the value you are expecting.
>>
>>>> UIView *view = [[NSView alloc] initWithFrame:NSRectZero];
>>
>>>> NSRect (*sendRectFn)(id receiver, SEL operation);
>>>> sendRectFn = (NSRect(*)(id, SEL))objc_msgSend_stret;
>>>> NSRect frame = sendRectFn(view, @selector(frame));
>>>> Idea 1: THIS DOES NOT WORK. I really have no idea what I am doing.
>>
>>>> void* forSwift_objcMsgSend_stret(id ID, SEL cmd, int64_t returnSize) {
>>>> void* itemArr = malloc(returnSize);
>>>> void* (*sendRectFn)(id receiver, SEL operation);
>>>> sendRectFn = (void(*)(id, SEL))objc_msgSend_stret;
>>>> itemArr = sendRectFn(ID, cmd);
>>>> return itemArr;
>>>> }
>>>> What we need to be able to do is express this in Swift using
>>
>>>> I do not know how the objc_msgSend_stret knows what the returned data type
>>>> should be.
>>
>>>>> On Aug 8, 2023, at 4:56 AM, Gregory Casamento
>>>>> <greg.casamento@gmail.com> wrote:
>>
>>>>> M A,
>>
>>>>> I guess you could consider the issues and such on github as a todo list.
>>>>> You are welcome to take on any tasks on there if you like. Each repo has
>>>>> it's own "Issues" tab where you can see what issues are outstanding. Or
>>>>> if you can think of features that you think might be useful, please
>>>>> discuss it here and we can all work together to make it happen if it
>>>>> sounds reasonable.
>>
>>>>> Wrapping an ObjC class around swift sounds interesting, though most
>>>>> people go the other way around these days... Swift->ObjC.
>>
>>>>> Yours, GC
>>
>>>>> On Mon, Aug 7, 2023 at 1:58 PM M A <teammember0x01@gmail.com
>>>>> <mailto:teammember0x01@gmail.com>> wrote:
>>>>>> A to do list would be a great edition to this project's website.
>>
>>>>>> One thing I would add it making a program that can wrap an Objective-c
>>>>>> class around Swift code. There are just too many classes and methods to
>>>>>> do it all by hand.
>>
>>>>>>> On Aug 7, 2023, at 1:51 PM, Gregory Casamento <greg.casamento@gmail.com
>>>>>>> <mailto:greg.casamento@gmail.com>> wrote:
>>>>>>>> I am extremely impressed!!! This is great! Please let me know if I
>>>>>>> can help in any way.
>>>>>>>> GC
>>>>>>>> On Mon, Aug 7, 2023 at 10:35 AM <dr_clow@me.com
>>>>>>> <mailto:dr_clow@me.com>> wrote:
>>>>>>> Gregory, > > Thank you. I over last night, I was able to solve almost
>>>>>>> all the issues with calling into GNUStep's AppKit and Foundation. I've
>>>>>>> been able to set up buttons that respond to selectors, create objects
>>>>>>> at runtime and register them with the runtime. Right now, I am working
>>>>>>> on generalizing a sort of "Smart" version of obj_msgSend that allows me
>>>>>>> to not have to write a separate version of that handles each type
>>>>>>> parameters. As it is now, the only way I am getting it to work is to
>>>>>>> make a version of objc_msgSend that explicitly takes, for example, an
>>>>>>> NSRect, or id. > > This is probably because I just don't fully
>>>>>>> understand how pointers work in Swift. If anyone has any idea of how we
>>>>>>> can generalize the function, I would greatly appreciate it. Thanks!
>>>>>>>> Below is a screen shot of a working app written in Swift. The button
>>>>>>> does work and does open the other window. It's pretty cool. You can see
>>>>>>> the code on my GitHub. It's messy still. > > > <Image 8-7-23 at
>>>>>>> 9.33 AM.jpeg>
>>>>>>>>> On Aug 6, 2023, at 7:59 PM, Gregory Casamento
>>>>>>> <greg.casamento@gmail.com <mailto:greg.casamento@gmail.com>> wrote:
>>>>>>>>>> Hey, I just want you to know that this is VERY VERY cool!!! Yours,
>>>>>>>> GC
>>>>>>>>>> On Sun, Aug 6, 2023 at 12:05 PM <dr_clow@me.com
>>>>>>>> <mailto:dr_clow@me.com>> wrote:
>>>>>>>> I have solved the NSWindow initializer issue. I didn't realize I was
>>>>>>>> passing Swift's Foundation.NSRect and not the C version. Sill haven't
>>>>>>>> solved the issues regarding adding new ObjC classes to the runtime at
>>>>>>>> runtime through Swift. Any ideas here would be appreciated. >> >> The
>>>>>>>> image below is an GNUStep app written in Swift. The Menu is from the
>>>>>>>> GORM file from the Terminal (I had to start somewhere!)
>>>>>>>>>> <Screenshot 2023-08-06 at 10.54.06 AM.png>
>>>>>>>>>>>>> On Aug 5, 2023, at 9:03 PM, dr_clow@me.com
>>>>>>>> <mailto:dr_clow@me.com> wrote:
>>>>>>>>>>>> I just wanted to update everyone on my progress and solicit some
>>>>>>>>> help if possible.
>>>>>>>>>>>> State of my progress: >>> I've had a lot of success patching into
>>>>>>>>> GNUStep's libobjc2 C runtime from within Swift. I've been able to
>>>>>>>>> create NSWindows through Swift, call methods, et cetera. You can see
>>>>>>>>> my progress here
>>>>>>>>> https://github.com/austintatiousness/GNUStepSwiftBridge . This
>>>>>>>>> assumes that you're running this from within OnFlapp's GNUStep
>>>>>>>>> Desktop. >>> >>> Solution to objcSendMessage: >>> Because Swift
>>>>>>>>> doesn't allow variable argument parameters, I had to create various
>>>>>>>>> versions of objcSendMessage (e.g forSwift_objcSendMessage1,
>>>>>>>>> forSwift_objcSendMessage2, forSwift_objcSendMessage3) to accommodate
>>>>>>>>> various number of arguments. >>> >>> Problem 1: NSWindow
>>>>>>>>> initWithContentRect:styleMask:backing:defer
>>>>>>>>>>>> 1) I am having trouble with the NSWindow.initWith… functions. I
>>>>>>>>> am sure that it is because of the way that I am casting all the
>>>>>>>>> values from Swift into to the C implementation. Either I just don't
>>>>>>>>> understand how the casting between Swift and C works OR I am just
>>>>>>>>> using the wrong variables. I include a C version of the NSRect
>>>>>>>>> struct in my project. >>> >>> let nsWindowClass =
>>>>>>>>> objc_getClass("NSWindow")
>>>>>>>>> var allocatedObject =
>>>>>>>>> forSwift_objcSendMessage(&nsWindowClass!.pointee,
>>>>>>>>> sel_registerName("alloc"))
>>>>>>>>>>>> var styleMask: UInt64 = 1 + 2 + 4
>>>>>>>>> var backingStoreType: UInt64 = 0
>>>>>>>>> var deferr: UInt8 = 0
>>>>>>>>> var rect = NSRect(x: 200, y: 200, width: 300, height: 300)
>>>>>>>>>>>> allocatedObject =
>>>>>>>>> forSwift_objcSendMessage4(&allocatedObject!.pointee,
>>>>>>>>> sel_registerName("initWithContentRect:styleMask:backing:defer:"),
>>>>>>>>> &rect, &styleMask, &backingStoreType, &deferr)
>>>>>>>>>>>> I've tried several times to change the various integer types from
>>>>>>>>> UInt64 to UInt8 to no avail. >>> >>> Problem 2: Registering new
>>>>>>>>> classes with the runtime. >>> This is the current state of the
>>>>>>>>> HelloWorld target: >>> >>> For reasons I cannot explain, I am able to
>>>>>>>>> allocate a new obj-c object with objc_allocateClassPair and then
>>>>>>>>> register it using objc_registerClassPair but when objc_getClass using
>>>>>>>>> the same class name that I registered, it returns nil.
>>>>>>>>>>>> Any help would be appreciated. I am currently unable to make
>>>>>>>>> progress on adding delegates with out being able to register new ObjC
>>>>>>>>> classes with the runtime. >>> >>> Thanks!
>>>>>>>>>>>>>> -- >> Gregory Casamento
>>>>>>>> GNUstep Lead Developer / OLC, Principal Consultant
>>>>>>>> http://www.gnustep.org <http://www.gnustep.org/> -
>>>>>>>> http://heronsperch.blogspot.com <http://heronsperch.blogspot.com/>
>>>>>>>> https://www.patreon.com/bePatron?u=352392 - Become a Patron
>>>>>>>> https://www.openhub.net/languages/objective_c - OpenHub standings
>>>>>>>>>> -- > Gregory Casamento
>>>>>>> GNUstep Lead Developer / OLC, Principal Consultant
>>>>>>> http://www.gnustep.org <http://www.gnustep.org/> -
>>>>>>> http://heronsperch.blogspot.com <http://heronsperch.blogspot.com/>
>>>>>>> https://www.patreon.com/bePatron?u=352392 - Become a Patron
>>>>>>> https://www.openhub.net/languages/objective_c - OpenHub standings
>>
>>
>>
>>
>>>>> --
>>>>> Gregory Casamento
>>>>> GNUstep Lead Developer / OLC, Principal Consultant
>>>>> http://www.gnustep.org <http://www.gnustep.org/> -
>>>>> http://heronsperch.blogspot.com <http://heronsperch.blogspot.com/>
>>>>> https://www.patreon.com/bePatron?u=352392 - Become a Patron
>>>>> https://www.openhub.net/languages/objective_c - OpenHub standings
>>
>>
>>
>>
>
>
- Re: Swift calling into GNUStep Progress, (continued)
- Re: Swift calling into GNUStep Progress, dr_clow, 2023/08/07
- Re: Swift calling into GNUStep Progress, Gregory Casamento, 2023/08/07
- Re: Swift calling into GNUStep Progress, M A, 2023/08/07
- Re: Swift calling into GNUStep Progress, dr_clow, 2023/08/07
- Re: Swift calling into GNUStep Progress, Gregory Casamento, 2023/08/08
- Re: Swift calling into GNUStep Progress, dr_clow, 2023/08/08
- Re: Swift calling into GNUStep Progress, dr_clow, 2023/08/08
- Re: Swift calling into GNUStep Progress, dr_clow, 2023/08/10
- Re: Swift calling into GNUStep Progress, Gregory Casamento, 2023/08/11
- Re: Swift calling into GNUStep Progress, Ondrej Florian, 2023/08/17
- Re: Swift calling into GNUStep Progress,
dr_clow <=