Forum > Other OS

Sample Simple HOST/DYLIB for OSX [SOLVED]

(1/1)

kevin.black:
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  window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Hint: (11030) Start of reading config file /etc/fpc.cfgHint: (11031) End of reading config file /etc/fpc.cfgFree Pascal Compiler version 3.0.4 [2017/11/26] for x86_64Copyright (c) 1993-2017 by Florian Klaempfl and others(1002) Target OS: Darwin for x86_64(3104) Compiling pDYLIBTestAPP.lpr(3104) Compiling udylibtestapp.pas/Users/kevin/Dropbox/Lazarus/DYLIBTest/udylibtestapp.pas(28,28) Hint: (5024) Parameter "Sender" not used/Users/kevin/Dropbox/Lazarus/DYLIBTest/udylibtestapp.pas(27,28) Hint: (5024) Parameter "Sender" not used/Users/kevin/Dropbox/Lazarus/DYLIBTest/udylibtestapp.pas(26,28) Hint: (5024) Parameter "Sender" not used(9001) Assembling (pipe) /Users/kevin/Dropbox/Lazarus/DYLIBTest/lib/x86_64-darwin/udylibtestapp.s(9001) Assembling (pipe) /Users/kevin/Dropbox/Lazarus/DYLIBTest/lib/x86_64-darwin/pDYLIBTestAPP.s(9022) Compiling resource /Users/kevin/Dropbox/Lazarus/DYLIBTest/lib/x86_64-darwin/pDYLIBTestAPP.or(9015) Linking /Users/kevin/Dropbox/Lazarus/DYLIBTest/darwin/pDYLIBTestAPPUndefined symbols for architecture x86_64:  "__say_Hello", referenced from:                                         [MY COMMENT] NOTE THE Double '_' as in '__'      _UDYLIBTESTAPP$_$TFDYLIBTESTAPP_$__$$_BITBTN1CLICK$TOBJECT in udylibtestapp.old: symbol(s) not found for architecture x86_64An error occurred while linking pDYLIBTestAPP.lpr(25) Error: (9013) Error while linkingpDYLIBTestAPP.lpr(25) Fatal: (10026) There were 1 errors compiling module, stoppingFatal: (1018) Compilation aborted 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  window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---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  window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit uDYLIBTestAPP; {$mode objfpc}{$H+} interface uses  Classes,  SysUtils,  Forms,  Controls,  Graphics,  Dialogs,  Buttons,  StdCtrls; type   { TfDylibTestApp }   TfDylibTestApp = class(TForm)    BitBtn1: TBitBtn;    BitBtn2: TBitBtn;    BitBtn3: TBitBtn;    Memo1: TMemo;    procedure BitBtn1Click(Sender: TObject);    procedure BitBtn2Click(Sender: TObject);    procedure BitBtn3Click(Sender: TObject);  private   public   end; const  // Windows DLL Names  {$IFDEF MSWINDOWS}  TestDLL = 'pdylibtest.dll';  {$ENDIF MSWINDOWS}   // macOS DYLIB Names  {$IFDEF DARWIN}  TestDLL = 'pdylibtest';  {$ENDIF DARWIN}   {$IFDEF MSWINDOWS}    function say_Hello(Hello: string): boolean; stdcall; external TestDLL Delayed;  {$ENDIF MSWINDOWS}   {$IFDEF DARWIN}   function say_Hello(Hello: string): boolean; cdecl; external TestDLL;  {$ENDIF DARWIN}   function localFunction(localIn: string; out localOut: string): boolean; var  fDylibTestApp: TfDylibTestApp; implementation function localFunction(localIn: string; out localOut: string): boolean;begin  LocalOut := 'This was passed to the function: ' + LocalIn;  Result := True;end; {$R *.lfm} { TfDylibTestApp } procedure TfDylibTestApp.BitBtn3Click(Sender: TObject);begin  // Quit the test application  close;end; procedure TfDylibTestApp.BitBtn2Click(Sender: TObject);var  sOut: string; begin  // This is a local function  ShowMessage('Local Function Call');  if localFunction('Local in', sOut) then    showmessage('Local Function: TRUE (' + sOut + ')')  else    showmessage('Local Function: FALSE');end; procedure TfDylibTestApp.BitBtn1Click(Sender: TObject); var   b:boolean;   sType: string;   sDLLString: string; begin     b := False;     // Call the DLL Function    {$IFDEF MSWINDOWS}    sType := 'Windows DLL';    sDLLString := 'The string passed to the Windows DLL';    b := say_Hello(sDLLString);    {$ENDIF MSWINDOWS}    {$IFDEF DARWIN}    sType := 'macOS DYLIB';    sDLLString := 'The string passed to the macOS DYLIB';    b := say_Hello(sDLLString);    {$ENDIF DARWIN}     if b then      showmessage('Returned From: ' + sType + ': TRUE')    else      showmessage('Returned From: ' + sType + ': FALSE'); end; end. 
DYLIB CODE (the dylib builds OK without error):

--- Code: Pascal  window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---library pDYLIBTest; {$mode objfpc}{$H+} {$R *.res} uses  Classes,  SysUtils,  Forms,  Controls,  Graphics,  StdCtrls,  Dialogs,  Buttons,  Interfaces; var  sType: string; //function say_Hello(Hello: string): boolean; cdecl;{$IFDEF DARWIN} alias : '_say_Hello'; {$ENDIF DARWIN}function say_Hello(Hello: string): boolean; cdecl;begin   ShowMessage('[DYLIB] This is the new direct call: DYLIB / DLL using FMX.Forms and FMX.Dialogs');   {$IFDEF WINDOWS}  sType := 'Windows DLL';  {$ENDIF WINDOWS}  {$IFDEF DARWIN}  sType := 'macOS DYLIB';  {$ENDIF DARWIN}  Result := True;end;  end. exports  //say_Hello;{$IFDEF DARWIN} name '_say_Hello'; {$ENDIF DARWIN}  say_Hello; initialization  ShowMessage('[DYLIB] initialization'); finalization  ShowMessage('[DYLIB] finalization');  end.``
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

Jonas Maebe:
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:
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  window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{$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  window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---ld: library not found for -ltw9089aAn 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  window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Hint: (11030) Start of reading config file /etc/fpc.cfgHint: (11031) End of reading config file /etc/fpc.cfgFree Pascal Compiler version 3.0.4 [2017/11/26] for x86_64Copyright (c) 1993-2017 by Florian Klaempfl and others(1002) Target OS: Darwin for x86_64(3104) Compiling tw9089b.pas/Users/kevin/Dropbox/Lazarus/DYLIB Compiler Test/tw9089b.pas(13,3) Hint: (5028) Local const "libname" is not used(9001) Assembling (pipe) /Users/kevin/Dropbox/Lazarus/DYLIB Compiler Test/lib/x86_64-darwin/tw9089b.s(9015) Linking /Users/kevin/Dropbox/Lazarus/DYLIB Compiler Test/tw9089bld: library not found for -ltw9089aAn error occurred while linking tw9089b.pas(47) Error: (9013) Error while linkingtw9089b.pas(47) Fatal: (10026) There were 1 errors compiling module, stoppingFatal: (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

kevin.black:
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....

Navigation

[0] Message Index

Go to full version