近日和樵夫交流时发现unidac在aarch64 linux交叉编译UniProvider.pas出错:
UniProvider.pas(1040,1) Error: Compilation raised exception internally
奇怪的是其他CPU类型是正常的。
樵夫的解决办法:
1、修改UniProvider.pas,添加
{$if FPC_FULLVERSION<30301}
TEnumeratorOption = class(TOption) private FTypeInfo: PTypeInfo; FMinValue: integer; FMaxValue: integer; FInternalType: boolean; protected procedure InternalGetValuesList(List: TStrings); override; public procedure SetTypeInfo(typeInfo: PTypeInfo); {$if FPC_FULLVERSION<30301} constructor Create(const OptionName: string; InternalIndex: integer; InternalClasses: array of TClass; DefaultValue: variant; TypeInfo: PTypeInfo); {$endif} function GetAsString(const Value: variant): string; override; function GetAsNative(const Value: string): variant; override; function CheckValue(const Value: string): boolean; override; end; TOptionsList = class(TStringList)
{$if FPC_FULLVERSION<30301} constructor TEnumeratorOption.Create(const OptionName: string; InternalIndex: integer; InternalClasses: array of TClass; DefaultValue: variant; TypeInfo: PTypeInfo); var TypeData: PTypeData; TypeName: string; begin inherited Create(OptionName, InternalIndex, InternalClasses, DefaultValue); FTypeInfo := TypeInfo; TypeData := GetTypeData(FTypeInfo); if TypeData <> nil then begin FMinValue := TypeData{$IFNDEF CLR}^{$ENDIF}.MinValue; FMaxValue := TypeData{$IFNDEF CLR}^{$ENDIF}.MaxValue; end; {$IFDEF NEXTGEN} TypeName := GetTypeName(FTypeInfo); {$ELSE} TypeName := string(FTypeInfo.Name); {$ENDIF} FInternalType := (TypeName <> '') and (TypeName[1] = '_'); end; {$endif}
修改相应的TxxxUniProvider.pas,添加
{$if FPC_FULLVERSION>=30301}
参考以下方法修改
procedure TAccessUniProvider.CreateConnectionOptions; {$if FPC_FULLVERSION>=30301} var tmpOption: TEnumeratorOption; {$endif} begin if FConnectionOptions = nil then begin FConnectionOptions := TOptionsList.Create(GetProviderName); FConnectionOptions.Add(TBooleanOption.Create('ColumnWiseBinding', prColumnWiseBinding, [TAccessConnection], False)); FConnectionOptions.Add(TIntegerOption.Create('ConnectionTimeout', prConnectionTimeout, [TAccessConnection], 15)); FConnectionOptions.Add(TBooleanOption.Create('ExclusiveLock', prExclusiveLock, [TAccessConnection], False)); FConnectionOptions.Add(TBooleanOption.Create('ExtendedAnsiSQL', prExtendedAnsiSQL, [TAccessConnection], False)); FConnectionOptions.Add(TBooleanOption.Create('ForceCreateDatabase', prForceCreateDatabase, [TAccessConnection], False)); FConnectionOptions.Add(TStringOption.Create('SystemDatabase', prSystemDatabase, [TAccessConnection], '')); FConnectionOptions.Add(TBooleanOption.Create('UseUnicode', prUseUnicode, [TAccessConnection], False)); {$if FPC_FULLVERSION>=30301} tmpOption:=TEnumeratorOption.Create('DriverVersion', prDriverVersion, [TAccessConnection], Variant(dvAuto)); tmpOption.SetTypeInfo(TypeInfo(TDriverVersion)); FConnectionOptions.Add(tmpOption); {$else} FConnectionOptions.Add(TEnumeratorOption.Create('DriverVersion', prDriverVersion, [TAccessConnection], Variant(dvAuto), TypeInfo(TDriverVersion))); {$endif} end; end; procedure TAccessUniProvider.CreateSQLOptions; begin if FSQLOptions = nil then begin FSQLOptions := TOptionsList.Create(GetProviderName); FSQLOptions.Add(TIntegerOption.Create('CommandTimeout', prCommandTimeout, [TAccessCommand], 0)); end; end; procedure TAccessUniProvider.CreateDataSetOptions; begin if FDataSetOptions = nil then begin FDataSetOptions := TOptionsList.Create(GetProviderName); FDataSetOptions.Add(TIntegerOption.Create('CommandTimeout', prCommandTimeout, [TAccessRecordSet], 0)); FDataSetOptions.Add(TBooleanOption.Create('ExtendedFieldsInfo', prExtendedFieldsInfo, [TAccessRecordSet], False)); FDataSetOptions.Add(TBooleanOption.Create('FetchAll', prFetchAll, [TAccessRecordSet], True)); end; end;
相关单元按以上方法修改后就能交叉编译
注意(2024-11-07更新):
unidac 10.3.0及之后的版本UniProvider中的TEnumeratorOption = class(TOption)删除了原来的procedure SetTypeInfo(typeInfo: PTypeInfo),按上述方法编译时会出错。
添加下面红色代码就可以。
TEnumeratorOption = class(TOption) private FTypeInfo: PTypeInfo; FMinValue: integer; FMaxValue: integer; FInternalType: boolean; protected procedure InternalGetValuesList(List: TStrings); override; public procedure SetTypeInfo(typeInfo: PTypeInfo); {$if FPC_FULLVERSION<30301} constructor Create(const OptionName: string; InternalIndex: integer; InternalClasses: array of TClass; DefaultValue: variant; TypeInfo: PTypeInfo); {$endif} function GetAsString(const Value: variant): string; override; function GetAsNative(const Value: string): variant; override; function CheckValue(const Value: string): boolean; override; end;
procedure TEnumeratorOption.SetTypeInfo(typeInfo: PTypeInfo); var TypeData: PTypeData; TypeName: string; begin FTypeInfo := TypeInfo; TypeData := GetTypeData(FTypeInfo); if TypeData <> nil then begin FMinValue := TypeData{$IFNDEF CLR}^{$ENDIF}.MinValue; FMaxValue := TypeData{$IFNDEF CLR}^{$ENDIF}.MaxValue; end; {$IFDEF NEXTGEN} TypeName := GetTypeName(FTypeInfo); {$ELSE} TypeName := string(FTypeInfo.Name); {$ENDIF} FInternalType := (TypeName <> '') and (TypeName[1] = '_'); end; {$if FPC_FULLVERSION<30301} constructor TEnumeratorOption.Create(const OptionName: string; InternalIndex: integer; InternalClasses: array of TClass; DefaultValue: variant; TypeInfo: PTypeInfo); var TypeData: PTypeData; TypeName: string; begin inherited Create(OptionName, InternalIndex, InternalClasses, DefaultValue); FTypeInfo := TypeInfo; TypeData := GetTypeData(FTypeInfo); if TypeData <> nil then begin FMinValue := TypeData{$IFNDEF CLR}^{$ENDIF}.MinValue; FMaxValue := TypeData{$IFNDEF CLR}^{$ENDIF}.MaxValue; end; {$IFDEF NEXTGEN} TypeName := GetTypeName(FTypeInfo); {$ELSE} TypeName := string(FTypeInfo.Name); {$ENDIF} FInternalType := (TypeName <> '') and (TypeName[1] = '_'); end; {$endif}