[SOLVED] Can't access .so library function from Ubuntu lazarus / 32-Linux ---------------------------------------------------------------------- Mujie · 2017-07-30 11:35 Hi, In MS Windows I was successfully call the function from my own dll library. Then I tried to crosscompile the sources  to Linux (Elementary OS which is Ubuntu based). But no luck when result has become standalone application on Ubuntu/Elementary OS. Here is my OS QuoteLinux G230 4.10.0-27-generic #30~16.04.2-Ubuntu SMP Thu Jun 29 16:07:46 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux My Lazarus IDE QuoteLazarus 1.6.4 rUnversioned directory FPC 3.0.2 x86_64-linux-gtk 2 My application sources Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i //appcool.lprprogram appcool; {$mode objfpc}{$H+}//for threads{$define UseCThreads} uses  {$IFDEF UNIX}{$IFDEF UseCThreads}  cthreads,  {$ENDIF}{$ENDIF}  Interfaces, // this includes the LCL widgetset  Forms, login_f, login_u  { you can add units after this }; {$R *.res} begin  Application.Title:='Cool Application';  RequireDerivedFormResource:=True;  Application.Initialize;  Application.CreateForm(TformLogin, formLogin);  Application.Run;end.  Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i //login_u.pas for unitunit login_u; {$mode objfpc}{$H+} interface uses  Classes, SysUtils,  //additional  LCLIntf, Dynlibs, Dialogs, Buttons; type //API Testing  ThreadAPITesting = class(TThread)  protected    procedure LoadingLib;    procedure Execute; override;  end; procedure ShowApiTesting; implementation //uses type //API TESTING//=========== API TESTING =============  TApiTesting = function (client_key, client_secret: string): string; cdecl; //API TESTING procedure ThreadApiTesting.LoadingLib;var  MyHandle: TLibHandle;  ApiTestingFunc: TApiTesting;  DataResult: string;  client_key, client_secret: string;begin  MyHandle := LoadLibrary('libs/libdbq.so');  if MyHandle<>0 then    begin      ApiTestingFunc := TApiTesting(GetProcedureAddress(MyHandle,'ApiTesting'));      if Assigned(@ApiTestingFunc) then        begin          DataResult := ApiTestingFunc('what', 'ever');        end;    FreeLibrary(MyHandle);    end  else    begin      FreeLibrary(MyHandle);      ShowMessage('Library failed.');    end;  Exit;end; procedure ThreadApiTesting.Execute;begin  if not Terminated then    begin      Synchronize(@LoadingLib);      Exit;    end;end; procedure ShowApiTesting;var ExecApiTesting: ThreadApiTesting;begin ExecApiTesting := ThreadApiTesting.Create(False); ExecApiTesting.FreeOnTerminate := True; Exit;end; end. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i //login_f for formunit login_f; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, FileUtil, BCButton, Forms, Controls, Graphics,  Dialogs, ExtCtrls, StdCtrls; type   { TformLogin }   TformLogin = class(TForm)    btLogin: TBCButton;    procedure btLoginClick(Sender: TObject);    procedure FormCreate(Sender: TObject);  private    { private declarations }  public    { public declarations }  end; var  formLogin: TformLogin; implementation {$R *.lfm} uses  //Unit  login_u; { TformLogin } procedure TformLogin.btLoginClick(Sender: TObject);begin  ShowApiTesting();end; //anti flickerprocedure TformLogin.FormCreate(Sender: TObject);begin  Self.DoubleBuffered:=True;end; end.  And the .so (dll) library Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit login; {$mode objfpc}{$H+} interface uses  Classes, SysUtils,  //additional  LCLIntf, cmem; implementation function ApiTesting(client_key, client_secret: string): string; cdecl;begin  MessageBox(0,PChar('Success!'),PChar('Info'));end; exports ApiTesting;  Is there something I missed? Thank you before. ---------------------------------------------------------------------- Thaddy · 2017-07-30 11:39 A dll is a library, not a program. Where's your main LIBRARY code?....... If it compiles to a dll it will compile to an .so on nixes. But your code is no good anyway, so why bother? ---------------------------------------------------------------------- Mujie · 2017-07-30 11:46 Quote from: Thaddy on July 30, 2017, 01:39:33 pmA dll is a library, not a program. Where's your main LIBRARY code?....... If it compiles to a dll it will compile to an .so on nixes. But your code is no good anyway, so why bother? Hi, Thanks for your reply. There is my main library codes, not good enough  Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit login; {$mode objfpc}{$H+} interface uses  Classes, SysUtils,  //additional  LCLIntf, cmem; implementation function ApiTesting(client_key, client_secret: string): string; cdecl;begin  MessageBox(0,PChar('Success!'),PChar('Info'));end; exports ApiTesting; ---------------------------------------------------------------------- molly · 2017-07-30 14:19 Quote from: Mujie on July 30, 2017, 01:46:11 pmThanks for your reply. There is my main library codes, not good enough  You are not creating a (shared) library there but, you are exporting functions. There is an important difference there. Programming shared libraries ---------------------------------------------------------------------- Mujie · 2017-07-30 16:27 Quote from: molly on July 30, 2017, 04:19:02 pmYou are not creating a (shared) library there but, you are exporting functions. There is an important difference there. Programming shared libraries Hi, Thanks for your reply. I got this messages from GetLoadErrorStr Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i libs/libdbq.so: undefined symbol: ApiTesting ---------------------------------------------------------------------- molly · 2017-07-30 16:56 Quote from: Mujie on July 30, 2017, 06:27:55 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i libs/libdbq.so: undefined symbol: ApiTestingYou have not showed us a library unit named (lib)dbq so how would you expect it to load/link a function named ApiTesting ? ---------------------------------------------------------------------- Thaddy · 2017-07-30 18:21 A library looks like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i library somelibrary;interface  // not requiredexports... implementation // not requiredend.It is not a program..... As you wrote, it's your own library.... (some people lack their glasses) ---------------------------------------------------------------------- Leledumbo · 2017-07-31 04:44 You should try a simple program-library first. If you can make this work on Linux, then you should have no problem doing it for more complex program: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i library mylib; uses  strings; // NEVER declare string as parameter in library function, string is a managed type and each program and library has their own copy of the memory managerfunction f(p: pchar): integer; cdecl;begin  f := strlen(p);end; exports  f; end. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program mylibtest; uses  dynlibs; type Tf = function (p: pchar): integer; var  OK: Boolean;  h: TLibHandle;  f: Tf;begin  OK := false;  h :=  LoadLibrary('./libmylib.' + SharedSuffix);  if h <> NilHandle then begin    f := Tf(GetProcedureAddress(h,'f'));    if Assigned(f) then begin      WriteLn(f('test'));      OK := true;    end;  end;   if not OK then    WriteLn(StdErr,GetLoadErrorStr);end. ---------------------------------------------------------------------- Thaddy · 2017-07-31 07:02 "// NEVER declare string as parameter in library function, string is a managed type and each program and library has their own copy of the memory manager" Well. As long it is pure pascal for pure pascal, one could use {$H-}. Shortstrings are not a managed string type!! ---------------------------------------------------------------------- Mujie · 2017-07-31 14:35 Hi LeleDumbo, Thanks for your reply. Its look like I struggle with 'LCLIntf' on my .so library source codes. I try to replace 'Windows' uses with 'LCLIntf'. My codes is fine on MS Windows, maybe I should take a look another distro. Quote from: Leledumbo on July 31, 2017, 06:44:37 amYou should try a simple program-library first. If you can make this work on Linux, then you should have no problem doing it for more complex program: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i library mylib; uses  strings; // NEVER declare string as parameter in library function, string is a managed type and each program and library has their own copy of the memory managerfunction f(p: pchar): integer; cdecl;begin  f := strlen(p);end; exports  f; end. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program mylibtest; uses  dynlibs; type Tf = function (p: pchar): integer; var  OK: Boolean;  h: TLibHandle;  f: Tf;begin  OK := false;  h :=  LoadLibrary('./libmylib.' + SharedSuffix);  if h <> NilHandle then begin    f := Tf(GetProcedureAddress(h,'f'));    if Assigned(f) then begin      WriteLn(f('test'));      OK := true;    end;  end;   if not OK then    WriteLn(StdErr,GetLoadErrorStr);end. ---------------------------------------------------------------------- Mujie · 2017-07-31 14:38 Hi, 'library' syntax has been declare on .lpr You're right about the glasses  Quote from: Thaddy on July 30, 2017, 08:21:31 pmA library looks like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i library somelibrary;interface  // not requiredexports... implementation // not requiredend.It is not a program..... As you wrote, it's your own library.... (some people lack their glasses) ---------------------------------------------------------------------- Mujie · 2017-08-06 05:40 Hi, It's me again, I solved this by adding the code into one instead of the unit outside the library code. Example Work library codes Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i //myapilibrary.lpr library myapilibrary; {$mode objfpc}{$H+} uses  Classes  { you can add units after this }; function ApiTesting(p: PChar): integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};begin  ApiTesting:= strlen(p);end; exports ApiTesting; beginend.   Not work on Ubuntu 16 and Centos 7, error message appears 'undefined symbol ApiTesting'. But work on MS Windows 7 and MS Windows 10. I put a function on unit and linked with lpr. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i //myapilibrary.lpr library myapilibrary; {$mode objfpc}{$H+} uses  Classes, myanotherunit  { you can add units after this }; beginend.   Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i //myanotherunit.pas unit myanotherunit; {$mode objfpc}{$H+} interface uses  Classes, SysUtils; implementation function ApiTesting(p: PChar): integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};begin  ApiTesting:= strlen(p);end; exports ApiTesting; end.