开发环境:
开发工具:lazarus 4.4+fpc 3.3.1(aa182cb14737fce742689f269210acfbc51e2b8d分支)
交叉编译lib文件:从openwrt的/lib/目录提取的so作为交叉编译lib使用(14个so)。
嵌入设备:树莓派3B,系统:openwrt,arm32
嵌入设备系统:openwrt 32位
出现的问题及原因:
用例是网友(wwjj)提供的(见后面有测试代码)。
用lnet交叉编译类似openwrt这类精简linux系统(只有几个必须要的libc.so,连libpthreads.so都没有)的应用时,提示出现找不到pthread的错误信息,但网友他用Typhon 7.7.1可以编译及运行正常,经排查,发现我用的fpc中的syncobjs单元引用了pthreads单元,他使用的syncobjs.pp(2022-02-14的版本3.3.1)没引用。
解决方法:
将Typhon 7.7.1 fpc的syncobjs.pp拷贝到项目目录,最后编译就可以,实测编译出来的应用在目标系统也能执行正常。
注意:
1、不要添加lnetbase等依赖包,只能在Project-->Options-->Compiler Options-->Paths-->Other unit files添加lnet路径,否则编译还是会出错。
2、可用的syncobjs.pp源码放在最后面了
开发工具:lazarus 4.4+fpc 3.3.1(aa182cb14737fce742689f269210acfbc51e2b8d分支)
交叉编译lib文件:从openwrt的/lib/目录提取的so作为交叉编译lib使用(14个so)。
嵌入设备:树莓派3B,系统:openwrt,arm32
嵌入设备系统:openwrt 32位
出现的问题及原因:
用例是网友(wwjj)提供的(见后面有测试代码)。
用lnet交叉编译类似openwrt这类精简linux系统(只有几个必须要的libc.so,连libpthreads.so都没有)的应用时,提示出现找不到pthread的错误信息,但网友他用Typhon 7.7.1可以编译及运行正常,经排查,发现我用的fpc中的syncobjs单元引用了pthreads单元,他使用的syncobjs.pp(2022-02-14的版本3.3.1)没引用。
解决方法:
将Typhon 7.7.1 fpc的syncobjs.pp拷贝到项目目录,最后编译就可以,实测编译出来的应用在目标系统也能执行正常。
注意:
1、不要添加lnetbase等依赖包,只能在Project-->Options-->Compiler Options-->Paths-->Other unit files添加lnet路径,否则编译还是会出错。
2、可用的syncobjs.pp源码放在最后面了

D:\QFLazarus4.4\cross\bin-x86_64-win64\arm-linux\arm-linux-gnueabihf-ld.exe: cannot find -lpthread Error: Error while linking



