digitalmars.D - How To Call D Code from Objective C?
- Mike McKee (21/21) Dec 10 2015 Is there a way to call D code from Objective C on OSX?
- Rikki Cattermole (8/27) Dec 10 2015 D.learn is more appropriate but here in the "easy" answer (ignoring
- Mike McKee (39/39) Dec 10 2015 Okay, so what has been shared is that the first step is to get C
- Jacob Carlborg (5/6) Dec 10 2015 I recommend using the D compiler to compile the final application. Then
- Jacob Carlborg (10/29) Dec 10 2015 You can call Objective-C from D [1]. For the other way around, you
- Mike McKee (24/24) Dec 11 2015 I found a way to call C from in Objective C. The big trick is to
- Mike McKee (106/106) Dec 11 2015 So I'm having trouble figuring out the D and C code.
- Mike McKee (12/12) Dec 11 2015 Well, part of it was that I needed to do -shared on Linux instead
- Jacob Carlborg (15/27) Dec 11 2015 There are several issues:
- Jacob Carlborg (16/29) Dec 11 2015 "string" in D is not the same as "char*" in C. "string" is an alias to
- Jacob Carlborg (9/31) Dec 11 2015 .mm means Objective-C++. That is, combining C++ and Objective-C in the
Is there a way to call D code from Objective C on OSX? Here's something cool I was thinking about doing: * I've learned how to make Cocoa UI Objective C apps on OSX. * I've learned how to load the native OSX webkit widget in a Cocoa app. It provides a rich user interface using ordinary HTML, CSS, and Javascript/jQuery. It's much better than anything Qt has with its widgets or QML. It's much better than anything Apple allows with its other Aqua Cocoa widgets. I can make any kind of widget you can think of, colored and styled anyway I want, using webkit. * I've learned how to enable a bridge between Javascript to Objective C. This lets me make an Objective C function that Javascript can call. So, if I need my webkit app to do something powerful like show a file chooser dialog, I can call an object called "objc" and so something like: var sFilePath = objc.chooseFile(); * Now all I want to do is to bridge Objective C to D. That way, my webkit pages can call Objective C, which can then call D. I can put much of the heavy lifting work in D for my app. If I need to call an Apple Foundation Class library, I can have D call back to Objective C just for that special thing.
Dec 10 2015
On 11/12/15 7:01 PM, Mike McKee wrote:Is there a way to call D code from Objective C on OSX? Here's something cool I was thinking about doing: * I've learned how to make Cocoa UI Objective C apps on OSX. * I've learned how to load the native OSX webkit widget in a Cocoa app. It provides a rich user interface using ordinary HTML, CSS, and Javascript/jQuery. It's much better than anything Qt has with its widgets or QML. It's much better than anything Apple allows with its other Aqua Cocoa widgets. I can make any kind of widget you can think of, colored and styled anyway I want, using webkit. * I've learned how to enable a bridge between Javascript to Objective C. This lets me make an Objective C function that Javascript can call. So, if I need my webkit app to do something powerful like show a file chooser dialog, I can call an object called "objc" and so something like: var sFilePath = objc.chooseFile(); * Now all I want to do is to bridge Objective C to D. That way, my webkit pages can call Objective C, which can then call D. I can put much of the heavy lifting work in D for my app. If I need to call an Apple Foundation Class library, I can have D call back to Objective C just for that special thing.D.learn is more appropriate but here in the "easy" answer (ignoring extern(Objective-C)). Create a c wrapper. Example: https://github.com/Devisualization/window/blob/master/platforms/macosx/devisualization/window/window.d#L227 https://github.com/Devisualization/window/blob/master/cocoa_library/project/dwc-osx/dwc_cocoa.h https://github.com/Devisualization/window/blob/master/cocoa_library/project/dwc-osx/window.m
Dec 10 2015
Okay, so what has been shared is that the first step is to get C to call D, because if I can do that, then I can get Obj C to call C since there's no direct bridge to D. Obj C has a way to call C. So, I found this article: http://www.prowiki.org/wiki4d/wiki.cgi?DcalledFromC I also found it's not quite up to date with the latest DMD. Here are some things I didn't have to do: * If you scroll to the bottom, it talks about needing a main() in D. That's no longer necessary. So, the file in the example Dmaindummy.d is no longer required. This meant that I could edit Cmain.c and remove the print line there because it was irrelevant. * One needs to use phobos2 instead of phobos. On Ubuntu 14.04, I did apt-get install dmd to get the D compiler, and then did apt-cache search libphobos to see which one was the latest it had, and then in my case I did apt-get install libphobos2-69, but your situation may vary. * This changes the compilation a little, and I lowercased the filenames to make it easier for me: $ dmd -c dfunc.d $ gcc cmain.c dfunc.o -o ctest -lphobos2 -lpthread -lm I then could call ctest with: $ ./ctest Note on OSX, the GCC line is a little different. If you've installed dmd from homebrew, it doesn't write to /usr/lib (that's locked down now) but does write to /usr/local/lib and /usr/local/include. So, you have to tell GCC to call that path with the -L parameter because it doesn't do that by default for some strange reason on OSX: $ gcc cmain.c dfunc.o -o ctest -L/usr/local/lib -lphobos2 -lpthread -lm This then made it find /usr/local/lib/libphobos2.a with that -lphobos2 parameter. So, then it worked on OSX too. And now to figure out how to make a C library instead of an executable, and then how to load that compiled library in Objective C, load a header (.h file) in Objective C for that C function, and call the C function, which then calls the D function. I'll update you if I figure all that out...
Dec 10 2015
On 2015-12-11 08:29, Mike McKee wrote:$ gcc cmain.c dfunc.o -o ctest -L/usr/local/lib -lphobos2 -lpthread -lmI recommend using the D compiler to compile the final application. Then you don't need to worry about all these extra flags and paths. -- /Jacob Carlborg
Dec 10 2015
On 2015-12-11 07:01, Mike McKee wrote:Is there a way to call D code from Objective C on OSX?You can call Objective-C from D [1]. For the other way around, you currently need to use the API for the Objective-C runtime [2].Here's something cool I was thinking about doing: * I've learned how to make Cocoa UI Objective C apps on OSX. * I've learned how to load the native OSX webkit widget in a Cocoa app. It provides a rich user interface using ordinary HTML, CSS, and Javascript/jQuery. It's much better than anything Qt has with its widgets or QML. It's much better than anything Apple allows with its other Aqua Cocoa widgets. I can make any kind of widget you can think of, colored and styled anyway I want, using webkit. * I've learned how to enable a bridge between Javascript to Objective C. This lets me make an Objective C function that Javascript can call. So, if I need my webkit app to do something powerful like show a file chooser dialog, I can call an object called "objc" and so something like: var sFilePath = objc.chooseFile();Are these Objective-C functions or C functions?* Now all I want to do is to bridge Objective C to D. That way, my webkit pages can call Objective C, which can then call D. I can put much of the heavy lifting work in D for my app. If I need to call an Apple Foundation Class library, I can have D call back to Objective C just for that special thing.You can call the Foundation classes directly from D. [1] http://dlang.org/spec/objc_interface.html [2] https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/ -- /Jacob Carlborg
Dec 10 2015
I found a way to call C from in Objective C. The big trick is to rename a .m file to a .mm file. So, I think there's probably a way for me to link a compiled C dylib into Objective C and then load its .h header file so that Objective C can call those C functions. I'll be using GCC to statically combine the D's .o code in with the C code. So, I'm thinking the process is like this: 1. Create a D function d_test() that takes a string input, concatenates on "-response", and returns the result. Compile as dtest.o with "dmd -c dtest.d". 2. Create a C function c_test() that takes a string input, calls d_test() and passes it the string, and then returns the response from d_test() out of c_test() as a string result. Compile as ctest.dylib with "gcc -dynamiclib -o ctest.dylib ctest.c dtest.o -L/usr/local/lib -lphobos2 -lpthread -lm". 3. In Xcode IDE, add this ctest.dylib linked library. Then, create a ctest.h for the function declaration. 4. In Objective C, import ctest.h in my main.mm file and then call with something like NSLog("RESULT=%s",c_test("request")); That should create a debugger line that reads: RESULT=request-response. The problem is that I don't know the entire way that I should create dtest.d and ctest.c.
Dec 11 2015
So I'm having trouble figuring out the D and C code. Created dfunc.d with this: extern (C) string dfunc(string s) { return s ~ "response"; } Then compiled: $ dmd -c dfunc.d This created dfunc.o without error. Next, I created C code like so: extern char * dfunc(char *); char * c_dfunc(char *s) { return dfunc(s); } But when I try to compile on Linux (as a test -- I could have done this slightly differently on OSX), it throws this error: $ gcc -dynamiclib -o cfunc.o cfunc.c dfunc.o -L/usr/local/lib -lphobos2 -lpthread -lm cc1: warning: unrecognized gcc debugging option: y [enabled by default] cc1: warning: unrecognized gcc debugging option: n [enabled by default] cc1: warning: unrecognized gcc debugging option: m [enabled by default] cc1: warning: unrecognized gcc debugging option: i [enabled by default] cc1: warning: unrecognized gcc debugging option: c [enabled by default] cc1: warning: unrecognized gcc debugging option: l [enabled by default] cc1: warning: unrecognized gcc debugging option: i [enabled by default] cc1: warning: unrecognized gcc debugging option: b [enabled by default] /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 0 has invalid symbol index 11 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 1 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 2 has invalid symbol index 2 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 3 has invalid symbol index 2 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 4 has invalid symbol index 11 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 5 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 6 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 7 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 8 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 9 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 10 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 11 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 12 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 13 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 14 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 15 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 16 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 17 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 18 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 19 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 20 has invalid symbol index 13 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 21 has invalid symbol index 22 /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_line): relocation 0 has invalid symbol index 2 /usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/crt1.o: In function `_start': (.text+0x18): undefined reference to `main' collect2: error: ld returned 1 exit status
Dec 11 2015
Well, part of it was that I needed to do -shared on Linux instead of -dynamiclib. On OSX, I have to use -dynamiclib. It compiles now on the C code, but when I created a cmain.c to test the library, it gave me a segmentation fault when trying to run this compiled program, even though I copied gfunc.o and cfunc.o to /usr/lib on Linux. // cmain.c #include <stdio.h> extern char * c_dfunc(char *s); void main() { printf("%s\n",c_dfunc("request")); }
Dec 11 2015
On 2015-12-11 10:18, Mike McKee wrote:Well, part of it was that I needed to do -shared on Linux instead of -dynamiclib. On OSX, I have to use -dynamiclib. It compiles now on the C code, but when I created a cmain.c to test the library, it gave me a segmentation fault when trying to run this compiled program, even though I copied gfunc.o and cfunc.o to /usr/lib on Linux. // cmain.c #include <stdio.h> extern char * c_dfunc(char *s); void main() { printf("%s\n",c_dfunc("request")); }There are several issues: 1. The D function needs to use C compatible types, see my answer to your previous post 2. You need to initialize the D runtime from the C side 3. If you allocate data in D using the GC and pass it to the C side, you need to make sure there's a reference to it on the D side. Otherwise the GC could collect the memory 4. Dynamic libraries are not yet supported on OS X I recommend asking these question in the learning forum. As a first step you need to learn how to interact between D and C. You can get a lot of answers for that on the learning forum, tutorials, documentation, books and so on. -- /Jacob Carlborg
Dec 11 2015
On 2015-12-11 09:51, Mike McKee wrote:So I'm having trouble figuring out the D and C code. Created dfunc.d with this: extern (C) string dfunc(string s) { return s ~ "response"; } Then compiled: $ dmd -c dfunc.d This created dfunc.o without error. Next, I created C code like so: extern char * dfunc(char *); char * c_dfunc(char *s) { return dfunc(s); }"string" in D is not the same as "char*" in C. "string" is an alias to an array of immutable characters. An array in D consists of the length of the array and a pointer to the data. The interface of the function needs to only contain C types. Something like this: extern (C) char* dfunc(char* s); If you want to use the D string operations, like ~, you need to convert it to a D string, do the concatenation, and then convert it back to a C string [2] [3]. See [3] for more information. [3] http://dlang.org/spec/interfaceToC.html -- /Jacob Carlborg
Dec 11 2015
On 2015-12-11 09:20, Mike McKee wrote:I found a way to call C from in Objective C. The big trick is to rename a .m file to a .mm file..mm means Objective-C++. That is, combining C++ and Objective-C in the same file. Objective-C can call C functions directly with no problems. A global function in a .m file is a C function. NSLog, for example is a regular C function.So, I think there's probably a way for me to link a compiled C dylib into Objective C and then load its .h header file so that Objective C can call those C functions. I'll be using GCC to statically combine the D's .o code in with the C code. So, I'm thinking the process is like this: 1. Create a D function d_test() that takes a string input, concatenates on "-response", and returns the result. Compile as dtest.o with "dmd -c dtest.d". 2. Create a C function c_test() that takes a string input, calls d_test() and passes it the string, and then returns the response from d_test() out of c_test() as a string result. Compile as ctest.dylib with "gcc -dynamiclib -o ctest.dylib ctest.c dtest.o -L/usr/local/lib -lphobos2 -lpthread -lm".This step is not necessary. You can call the D function directly without needing a wrapper.3. In Xcode IDE, add this ctest.dylib linked library. Then, create a ctest.h for the function declaration. 4. In Objective C, import ctest.h in my main.mm file and then call with something like NSLog("RESULT=%s",c_test("request")); That should create a debugger line that reads: RESULT=request-response. The problem is that I don't know the entire way that I should create dtest.d and ctest.c.-- /Jacob Carlborg
Dec 11 2015