Recent

Author Topic: Sample Simple HOST/DYLIB for OSX [SOLVED]  (Read 4070 times)

kevin.black

  • Full Member
  • ***
  • Posts: 122
Sample Simple HOST/DYLIB for OSX [SOLVED]
« on: January 15, 2019, 11:45:05 pm »
Hi,

Apart from just starting with Lazarus after a many year hiatus, I am necessarily in the OSX world. This is because of issues with Delphi which, even at 10.2.3, there are problems and no 64bit version for the foreseeable future (which is bad if you are doing OSX).

Now (I think) I had my code working the 32 bit version (carbon). It's a simple statically loaded DYLIB (so it gets loaded first) with one call (_say_Hello). I have converted to 64bit. This in and of itself has been plagued with issues. My settings now are (so we are all on the same page):

Tools>Settings>Environment>Files
Compiler Executable:  /usr/local/bin/ppcx64

Project Options>Compiler Options>Config and Target
Target OS:             (Default)
Target CPU Family: x86_x64
Target Processor:   (Default)

For clarity I've included the code below, but when I look at the DYLIB with nm -gU there is definitely an entry for _say_Hello(). Please take the time to have a look, this is a blocker.

Regardless, I cannot seem to get past this error (no matter what combination of '_' I use or whether or not I put in the full path of the DYLIB. There error messages are:
Code: Pascal  [Select]
  1. Hint: (11030) Start of reading config file /etc/fpc.cfg
  2. Hint: (11031) End of reading config file /etc/fpc.cfg
  3. Free Pascal Compiler version 3.0.4 [2017/11/26] for x86_64
  4. Copyright (c) 1993-2017 by Florian Klaempfl and others
  5. (1002) Target OS: Darwin for x86_64
  6. (3104) Compiling pDYLIBTestAPP.lpr
  7. (3104) Compiling udylibtestapp.pas
  8. /Users/kevin/Dropbox/Lazarus/DYLIBTest/udylibtestapp.pas(28,28) Hint: (5024) Parameter "Sender" not used
  9. /Users/kevin/Dropbox/Lazarus/DYLIBTest/udylibtestapp.pas(27,28) Hint: (5024) Parameter "Sender" not used
  10. /Users/kevin/Dropbox/Lazarus/DYLIBTest/udylibtestapp.pas(26,28) Hint: (5024) Parameter "Sender" not used
  11. (9001) Assembling (pipe) /Users/kevin/Dropbox/Lazarus/DYLIBTest/lib/x86_64-darwin/udylibtestapp.s
  12. (9001) Assembling (pipe) /Users/kevin/Dropbox/Lazarus/DYLIBTest/lib/x86_64-darwin/pDYLIBTestAPP.s
  13. (9022) Compiling resource /Users/kevin/Dropbox/Lazarus/DYLIBTest/lib/x86_64-darwin/pDYLIBTestAPP.or
  14. (9015) Linking /Users/kevin/Dropbox/Lazarus/DYLIBTest/darwin/pDYLIBTestAPP
  15. Undefined symbols for architecture x86_64:
  16.   "__say_Hello", referenced from:                                         [MY COMMENT] NOTE THE Double '_' as in '__'
  17.       _UDYLIBTESTAPP$_$TFDYLIBTESTAPP_$__$$_BITBTN1CLICK$TOBJECT in udylibtestapp.o
  18. ld: symbol(s) not found for architecture x86_64
  19. An error occurred while linking
  20. pDYLIBTestAPP.lpr(25) Error: (9013) Error while linking
  21. pDYLIBTestAPP.lpr(25) Fatal: (10026) There were 1 errors compiling module, stopping
  22. Fatal: (1018) Compilation aborted
  23.  
If I take the '_' out of the function name in the coed this shows the same error, but with a single '_'. I have used the application bundle  option and that is an issue because it don't build the Host. If I take out the call to the DYLIB, it works fine.

Host Code:

UPDATE:According to what I have found, I don't need to use the full name of the DYLIB because the system will fix that. So I only need
Code: Pascal  [Select]
  1. external 'pdylibtest'
and the system will prefix wth lib and postfix with .dylib. And modified to remove '_' for 64 bit version as seen in lazarus documentation. Did that, same issue?
Code: Pascal  [Select]
  1. unit uDYLIBTestAPP;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes,
  9.   SysUtils,
  10.   Forms,
  11.   Controls,
  12.   Graphics,
  13.   Dialogs,
  14.   Buttons,
  15.   StdCtrls;
  16.  
  17. type
  18.  
  19.   { TfDylibTestApp }
  20.  
  21.   TfDylibTestApp = class(TForm)
  22.     BitBtn1: TBitBtn;
  23.     BitBtn2: TBitBtn;
  24.     BitBtn3: TBitBtn;
  25.     Memo1: TMemo;
  26.     procedure BitBtn1Click(Sender: TObject);
  27.     procedure BitBtn2Click(Sender: TObject);
  28.     procedure BitBtn3Click(Sender: TObject);
  29.   private
  30.  
  31.   public
  32.  
  33.   end;
  34.  
  35. const
  36.   // Windows DLL Names
  37.   {$IFDEF MSWINDOWS}
  38.   TestDLL = 'pdylibtest.dll';
  39.   {$ENDIF MSWINDOWS}
  40.  
  41.   // macOS DYLIB Names
  42.   {$IFDEF DARWIN}
  43.   TestDLL = 'pdylibtest';
  44.   {$ENDIF DARWIN}
  45.  
  46.   {$IFDEF MSWINDOWS}
  47.     function say_Hello(Hello: string): boolean; stdcall; external TestDLL Delayed;
  48.   {$ENDIF MSWINDOWS}
  49.  
  50.   {$IFDEF DARWIN}
  51.    function say_Hello(Hello: string): boolean; cdecl; external TestDLL;
  52.   {$ENDIF DARWIN}
  53.  
  54.   function localFunction(localIn: string; out localOut: string): boolean;
  55.  
  56. var
  57.   fDylibTestApp: TfDylibTestApp;
  58.  
  59. implementation
  60.  
  61. function localFunction(localIn: string; out localOut: string): boolean;
  62. begin
  63.   LocalOut := 'This was passed to the function: ' + LocalIn;
  64.   Result := True;
  65. end;
  66.  
  67. {$R *.lfm}
  68.  
  69. { TfDylibTestApp }
  70.  
  71. procedure TfDylibTestApp.BitBtn3Click(Sender: TObject);
  72. begin
  73.   // Quit the test application
  74.   close;
  75. end;
  76.  
  77. procedure TfDylibTestApp.BitBtn2Click(Sender: TObject);
  78. var
  79.   sOut: string;
  80.  
  81. begin
  82.   // This is a local function
  83.   ShowMessage('Local Function Call');
  84.   if localFunction('Local in', sOut) then
  85.     showmessage('Local Function: TRUE (' + sOut + ')')
  86.   else
  87.     showmessage('Local Function: FALSE');
  88. end;
  89.  
  90. procedure TfDylibTestApp.BitBtn1Click(Sender: TObject);
  91.  
  92. var
  93.    b:boolean;
  94.    sType: string;
  95.    sDLLString: string;
  96.  
  97. begin
  98.  
  99.     b := False;
  100.  
  101.     // Call the DLL Function
  102.     {$IFDEF MSWINDOWS}
  103.     sType := 'Windows DLL';
  104.     sDLLString := 'The string passed to the Windows DLL';
  105.     b := say_Hello(sDLLString);
  106.     {$ENDIF MSWINDOWS}
  107.     {$IFDEF DARWIN}
  108.     sType := 'macOS DYLIB';
  109.     sDLLString := 'The string passed to the macOS DYLIB';
  110.     b := say_Hello(sDLLString);
  111.     {$ENDIF DARWIN}
  112.  
  113.     if b then
  114.       showmessage('Returned From: ' + sType + ': TRUE')
  115.     else
  116.       showmessage('Returned From: ' + sType + ': FALSE');
  117.  
  118. end;
  119.  
  120. end.
  121.  

DYLIB CODE (the dylib builds OK without error):
Code: Pascal  [Select]
  1. library pDYLIBTest;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. {$R *.res}
  6.  
  7. uses
  8.   Classes,
  9.   SysUtils,
  10.   Forms,
  11.   Controls,
  12.   Graphics,
  13.   StdCtrls,
  14.   Dialogs,
  15.   Buttons,
  16.   Interfaces;
  17.  
  18. var
  19.   sType: string;
  20.  
  21. //function say_Hello(Hello: string): boolean; cdecl;{$IFDEF DARWIN} alias : '_say_Hello'; {$ENDIF DARWIN}
  22. function say_Hello(Hello: string): boolean; cdecl;
  23. begin
  24.  
  25.   ShowMessage('[DYLIB] This is the new direct call: DYLIB / DLL using FMX.Forms and FMX.Dialogs');
  26.  
  27.   {$IFDEF WINDOWS}
  28.   sType := 'Windows DLL';
  29.   {$ENDIF WINDOWS}
  30.   {$IFDEF DARWIN}
  31.   sType := 'macOS DYLIB';
  32.   {$ENDIF DARWIN}
  33.   Result := True;
  34. end;
  35.  
  36.  
  37. end.
  38.  
  39. exports
  40.   //say_Hello;{$IFDEF DARWIN} name '_say_Hello'; {$ENDIF DARWIN}
  41.   say_Hello;
  42.  
  43. initialization
  44.   ShowMessage('[DYLIB] initialization');
  45.  
  46. finalization
  47.   ShowMessage('[DYLIB] finalization');
  48.  
  49.  
  50. end.
  51. ``

So apart from the obvious question, why can the Host application NOT see the function in the DYLIB?

Does anyone have simple test code that is working that has a 64bit Host and a 64bit DYLIB that they might share with me (or point me to an example) so that I can see where I am going wrong?

Many thanks
« Last Edit: March 01, 2019, 06:35:49 am by kevin.black »

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 659
Re: Sample Simple HOST/DYLIB for OSX
« Reply #1 on: January 16, 2019, 07:07:11 pm »
Here is the test we use to check this functionality in the compiler:
* https://svn.freepascal.org/svn/fpc/trunk/tests/webtbs/tw9089a.pp (library 1, exports variable)
* https://svn.freepascal.org/svn/fpc/trunk/tests/webtbs/tw9089b.pp (library 2, uses library 1 and exports function that returns the value of the exported variable)
* https://svn.freepascal.org/svn/fpc/trunk/tests/webtbs/tw9089c.pp (links against library 2 and calls the function)

kevin.black

  • Full Member
  • ***
  • Posts: 122
Re: Sample Simple HOST/DYLIB for OSX
« Reply #2 on: January 16, 2019, 10:50:21 pm »
Hi Jonas,

One thing that immediately leaps out at me is that, if NOT MSWINDOWS, then there is a link lib directive. Is this necessary, I'm assuming it is?

Code: Pascal  [Select]
  1. {$linklib tw9089b}

UPDATE:

I initially had the output path (for the dylib) set to ./x86_64-darwin and, whilst there is a built file called tw9089a (no issues) when I try and build tw9089b I get the standard
Code: Pascal  [Select]
  1. ld: library not found for -ltw9089a
  2. An error occurred while linking
The file is definitely there.

So I changed the output folder to the source folder where it is by default, again I can confirm that the file tw9089a is definitely there, but I get these messages:
Code: Pascal  [Select]
  1. Hint: (11030) Start of reading config file /etc/fpc.cfg
  2. Hint: (11031) End of reading config file /etc/fpc.cfg
  3. Free Pascal Compiler version 3.0.4 [2017/11/26] for x86_64
  4. Copyright (c) 1993-2017 by Florian Klaempfl and others
  5. (1002) Target OS: Darwin for x86_64
  6. (3104) Compiling tw9089b.pas
  7. /Users/kevin/Dropbox/Lazarus/DYLIB Compiler Test/tw9089b.pas(13,3) Hint: (5028) Local const "libname" is not used
  8. (9001) Assembling (pipe) /Users/kevin/Dropbox/Lazarus/DYLIB Compiler Test/lib/x86_64-darwin/tw9089b.s
  9. (9015) Linking /Users/kevin/Dropbox/Lazarus/DYLIB Compiler Test/tw9089b
  10. ld: library not found for -ltw9089a
  11. An error occurred while linking
  12. tw9089b.pas(47) Error: (9013) Error while linking
  13. tw9089b.pas(47) Fatal: (10026) There were 1 errors compiling module, stopping
  14. Fatal: (1018) Compilation aborted
  • I'm using lazarus 2.0.0RC3
  • The files have a pas extension (don't think that's relevant)
  • Target OS is Darwin
  • I'm building for x86_64
  • The compiler is /usr/local/bin/ppcx64

I apologise for the newbie questions (so don't assume I'm doing things by default), but this is a sticking point, I really cannot move on until this simple code executes and by that I mean LINKS?

Do you have any suggestions of what I should try next/what I'm doing wrong?

Thanks,
kevin
« Last Edit: January 17, 2019, 12:59:32 am by kevin.black »

kevin.black

  • Full Member
  • ***
  • Posts: 122
Re: Sample Simple HOST/DYLIB for OSX [SOLVED]
« Reply #3 on: January 17, 2019, 03:54:11 am »
As is often the case with these sorts of issues, it's usually a blinding flash of the obvious(BFO). In this case I had the incorrect path set for Libraries (-Fl):

What it was set to:                     $(TargetOS)

What it should have been set to: $(TargetCPU)-$(TargetOS)

So at least now I can build the application. It's not actually doing what it should, but that's probably me again.

One issue I have, when I run the application (in DEBUG mode), pressing the RED STOP button in the IDE does absolutely nothing. Likewise if I press the stop button in the RUN menu item. Is this normal behaviour?

If I press RESET DEBUGGER it then kills the current session?

If I run the application outside the debugger, the QUIT button and the red Kill button (top right) does nothing. The application does not appear in the force quit window, terminating lazarus does not kill it and I cannot see the process in the process window. All very messy....