测试用例:
program test; {$mode objfpc}{$H+} uses Sysutils, Classes, Sockets, BaseUnix, lNet; function GetLocalIP: string; {$IFDEF UNIX} const CGDNSADDR = '127.0.0.1'; CGDNSPORT = 53; {$ENDIF} {$IFDEF UNIX} var S: string; VHostAddr: TSockAddr; VLength: Integer; VInetSockAddr: TInetSockAddr; VSock, VError: LongInt; VIPBuf: array[0..255] of Char = #0; {$ENDIF} {$IFDEF MSWINDOWS} type P_hostent = ^hostent; //这里不管64位还是32位都必须是PAnsiChar; PHostEnt改了结构,Win64位会不正常,因此重新定义 hostent = record h_name: PAnsiChar; // official name of host h_aliases: PPAnsiChar; // alias list h_addrtype: Smallint; // host address type h_length: Smallint; // length of address case Integer of 0: (h_addr_list: PPAnsiChar); // list of addresses 1: (h_addr: PPAnsiChar); // address, for backward compat end; var VWSAData: TWSAData; VHostEnt: P_hostent; //PHostEnt; VName: string; {$ENDIF} begin {$IFDEF UNIX} VError := 0; FillChar(VIPBuf, SizeOf(VIPBuf), #0); VSock := FpSocket(AF_INET, SOCK_DGRAM, 0); VInetSockAddr.sin_family := AF_INET; //=== ct9999 ================= VInetSockAddr.sin_port := htons(CGDNSPORT); //=== ct9999 ================= VInetSockAddr.sin_addr := StrToHostAddr(CGDNSADDR); //=== ct9999 ================= if (FpConnect(VSock, @VInetSockAddr, SizeOf(VInetSockAddr)) = 0) then try VLength := SizeOf(VHostAddr); if (FpGetSockName(VSock, @VHostAddr, @VLength) = 0) then begin S := NetAddrToStr(VHostAddr.sin_addr); StrPCopy(PChar(VIPBuf), S); end else VError := SocketError; finally if (FpClose(VSock) <> 0) then VError := SocketError; end else VError := SocketError; if (VError <> 0) then Result := '127.0.0.1' else Result := StrPas(VIPBuf); {$ENDIF} {$IFDEF MSWINDOWS} {$HINTS OFF} WSAStartup($101, VWSAData); {$HINTS ON} SetLength(VName, 255); GetHostName(PAnsiChar(VName), 255); SetLength(VName, StrLen(PAnsiChar(VName))); VHostEnt := P_hostent(GetHostByName(PAnsiChar(VName))); Result := Format('%d.%d.%d.%d', [Byte(VHostEnt^.h_addr^[0]), Byte(VHostEnt^.h_addr^[1]), Byte(VHostEnt^.h_addr^[2]), Byte(VHostEnt^.h_addr^[3])]); SetLength(VName, 0); WSACleanup; {$ENDIF} end; const IFHWADDRLEN = 6; IF_NAMESIZE = 16; IFNAMSIZ = IF_NAMESIZE; SIOCGIFCONF = $8912; SIOCGIFNETMASK = $891b; SIOCGIFHWADDR = $8927; type TIPStrings = array [0..29] of string; //最多支持20个IP地址, 20个以上是VPN地址 Pifmap = ^ifmap; ifmap = record mem_start : culong; mem_end : culong; base_addr : word; irq : byte; dma : byte; port : byte; end; __caddr_t = pansichar; Pifreq = ^ifreq; ifreq = record ifr_ifrn : record case longint of 0 : ( ifrn_name : array[0..(IFNAMSIZ)-1] of char ); end; ifr_ifru : record case longint of 0 : ( ifru_addr : sockaddr ); 1 : ( ifru_dstaddr : sockaddr ); 2 : ( ifru_broadaddr : sockaddr ); 3 : ( ifru_netmask : sockaddr ); 4 : ( ifru_hwaddr : sockaddr ); 5 : ( ifru_flags : smallint ); 6 : ( ifru_ivalue : longint ); 7 : ( ifru_mtu : longint ); 8 : ( ifru_map : ifmap ); 9 : ( ifru_slave : array[0..(IFNAMSIZ)-1] of char ); 10 : ( ifru_newname : array[0..(IFNAMSIZ)-1] of char ); 11 : ( ifru_data : __caddr_t ); end; end; Pifconf = ^ifconf; ifconf = record ifc_len : longint; ifc_ifcu : record case longint of 0 : ( ifcu_buf : __caddr_t ); 1 : ( ifcu_req : Pifreq ); end; end; var IPNum: Integer; procedure GetAdapterInfos(var Mac, IP, Mask, Description: TIPStrings); var fd : Integer; ifc_get_iface: ifconf; ifr_get_iface: Pifreq; ifr: ifreq; buf: array [0..1023] of AnsiChar; i, iNum, iNO: Integer; sip, sDescription: string; begin IPNum := 0; ifc_get_iface.ifc_len := SizeOf(buf); ifc_get_iface.ifc_ifcu.ifcu_buf:= buf; fd := fpsocket(AF_INET, SOCK_DGRAM, 0); if fd >= 0 then begin if fpioctl(fd, SIOCGIFCONF, @ifc_get_iface) >= 0 then begin ifr_get_iface := Pifreq(@buf); iNum := ifc_get_iface.ifc_len div sizeOf(ifreq); for i := 1 to iNum do begin sDescription := StrPas(ifr_get_iface^.ifr_ifrn.ifrn_name); sip := NetAddrToStr(ifr_get_iface^.ifr_ifru.ifru_addr.sin_addr); ifr := ifr_get_iface^; Inc(ifr_get_iface); {if (sip = '0.0.0.0') or (sip = '127.0.0.1') then Continue;} iNO := IPNum; if IPNum < 20 then Inc(IPNum); IP[iNo] := sIP; Description[iNo] := sDescription; if fpioctl(fd, SIOCGIFNETMASK, @ifr) >= 0 then Mask[iNo] := NetAddrToStr(ifr.ifr_ifru.ifru_netmask.sin_addr); if fpioctl(fd, SIOCGIFHWADDR, @ifr) >= 0 then begin Mac[iNo] := Format('%.2X-%.2X-%.2X-%.2X-%.2X-%.2X', [ifr.ifr_ifru.ifru_hwaddr.sa_data[0], ifr.ifr_ifru.ifru_hwaddr.sa_data[1], ifr.ifr_ifru.ifru_hwaddr.sa_data[2], ifr.ifr_ifru.ifru_hwaddr.sa_data[3], ifr.ifr_ifru.ifru_hwaddr.sa_data[4], ifr.ifr_ifru.ifru_hwaddr.sa_data[5]]); end; end; end; end; end; var i: Integer; Mac, IP, Mask, Description: TIPStrings; FCon: TLUdp; {$R *.res} begin Writeln('Hello World!'); for i := 1 to ParamCount do Writeln('Param' + IntToStr(i) + '=' + ParamStr(i)); Writeln(GetLocalIP); GetAdapterInfos(Mac, IP, Mask, Description); for i := 1 to IPNUM do Writeln('Mac=' + Mac[i - 1] + ' IP=' + IP[i - 1] + ' Mask=' + Mask[i - 1] + ' Description=' + Description[i - 1]); FCon := TLUdp.Create(nil); // create a new TLUDP component with no parent coponent FCon.ReuseAddress := True; FCon.Timeout := 100; // responsive enough, but won't hog CPU if FCon.Listen(1999) then repeat // if listen/connect was successful FCon.CallAction; // "eventize" the event loop in lNet until False; // repeat this cycle until FQuit = true, due to error or user input FCon.Disconnect(True); end.
syncobjs.pp源码:
{ This file is part of the Free Component Library (FCL) Copyright (c) 1998 by Florian Klaempfl member of the Free Pascal development team See the file COPYING.FPC, included in this distribution, for details about the copyright. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} {$mode objfpc} {$h+} unit syncobjs; interface uses sysutils; type PSecurityAttributes = Pointer; TEventHandle = Pointer; const INFINITE = Cardinal(-1); type ESyncObjectException = Class(Exception); ELockException = Class(ESyncObjectException); ELockRecursionException = Class(ESyncObjectException); TWaitResult = (wrSignaled, wrTimeout, wrAbandoned, wrError); TSynchroObject = class(TObject) procedure Acquire;virtual; procedure Release;virtual; end; TCriticalSection = class(TSynchroObject) private CriticalSection : TRTLCriticalSection; public procedure Acquire;override; procedure Release;override; procedure Enter; function TryEnter:boolean; procedure Leave; constructor Create; destructor Destroy;override; end; THandleObject = class abstract (TSynchroObject) protected FHandle : TEventHandle; FLastError : Integer; public destructor destroy;override; property Handle : TEventHandle read FHandle; property LastError : Integer read FLastError; end; TEventObject = class(THandleObject) private FManualReset: Boolean; public constructor Create(EventAttributes : PSecurityAttributes; AManualReset,InitialState : Boolean;const Name : string); destructor destroy; override; procedure ResetEvent; procedure SetEvent; function WaitFor(Timeout : Cardinal) : TWaitResult; Property ManualReset : Boolean read FManualReset; end; TEvent = TEventObject; TSimpleEvent = class(TEventObject) constructor Create; end; implementation Resourcestring SErrEventCreateFailed = 'Failed to create OS basic event with name "%s"'; { --------------------------------------------------------------------- Real syncobjs implementation ---------------------------------------------------------------------} {$IFDEF OS2} type TBasicEventState = record FHandle: THandle; FLastError: longint; end; PLocalEventRec = ^TBasicEventState; {$ENDIF OS2} procedure TSynchroObject.Acquire; begin end; procedure TSynchroObject.Release; begin end; procedure TCriticalSection.Enter; begin Acquire; end; procedure TCriticalSection.Leave; begin Release; end; function TCriticalSection.TryEnter:boolean; begin result:=TryEnterCriticalSection(CriticalSection)<>0; end; procedure TCriticalSection.Acquire; begin EnterCriticalSection(CriticalSection); end; procedure TCriticalSection.Release; begin LeaveCriticalSection(CriticalSection); end; constructor TCriticalSection.Create; begin Inherited Create; InitCriticalSection(CriticalSection); end; destructor TCriticalSection.Destroy; begin DoneCriticalSection(CriticalSection); end; destructor THandleObject.destroy; begin end; constructor TEventObject.Create(EventAttributes : PSecurityAttributes; AManualReset,InitialState : Boolean;const Name : string); begin FHandle := BasicEventCreate(EventAttributes, AManualReset, InitialState, Name); if (FHandle=Nil) then Raise ESyncObjectException.CreateFmt(SErrEventCreateFailed,[Name]); FManualReset:=AManualReset; end; destructor TEventObject.destroy; begin BasicEventDestroy(Handle); end; procedure TEventObject.ResetEvent; begin BasicEventResetEvent(Handle); end; procedure TEventObject.SetEvent; begin BasicEventSetEvent(Handle); end; function TEventObject.WaitFor(Timeout : Cardinal) : TWaitResult; begin Result := TWaitResult(basiceventWaitFor(Timeout, Handle)); if Result = wrError then {$IFDEF OS2} FLastError := PLocalEventRec (Handle)^.FLastError; {$ELSE OS2} {$if defined(getlastoserror)} FLastError := GetLastOSError; {$else} FLastError:=-1; {$endif} {$ENDIF OS2} end; constructor TSimpleEvent.Create; begin inherited Create(nil, True, False, ''); end; end.

浙公网安备 33010602011771号