36
Classes, SysUtils, LCLProc, Forms, Controls, Dialogs, LResources,
36
Classes, SysUtils, LCLProc, Forms, Controls, Dialogs, LResources, LConvEncoding,
37
37
FileUtil, contnrs, IniFiles, AVL_Tree,
39
39
CodeToolManager, DefineTemplates, CodeAtom, CodeCache, LinkScanner,
162
163
function CreateInstance: TModalResult; virtual; abstract;
163
164
function CreateMainSourceFile: TModalResult; virtual;
164
function ScanMainSourceFile: TModalResult; virtual;
165
165
function ConvertMainSourceFile: TModalResult; virtual;
166
166
function FindAllUnits: TModalResult; virtual; abstract;
167
167
function ConvertAllUnits: TModalResult; virtual; abstract;
168
168
function ExtractOptionsFromDelphiSource: TModalResult; virtual; abstract;
169
// The following protected funcs are needed only because Project and LazPackage
170
// don't inherit from the same class.
169
// The following protected funcs are needed only because
170
// Project and LazPackage don't inherit from the same class.
171
171
function GetCompOpts: TBaseCompilerOptions; virtual; abstract;
172
172
function GetCustomDefines: TDefineTemplate; virtual; abstract;
173
173
procedure CustomDefinesChanged; virtual; abstract;
289
function CheckDelphiFileExt(const Filename: string): TModalResult;
292
if CompareFileExt(Filename,'.pas',false)<>0 then
293
Result:=QuestionDlg(lisNotADelphiUnit,
294
Format(lisTheFileIsNotADelphiUnit, ['"', Filename, '"']),
295
mtError, [mrCancel,lisConvDelphiSkipThisFile,mbAbort,lisInfoBuildMakeAbort], 0);
298
function CheckFilenameForLCLPaths(const Filename: string): TModalResult;
299
// check if the unitpath of the directory of filename contains the path to the LCL
303
LazarusSrcDir: string;
305
NextStartPos: Integer;
307
// get directory of filename
308
Directory:=ExtractFilePath(Filename);
309
// get unitpath definition of directory
310
UnitPath:=CodeToolBoss.GetUnitPathForDirectory(Directory);
311
// get lazarus source directory
312
LazarusSrcDir:=CodeToolBoss.GlobalValues.Variables[ExternalMacroStart+'LazarusDir'];
313
// create base path to LCL compiled units <LazarusSrcDir>/lcl/units/
314
LCLPath:=TrimFilename(LazarusSrcDir+SetDirSeparators('/lcl/units/'));
316
if GetNextUsedDirectoryInSearchPath(UnitPath,LCLPath,NextStartPos)='' then
318
LCLPath:=LCLPath+'$(TargetCPU)-$(TargetOS)';
319
Result:=QuestionDlg(lisLCLUnitPathMissing,
320
Format(lisTheCurrentUnitPathForTheFileIsThePathToTheLCLUnits,
321
[sLineBreak,'"',Filename,'"',sLineBreak,'"',UnitPath,'"',sLineBreak,
322
sLineBreak,'"',LCLPath,'"',sLineBreak,sLineBreak,sLineBreak]),
323
mtError, [mrOK, lisContinue, mrAbort, lisInfoBuildMakeAbort], 0);
329
function CheckDelphiProjectExt(const Filename: string): TModalResult;
331
if CompareFileExt(Filename,'.dpr',false)<>0 then begin
332
Result:=QuestionDlg(lisNotADelphiProject,
333
Format(lisTheFileIsNotADelphiProjectDpr, ['"', Filename, '"']),
334
mtError, [mrCancel, lisConvDelphiSkipThisStep, mbAbort], 0);
340
281
function ConvertDelphiAbsoluteToRelativeFile(const Filename: string; AProject: TProject): string;
341
282
// often projects use paths near to their project directory. For example:
342
283
// A project /somewhere/MyProjects/project1.dpr
524
470
fPascalBuffer:=nil;
525
471
Result:=LoadCodeBuffer(fPascalBuffer,fLazUnitFilename,
526
472
[lbfCheckIfText,lbfUpdateFromDisk],true);
473
if Result<>mrOk then exit;
474
// Change encoding to UTF-8
475
if fPascalBuffer.DiskEncoding<>EncodingUTF8 then begin
476
IDEMessagesWindow.AddMsg(Format(lisConvDelphiChangedEncodingToUTF8,
477
[fPascalBuffer.DiskEncoding]), '', -1);
478
fPascalBuffer.DiskEncoding:=EncodingUTF8; // Takes effect when buffer is saved.
527
480
// Create a shared link for codetools.
528
481
Assert(fCTLink=Nil, 'fCTLink should be Nil in CopyAndLoadFile');
529
482
fCTLink:=TCodeToolLink.Create(fPascalBuffer);
530
483
fCTLink.Settings:=fSettings;
484
fCTLink.AskAboutError:=Assigned(fOwnerConverter);
485
// Create a toold for missing units.
486
fUsedUnitsTool:=TUsedUnitsTool.Create(fCTLink, fOrigUnitFilename);
487
if Assigned(fOwnerConverter) then begin
488
fUsedUnitsTool.CheckPackDepEvent:=@fOwnerConverter.CheckPackageDependency;
489
fUsedUnitsTool.IsConsoleApp:=fOwnerConverter.fIsConsoleApp;
533
function TConvertDelphiUnit.FixLfmFilename(ADfmFilename: string): TModalResult;
493
function TConvertDelphiUnit.FixLfmFilenameAndLoad(ADfmFilename: string): TModalResult;
535
495
LfmFilename: string; // Lazarus .LFM file name.
496
DFMConverter: TDFMConverter;
497
TempLFMBuffer: TCodeBuffer;
563
525
// convert .dfm file to .lfm file (without context type checking)
564
526
if FileExistsUTF8(LfmFilename) then begin
565
Result:=ConvertDfmToLfm(LfmFilename);
566
if Result<>mrOk then exit;
527
DFMConverter:=TDFMConverter.Create(IDEMessagesWindow);
529
Result:=DFMConverter.ConvertDfmToLfm(LfmFilename);
530
if Result<>mrOk then exit;
534
// Change encoding to UTF-8
535
Result:=LoadCodeBuffer(TempLFMBuffer,LfmFilename,
536
[lbfCheckIfText,lbfUpdateFromDisk],true);
537
if TempLFMBuffer.DiskEncoding<>EncodingUTF8 then begin
538
IDEMessagesWindow.AddMsg(Format(lisConvDelphiChangedEncodingToUTF8,
539
[TempLFMBuffer.DiskEncoding]), '', -1);
540
TempLFMBuffer.DiskEncoding:=EncodingUTF8;
567
543
// Read form file code in.
568
if fSettings.Target<>ctLazarusDelphiSameDfm then begin
544
if not fSettings.SameDfmFile then begin
569
545
Result:=LoadCodeBuffer(fLFMBuffer,LfmFilename,
570
546
[lbfCheckIfText,lbfUpdateFromDisk],true);
594
570
DfmFilename: string; // Delphi .DFM file name.
595
571
ConvTool: TConvDelphiCodeTool;
597
IDEMessagesWindow.AddMsg(Format(lisConvDelphiConvertingUnitFile,
598
[fOrigUnitFilename]), '', -1);
599
Application.ProcessMessages;
600
573
// Get DFM file name and close it in editor.
601
574
DfmFilename:=GetDfmFileName;
602
Result:=FixLfmFilename(DfmFilename);
575
Result:=FixLfmFilenameAndLoad(DfmFilename);
603
576
if Result<>mrOk then exit;
604
// Check LCL path for single files. They are correct when converting projects.
605
{ if not Assigned(fOwnerConverter) then begin
606
Result:=CheckFilenameForLCLPaths(fLazUnitFilename);
607
if Result<>mrOk then exit;
609
577
// Fix include file names.
610
578
Result:=FixIncludeFiles;
611
579
if Result<>mrOk then exit;
612
fCTLink.IsConsoleApp:=False;
613
fCTLink.IsMainFile:=False;
614
fCTLink.AskAboutError:=False;
615
if Assigned(fOwnerConverter) then begin
616
fCTLink.IsConsoleApp:= fOwnerConverter.fIsConsoleApp;
617
fCTLink.IsMainFile:=fOwnerConverter.MainName=fLazUnitFilename;
618
fCTLink.AskAboutError:=True;
580
if fSettings.UnitsReplaceMode<>rlDisabled then begin
581
// Find and prepare the missing units. Don't replace yet.
582
Result:=fUsedUnitsTool.Prepare;
583
if Result<>mrOk then exit;
584
if fUsedUnitsTool.MissingUnitCount>0 then begin
585
Result:=ReduceMissingUnits;
586
if Result<>mrOk then exit;
620
// Take care of missing units in uses sections.
589
// Do the actual code conversion.
590
ConvTool:=TConvDelphiCodeTool.Create(fCTLink);
623
if fSettings.UnitsReplaceMode<>rlDisabled then begin
624
fUsedUnitsTool:=TUsedUnitsTool.Create(fCTLink, fOrigUnitFilename);
625
// Find and prepare the missing units. Don't replace yet.
626
Result:=fUsedUnitsTool.Prepare;
627
if Result<>mrOk then exit;
628
if fUsedUnitsTool.MissingUnitCount>0 then begin
629
Result:=ReduceMissingUnits;
630
if Result<>mrOk then exit;
633
// Do the actual code conversion.
634
ConvTool:=TConvDelphiCodeTool.Create(fCTLink);
636
ConvTool.LowerCaseRes:=FileExistsUTF8(ChangeFileExt(fLazUnitFilename, '.res'));
637
ConvTool.HasFormFile:=DfmFilename<>'';
638
Result:=ConvTool.Convert;
639
if Result<>mrOk then exit;
643
// Fix or comment missing units, show error messages.
644
if fSettings.UnitsReplaceMode<>rlDisabled then
645
Result:=fUsedUnitsTool.Convert;
592
if Assigned(fOwnerConverter) then
593
ConvTool.IsConsoleApp:=fOwnerConverter.fIsConsoleApp;
594
ConvTool.LowerCaseRes:=FileExistsUTF8(ChangeFileExt(fLazUnitFilename, '.res'));
595
ConvTool.HasFormFile:=DfmFilename<>'';
596
ConvTool.AddUnitEvent:=@fUsedUnitsTool.AddUnitIfNeeded;
597
Result:=ConvTool.Convert;
647
FreeAndNil(fUsedUnitsTool);
809
768
// The initial unit name cache is done in a thread so that GUI shows at once.
810
769
CacheUnitsThread: TCacheUnitsThread;
771
if CompareFileExt(fOrigPFilename,'.dproj',false)=0 then begin
772
ShowMessage('.dproj file is not supported yet. The file is used by Delphi 2007 and newer.'+
773
' Please select a .dpr file for projects or .dpk file for packages.');
812
776
IDEMessagesWindow.Clear;
813
777
// Start scanning unit files one level above project path. The GUI will appear
814
778
// without delay but then we must wait for the thread before continuing.
815
779
CacheUnitsThread:=TCacheUnitsThread.Create(Self, fSettings.MainPath);
817
CacheUnitsThread.Resume;
781
CacheUnitsThread.Start;
818
782
Result:=fSettings.RunForm; // Get settings from user.
819
783
Screen.Cursor:=crHourGlass;
862
826
RemoveNonExistingFiles(false);
863
827
CleanUpCompilerOptionsSearchPaths(CompOpts);
864
// Scan LPR file for directives. Sets fIsConsoleApp flag.
865
Result:=ScanMainSourceFile;
866
if Result<>mrOK then exit;
867
828
// LCL dependency is added automatically later for GUI applications.
868
829
// AddPackageDependency('LCL');
869
830
// ToDo: make an option to add NoGUI to Project.CompilerOptions.LCLWidgetType.
870
831
if fProjPack is TProject then
871
PkgBoss.AddDefaultDependencies(fProjPack as TProject);
832
PkgBoss.OpenProjectDependencies(fProjPack as TProject,true);
872
833
CustomDefinesChanged;
874
835
SetCompilerModeForDefineTempl(CustomDefines);
876
Result:=ConvertMainSourceFile; // Convert project's LPR file.
877
837
if Result<>mrOK then exit;
878
838
// get all options from the .dpr or .dpk file
879
839
Result:=ExtractOptionsFromDelphiSource;
880
840
if Result<>mrOK then exit;
881
841
Result:=FindAllUnits; // find all files and save the project.
882
842
if Result<>mrOK then exit;
843
Result:=ConvertMainSourceFile; // Convert project's LPR file.
844
if Result<>mrOK then exit;
883
845
Result:=ConvertAllUnits; // convert all files.
885
847
UnsetCompilerModeForDefineTempl(CustomDefines);
1097
1062
Options.SrcPath:=CleanProjectSearchPath(Options.SrcPath);
1065
function TConvertDelphiPBase.CheckPackageDependency(AUnitName: string): Boolean;
1068
Dep: TPkgDependency;
1072
Pack:=PackageGraph.FindUnitInAllPackages(AUnitName, True);
1073
if Assigned(Pack) then begin
1074
// Found from package: add package to project dependencies and open it.
1075
s:=Pack.LazPackage.Name;
1078
AddPackageDependency(s);
1079
IDEMessagesWindow.AddMsg(Format(lisConvDelphiAddedPackageRequirement, [s]), '', -1);
1080
Dep:=FindDependencyByName(s);
1081
if Assigned(Dep) then
1082
PackageGraph.OpenDependency(Dep,false);
1085
// ToDo: Install the required package automatically from a repository...
1100
1089
function TConvertDelphiPBase.DoMissingUnits(AUsedUnitsTool: TUsedUnitsTool): integer;
1101
1090
// Locate unit names from earlier cached list or from packages.
1102
1091
// Return the number of units still missing.
1104
1093
procedure DoMissingSub(AUsedUnits: TUsedUnits);
1107
Dep: TPkgDependency;
1108
1095
mUnit, sUnitPath, RealFileName, RealUnitName: string;
1121
1108
RealFileName:=fCachedRealFileNames[UpperCase(mUnit)];
1122
1109
RealUnitName:=ExtractFileNameOnly(RealFileName);
1123
1110
if (RealUnitName<>'') and (RealUnitName<>mUnit) then
1124
AUsedUnits.UnitsToRename[mUnit]:=RealUnitName;
1111
AUsedUnits.UnitsToFixCase[mUnit]:=RealUnitName;
1125
1112
// Will be added later to project.
1126
1113
fUnitsToAddToProject.Add(sUnitPath+RealFileName);
1127
1114
AUsedUnits.MissingUnits.Delete(i); // No more missing, delete from list.
1130
Pack:=PackageGraph.FindUnitInAllPackages(mUnit, True);
1131
if Assigned(Pack) then begin
1132
// Found from package: add package to project dependencies and open it.
1133
AddPackageDependency(Pack.LazPackage.Name);
1134
Dep:=FindDependencyByName(Pack.LazPackage.Name);
1135
if Assigned(Dep) then
1136
PackageGraph.OpenDependency(Dep,false);
1137
AUsedUnits.MissingUnits.Delete(i);
1116
else if CheckPackageDependency(mUnit) then
1117
AUsedUnits.MissingUnits.Delete(i);
1256
1229
// adds the .lpr as main unit to the project, if not already done
1258
1231
MainUnitInfo: TUnitInfo;
1232
ConvTool: TConvDelphiCodeTool;
1260
1234
// Converter for main LPR file.
1261
1235
fMainUnitConverter:=TConvertDelphiUnit.Create(Self,fOrigPFilename,[]);
1262
if fSettings.Target in [ctLazarusDelphi, ctLazarusDelphiSameDfm] then
1236
if fSettings.SupportDelphi then
1263
1237
fMainUnitConverter.LazFileExt:=ExtractFileExt(fOrigPFilename)
1265
1239
fMainUnitConverter.LazFileExt:='.lpr';
1266
fMainUnitConverter.CopyAndLoadFile;
1240
Result:=fMainUnitConverter.CopyAndLoadFile;
1241
if Result<>mrOk then exit;
1267
1242
if LazProject.MainUnitInfo=nil then begin
1268
1243
// add .lpr file to project as main unit
1269
1244
MainUnitInfo:=TUnitInfo.Create(fMainUnitConverter.fPascalBuffer);
1276
1251
// replace main unit in project
1277
1252
LazProject.MainUnitInfo.Source:=fMainUnitConverter.fPascalBuffer;
1279
Result:=LazarusIDE.DoOpenEditorFile(fMainUnitConverter.fLazUnitFilename,0,0,[ofQuiet]);
1280
if Result<>mrOK then exit;
1284
function TConvertDelphiProject.ScanMainSourceFile: TModalResult;
1286
CTLink: TCodeToolLink;
1287
ConvTool: TConvDelphiCodeTool;
1290
CTLink:=TCodeToolLink.Create(fMainUnitConverter.fPascalBuffer);
1291
ConvTool:=TConvDelphiCodeTool.Create(CTLink);
1254
// Scan LPR file for directives. Sets fIsConsoleApp flag.
1255
ConvTool:=TConvDelphiCodeTool.Create(fMainUnitConverter.fCTLink);
1293
1257
fIsConsoleApp:=ConvTool.FindApptypeConsole;
1261
CompOpts.Win32GraphicApp := not fIsConsoleApp;
1262
with fMainUnitConverter do begin
1263
fUsedUnitsTool.IsMainFile:=True;
1264
fUsedUnitsTool.IsConsoleApp:=fIsConsoleApp;
1265
Result:=LazarusIDE.DoOpenEditorFile(fLazUnitFilename,0,0,[ofQuiet]);
1266
if Result<>mrOK then exit;
1300
1271
function TConvertDelphiProject.ConvertMainSourceFile: TModalResult;
1305
1276
Result:=fMainUnitConverter.ConvertFormFile;
1308
function TConvertDelphiProject.AddUnit(AUnitName: string;
1279
function TConvertDelphiProject.AddUnit(AFileName: string;
1309
1280
out OutUnitInfo: TUnitInfo): TModalResult;
1310
1281
// add new unit to project
1312
1283
CurUnitInfo: TUnitInfo;
1284
RP, PureUnitName: String;
1316
1288
OutUnitInfo:=nil;
1317
if not FilenameIsAbsolute(AUnitName) then
1318
AUnitName:=AppendPathDelim(LazProject.ProjectDirectory)+AUnitName;
1319
AUnitName:=TrimFilename(AUnitName);
1320
if not FileExistsUTF8(AUnitName) then
1289
if not FilenameIsAbsolute(AFileName) then
1290
AFileName:=AppendPathDelim(LazProject.ProjectDirectory)+AFileName;
1291
AFileName:=TrimFilename(AFileName);
1292
if not FileExistsUTF8(AFileName) then
1322
1294
// Create relative search path for project settings.
1323
RP:=ExtractFilePath(CreateRelativePath(AUnitName, LazProject.ProjectDirectory));
1295
RP:=ExtractFilePath(CreateRelativePath(AFileName, LazProject.ProjectDirectory));
1324
1296
if (RP<>'') and (fUnitSearchPaths.IndexOf(RP)<0) then
1325
1297
fUnitSearchPaths.Add(RP);
1326
// Check unitname and create UnitInfo.
1327
CurUnitInfo:=LazProject.UnitInfoWithFilename(AUnitName);
1328
if CurUnitInfo=nil then begin
1329
if FilenameIsPascalUnit(AUnitName) then begin
1330
CurUnitInfo:=LazProject.UnitWithUnitname(ExtractFileNameOnly(AUnitName));
1331
if CurUnitInfo<>nil then begin
1332
Result:=QuestionDlg(lisConvDelphiUnitnameExistsTwice,
1333
Format(lisConvDelphiThereAreTwoUnitsWithTheSameUnitname,
1334
[#13, CurUnitInfo.Filename, #13, AUnitName, #13]),
1335
mtWarning, [mrYes, lisConvDelphiRemoveFirst, mrNo,
1336
lisConvDelphiRemoveSecond,
1337
mrIgnore, lisConvDelphiKeepBoth, mrAbort], 0);
1339
mrYes: CurUnitInfo.IsPartOfProject:=false;
1298
PureUnitName:=ExtractFileNameOnly(AFileName);
1299
if not fSettings.OmitProjUnits.Find(PureUnitName, x) then begin
1300
// Check unitname and create UnitInfo.
1301
CurUnitInfo:=LazProject.UnitInfoWithFilename(AFileName);
1302
if CurUnitInfo=nil then begin
1303
if FilenameIsPascalUnit(AFileName) then begin
1304
CurUnitInfo:=LazProject.UnitWithUnitname(PureUnitName);
1305
if CurUnitInfo<>nil then begin
1306
Result:=QuestionDlg(lisConvDelphiUnitnameExistsTwice,
1307
Format(lisConvDelphiThereAreTwoUnitsWithTheSameUnitname,
1308
[#13, CurUnitInfo.Filename, #13, AFileName, #13]),
1309
mtWarning, [mrYes, lisConvDelphiRemoveFirst, mrNo,
1310
lisConvDelphiRemoveSecond,
1311
mrIgnore, lisConvDelphiKeepBoth, mrAbort], 0);
1313
mrYes: CurUnitInfo.IsPartOfProject:=false;
1321
CurUnitInfo:=TUnitInfo.Create(nil);
1322
CurUnitInfo.Filename:=AFileName;
1323
LazProject.AddFile(CurUnitInfo,false);
1347
CurUnitInfo:=TUnitInfo.Create(nil);
1348
CurUnitInfo.Filename:=AUnitName;
1349
LazProject.AddFile(CurUnitInfo,false);
1325
CurUnitInfo.IsPartOfProject:=true;
1326
OutUnitInfo:=CurUnitInfo;
1329
fMainUnitConverter.fUsedUnitsTool.Remove(PureUnitName);
1330
IDEMessagesWindow.AddMsg(Format(lisConvDelphiProjOmittedUnit,[PureUnitName]), '', -1);
1351
CurUnitInfo.IsPartOfProject:=true;
1352
OutUnitInfo:=CurUnitInfo;
1355
1334
function TConvertDelphiProject.FindAllUnits: TModalResult;
1390
1368
AllPath:=fUnitSearchPaths.DelimitedText;
1391
// set unit paths to find all project units
1392
LazProject.CompilerOptions.OtherUnitFiles:=
1393
MergeSearchPaths(LazProject.CompilerOptions.OtherUnitFiles,AllPath);
1395
LazProject.CompilerOptions.IncludePath:=
1396
MergeSearchPaths(LazProject.CompilerOptions.IncludePath,AllPath);
1369
// set unit and include paths for project
1370
with LazProject.CompilerOptions do begin
1371
OtherUnitFiles:=MergeSearchPaths(OtherUnitFiles,AllPath);
1372
IncludePath:=MergeSearchPaths(IncludePath,AllPath);
1397
1374
// clear caches
1398
1375
LazProject.DefineTemplates.SourceDirectoriesChanged;
1441
1419
// Main LPR file was converted earlier.
1442
1420
if CurUnitInfo.IsPartOfProject and (CurUnitInfo<>LazProject.MainUnitInfo) then begin
1443
1421
Result:=ConvertOne(CurUnitInfo);
1444
if Result<>mrOK then Break;
1422
if Result=mrIgnore then Continue;
1423
if Result=mrAbort then Exit;
1424
// if Result<>mrOK then Break;
1447
1427
// During conversion there were more units added to be converted.
1448
1428
for i:=0 to fUnitsToAddToProject.Count-1 do begin
1449
1429
Result:=AddUnit(fUnitsToAddToProject[i], CurUnitInfo);
1450
if Result=mrNo then continue;
1451
if Result=mrAbort then Break;
1430
if Result=mrNo then Continue;
1431
if Result=mrAbort then Exit;
1452
1432
Result:=ConvertOne(CurUnitInfo);
1453
if Result<>mrOK then Break;
1433
if Result=mrIgnore then Continue;
1434
if Result=mrAbort then Exit;
1436
if Result=mrOK then begin
1437
if fUseThreads then begin
1438
Result:=fMainUnitConverter.fUsedUnitsTool.AddThreadSupport;
1439
if Result<>mrOK then exit;
1456
1441
Result:=ConvertAllFormFiles(ConvUnits);
1458
1444
ConvUnits.Free; // Owns and frees converter objects.