diff --git a/CHANGELOG.md b/CHANGELOG.md index 601f7650..c4a1f97c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,14 +3,15 @@ ## Enhancements - Search and Replace: after a failed search give the editor the focus back. +- It's possible to open ".mak" or "makefile" files as projects. The project inspector will display the rules as configurations and display the content of "src", "include", "import" as source files. ## Bugs fixed -- crash to desktop for certain invalid or incomplete D constructs. (#107) +- Crash to desktop for certain invalid or incomplete D constructs. (#107) ## Other -- dexed-d does not rely on the old "iz" library +- dexed-d does not rely on the old "iz" library anymore. # v3.9.17 diff --git a/lazproj/dexed.lpi b/lazproj/dexed.lpi index 31006aed..375f1dab 100644 --- a/lazproj/dexed.lpi +++ b/lazproj/dexed.lpi @@ -1,11 +1,13 @@ - + + + + - <ResourceType Value="res"/> <UseXPManifest Value="True"/> @@ -549,7 +551,7 @@ <PackageName Value="LCL"/> </Item8> </RequiredPackages> - <Units Count="63"> + <Units Count="64"> <Unit0> <Filename Value="dexed.lpr"/> <IsPartOfProject Value="True"/> @@ -878,6 +880,10 @@ <Filename Value="..\src\u_sxsyn.pas"/> <IsPartOfProject Value="True"/> </Unit62> + <Unit63> + <Filename Value="..\src\u_makeproject.pas"/> + <IsPartOfProject Value="True"/> + </Unit63> </Units> </ProjectOptions> <CompilerOptions> diff --git a/lazproj/dexed.lpr b/lazproj/dexed.lpr index 8d30ee07..50a32e8b 100644 --- a/lazproj/dexed.lpr +++ b/lazproj/dexed.lpr @@ -13,7 +13,8 @@ uses u_processes, u_dialogs, u_dubprojeditor, u_controls, u_dfmt, u_lcldragdrop, u_stringrange, u_dlangmaps, u_projgroup, u_projutils, u_d2synpresets, u_dbgitf, u_ddemangle, u_dubproject, - u_halstead, u_diff, u_profileviewer, u_semver, u_term, u_simpleget; + u_halstead, u_diff, u_profileviewer, u_semver, u_term, u_simpleget, +u_makeproject; {$R *.res} diff --git a/src/u_dmdwrap.pas b/src/u_dmdwrap.pas index cde2d9c4..b67a2632 100644 --- a/src/u_dmdwrap.pas +++ b/src/u_dmdwrap.pas @@ -668,7 +668,7 @@ var baseopt: TOutputOpts; const trgKindStr: array[TTargetSystem] of string = ('', '-m32','-m64'); - binKindStr: array[TProjectBinaryKind] of string = ('', '-lib', '-shared', '-c'); + binKindStr: array[TProjectBinaryKind] of string = ('', '-lib', '-shared', '-c', ''); bchKindStr: array[TBoundCheckKind] of string = ('on', 'safeonly', 'off'); begin if base.isNotAssigned then diff --git a/src/u_interfaces.pas b/src/u_interfaces.pas index 413a6ac8..0de359c1 100644 --- a/src/u_interfaces.pas +++ b/src/u_interfaces.pas @@ -11,10 +11,10 @@ uses type // describes the project kind. Used as a hint to cast ICommonProject.getProject() - TProjectFormat = (pfDEXED, pfDUB); + TProjectFormat = (pfDEXED, pfDUB, pfMAKE); // describes the binary kind produced when compiling a project - TProjectBinaryKind = (executable, staticlib, sharedlib, obj); + TProjectBinaryKind = (executable, staticlib, sharedlib, obj, unknown); (** * Common project interface. diff --git a/src/u_main.lfm b/src/u_main.lfm index 43bcd2f0..1464d94c 100644 --- a/src/u_main.lfm +++ b/src/u_main.lfm @@ -1,17 +1,17 @@ object MainForm: TMainForm Left = 383 - Height = 35 + Height = 34 Top = 610 - Width = 687 + Width = 673 AllowDropFiles = True Caption = 'Dexed' + DesignTimePPI = 94 Menu = mainMenu OnClose = FormClose OnCloseQuery = FormCloseQuery OnDropFiles = FormDropFiles OnResize = FormResize ShowHint = True - LCLVersion = '2.2.0.1' object mainMenu: TMainMenu Top = 1 object MenuItem1: TMenuItem @@ -417,8 +417,7 @@ object MainForm: TMainForm end end object Actions: TActionList - Left = 32 - Top = 1 + Left = 31 object actEdCopy: TAction Category = 'Edit' Caption = 'Copy' @@ -866,7 +865,7 @@ object MainForm: TMainForm object ApplicationProperties1: TApplicationProperties OnActivate = ApplicationProperties1Activate OnException = ApplicationProperties1Exception - Left = 64 + Left = 63 Top = 1 end end diff --git a/src/u_main.pas b/src/u_main.pas index f33d2224..9e98bc5d 100644 --- a/src/u_main.pas +++ b/src/u_main.pas @@ -14,7 +14,7 @@ uses u_widget, u_messages, u_interfaces, u_editor, u_projinspect, u_ceprojeditor, u_search, u_miniexplorer, u_libman, u_libmaneditor, u_todolist, u_observer, u_toolseditor, u_procinput, u_optionseditor, u_symlist, u_mru, u_processes, - u_infos, u_dubproject, u_dialogs, u_dubprojeditor, u_gdb, + u_infos, u_dubproject, u_dialogs, u_dubprojeditor, u_gdb, u_makeproject, u_dfmt, u_lcldragdrop, u_projgroup, u_projutils, u_stringrange, u_dexed_d, u_halstead, u_profileviewer, u_semver, u_dsgncontrols, u_term, u_newdubproj; @@ -409,6 +409,7 @@ type fFreeProj: ICommonProject; fProjBeforeGroup: ICommonProject; fDubProject: TDubProject; + fMakeProject: TMakeProject; fNativeProject: TNativeProject; fProjMru: TMRUProjectList; fFileMru: TMRUDocumentList; @@ -518,6 +519,7 @@ type procedure saveProjSource(const document: TDexedMemo); procedure newNativeProj; procedure newDubProj; + procedure newMakeProj; procedure saveProj; procedure saveProjAs(const fname: string); procedure openProj(const fname: string); @@ -1097,10 +1099,11 @@ begin mem := hdl.findDocument(dst.fProj.filename); if mem.isAssigned then begin - if dst.fProj.getFormat = pfDEXED then - mem.Highlighter := LfmSyn - else - mem.Highlighter := JsSyn; + case dst.fProj.getFormat of + pfDEXED : mem.Highlighter := LfmSyn; + pfDUB : mem.Highlighter := JsSyn; + pfMAKE : mem.Highlighter := TxtSyn; + end; end; end; @@ -2447,8 +2450,9 @@ procedure TMainForm.projNew(project: ICommonProject); begin fProj := project; case fProj.getFormat of - pfDEXED: fNativeProject := TNativeProject(fProj.getProject); - pfDUB: fDubProject := TDubProject(fProj.getProject); + pfDEXED : fNativeProject := TNativeProject(fProj.getProject); + pfDUB : fDubProject := TDubProject(fProj.getProject); + pfMAKE : fMakeProject := TMakeProject(fProj.getProject); end; if not fProj.inGroup then fFreeProj := project; @@ -2468,6 +2472,7 @@ begin fProj := nil; fDubProject := nil; fNativeProject := nil; + fMakeProject := nil; showProjTitle; end; @@ -2475,8 +2480,9 @@ procedure TMainForm.projFocused(project: ICommonProject); begin fProj := project; case fProj.getFormat of - pfDEXED: fNativeProject := TNativeProject(fProj.getProject); - pfDUB: fDubProject := TDubProject(fProj.getProject); + pfDEXED : fNativeProject := TNativeProject(fProj.getProject); + pfDUB : fDubProject := TDubProject(fProj.getProject); + pfMAKE : fMakeProject := TMakeProject(fProj.getProject); end; if not fProj.inGroup then fFreeProj := project @@ -2645,7 +2651,7 @@ end; procedure TMainForm.saveFile(document: TDexedMemo); begin - if (document.Highlighter = LfmSyn) or (document.Highlighter = JsSyn) then + if document.isProjectDescription then saveProjSource(document) else if document.fileName.fileExists then document.save; @@ -3834,6 +3840,7 @@ begin fProj := nil; fNativeProject := nil; fDubProject := nil; + fMakeProject := nil; showProjTitle; result := true; end; @@ -3892,6 +3899,13 @@ begin showProjTitle; end; +procedure TMainForm.newMakeProj; +begin + fMakeProject := TMakeProject.create(nil); + fProj := fMakeProject as ICommonProject; + showProjTitle; +end; + procedure TMainForm.saveProj; begin fProj.saveToFile(fProj.filename); @@ -3914,8 +3928,9 @@ begin newDubProj else if ext = '.DPRJ' then newNativeProj - else - begin + else if (fname.extractFileName.upperCase = 'MAKEFILE') or (ext = '.MAK') then + newMakeProj + else begin dlgOkError('Unknown project extension : ' + ext); exit; end; @@ -3967,7 +3982,7 @@ begin end; with TSaveDialog.Create(nil) do try - Filter := 'DUB json|*.json|DUB sdl|*.sdl|Dexed project|*.dprj'; + Filter := 'DUB json|*.json|DUB sdl|*.sdl|Dexed project|*.dprj|makefile|*.mak|any|*'; if fProj.filename.fileExists then InitialDir := fProj.filename.extractFileDir; if execute then @@ -4003,7 +4018,7 @@ begin exit; with TOpenDialog.Create(nil) do try - Filter := 'DUB json|*.json|DUB sdl|*.sdl|Dexed project|*.dprj'; + Filter := 'DUB json|*.json|DUB sdl|*.sdl|Dexed project|*.dprj|makefile|*.mak|any|*'; if execute then openProj(filename.normalizePath); finally @@ -4041,10 +4056,11 @@ begin openFile(fProj.filename); fDoc.isProjectDescription := true; - if fProj.getFormat = pfDEXED then - fDoc.Highlighter := LfmSyn - else - fDoc.Highlighter := JsSyn; + case fProj.getFormat of + pfDEXED : fDoc.Highlighter := LfmSyn; + pfDUB : fDoc.Highlighter := JsSyn; + pfMAKE : fDoc.Highlighter := TxtSyn; + end; end; procedure TMainForm.actProjOptViewExecute(Sender: TObject); diff --git a/src/u_makeproject.pas b/src/u_makeproject.pas new file mode 100644 index 00000000..9e4752a6 --- /dev/null +++ b/src/u_makeproject.pas @@ -0,0 +1,431 @@ +unit u_makeproject; + +{$I u_defines.inc} + +interface + +uses + Classes, SysUtils, fpjson, jsonparser, jsonscanner, process, strutils, + LazFileUtils, RegExpr, fgl, math, + u_common, u_interfaces, u_observer, u_dialogs, u_processes, + u_writableComponent, u_compilers, u_semver, u_stringrange; + +type + +TMakeProject = class(TComponent, ICommonProject) +private + + fProjectSubject: TProjectSubject; + fRules: TStringList; + fMsgs: IMessagesDisplay; + fMakeProc: TDexedProcess; + fAsProjectItf: ICommonProject; + fBasePath: string; + fFilename: string; + fCompiled: boolean; + fInGroup: boolean; + fRuleIndex: integer; + fSrcs: TStringList; + + procedure makeProcOutput(proc: TObject); + procedure makeProcTerminated(proc: TObject); + +public + + constructor create(aOwner: TComponent); override; + destructor destroy; override; + + // indicates if the project is owned by a group. + function inGroup: boolean; + // flag the project as grouped + procedure inGroup(value: boolean); + // in a context of a group, activates the project + procedure activate; + // indicates the project format + function getFormat: TProjectFormat; + // returns an object that can be cast using the result of getFormat() + function getProject: TObject; + // returns the project filename + function filename: string; + // loads project from filename + procedure loadFromFile(const fname: string); + // saves project to filename + procedure saveToFile(const fname: string); + // reloads + procedure reload; + // indicates if the project is modified + function modified: boolean; + // returns the base dir used to solve relative paths + function basePath: string; + // returns the name of the file that's produced + function outputFilename: string; + // returns the kind of binary produced + function binaryKind: TProjectBinaryKind; + // returns the command line used to compile the project + function getCommandLine: string; + // stops compilation + procedure stopCompilation; + +// configs ----------------------------------------------------------------- + + // returns the count of configuration (or config count * type count for pfDUB) + function configurationCount: integer; + // sets the active configuration + procedure setActiveConfigurationIndex(index: integer); + // returns the name of the nth configuration + function configurationName(index: integer): string; + // return the index of the active config + function getActiveConfigurationIndex: integer; + +// project sources --------------------------------------------------------- + + // returns the count of source files for the current config + function sourcesCount: integer; + // returns the source absolute filename. + function sourceAbsolute(index: integer): string; + // returns the source relative filename. + function sourceRelative(index: integer): string; + // returns true if aFilename is a project source. + function isSource(const aFilename: string): boolean; + // returns the count of import paths for the current config + function importsPathCount: integer; + // returns the import absolute path + function importPath(index: integer): string; + +// sub routines for the actions -------------------------------------------- + + // tries to compile. + procedure compile; + // + procedure checkSemantics; + // indicates wether last complation was successful. + function compiled: boolean; + // tries to execute the project output. + procedure run(const runArgs: string = ''); + // test the project (only for pfDUB) + procedure test; + // returns true if the target has not to be recompiled + function targetUpToDate: boolean; +end; + +implementation + +constructor TMakeProject.create(aOwner: TComponent); +begin + inherited create(aOwner); + fRules := TStringList.Create; + fSrcs := TStringList.Create; + fProjectSubject := TProjectSubject.Create; + fAsProjectItf := self as ICommonProject; + fMsgs := getMessageDisplay; + + subjProjNew(fProjectSubject, self); +end; + +destructor TMakeProject.destroy; +begin + killProcess(fMakeProc); + subjProjClosing(fProjectSubject, self); + fProjectSubject.free; + fRules.Free; + fSrcs.Free; + inherited; +end; + +function TMakeProject.inGroup: boolean; +begin + result := fInGroup; +end; + +procedure TMakeProject.inGroup(value: boolean); +begin + fInGroup := value; +end; + +procedure TMakeProject.activate; +begin + subjProjFocused(fProjectSubject, fAsProjectItf); +end; + +function TMakeProject.getFormat: TProjectFormat; +begin + result := pfMAKE; +end; + +function TMakeProject.getProject: TObject; +begin + result := self; +end; + +function TMakeProject.filename: string; +begin + result := fFilename; +end; + +procedure TMakeProject.loadFromFile(const fname: string); +var + lines: TStringList; + srcs: TStringList; + line0: string; + line1: string; + hidden: string = DirectorySeparator + '.'; + f: string; + colPos: integer; + i: integer; +begin + fRules.Clear; + fRules.add('default'); + fRuleIndex := 0; + + fFilename := fname; + if not FilenameIsAbsolute(fFilename) then + fFilename := ExpandFileName(fFilename); + fBasePath := fFilename.extractFilePath; + + lines := TStringList.Create; + try + lines.LoadFromFile(fFilename); + if lines.Count > 1 then + for i := 0 to lines.Count-2 do + begin + line0 := lines[i]; + line1 := lines[i+1]; + colPos:= pos(':', line0); + if line0.isBlank or line1.isBlank or (colPos < 2) then + continue; + if (line0.length > 1) and not (line0[1] in [' ', #9]) and + (line1.length > 1) and (line1[1] in [' ', #9]) and not (line1[2] in [' ', #9]) then + fRules.Add(line0[1..colPos-1]); + end; + finally + lines.Free; + end; + + fSrcs.Clear; + fSrcs.Sorted:=false; + srcs := TStringList.Create; + try + listFiles(srcs, fBasePath + 'src', true); + for f in srcs do + if pos(hidden, f) = 0 then + fSrcs.Add(f[fBasePath.length + 1 .. f.length]); + srcs.Clear; + + listFiles(srcs, fBasePath + 'include', true); + for f in srcs do + if pos(hidden, f) = 0 then + fSrcs.Add(f[fBasePath.length + 1 .. f.length]); + srcs.Clear; + + listFiles(srcs, fBasePath + 'import', true); + for f in srcs do + if pos(hidden, f) = 0 then + fSrcs.Add(f[fBasePath.length + 1 .. f.length]); + srcs.Clear; + + finally + srcs.Free; + end; + fSrcs.Sorted:=true; + + subjProjChanged(fProjectSubject, self); + +end; + +procedure TMakeProject.saveToFile(const fname: string); +begin +end; + +procedure TMakeProject.reload; +begin + if fFilename.fileExists then + loadFromFile(fFilename); +end; + +function TMakeProject.modified: boolean; +begin + result := false; +end; + +function TMakeProject.basePath: string; +begin + result := fBasePath; +end; + +function TMakeProject.outputFilename: string; +begin + result := ''; +end; + +function TMakeProject.binaryKind: TProjectBinaryKind; +begin + result := TProjectBinaryKind.unknown; +end; + +function TMakeProject.getCommandLine: string; +begin + result := 'make ' + '-f ' + fFilename; + if not fRuleIndex.equals(0) then + result += ' ' + fRules[fRuleIndex]; +end; + +procedure TMakeProject.stopCompilation; +begin + if fMakeProc.isAssigned and fMakeProc.Running then + fMakeProc.Terminate(1); +end; + +function TMakeProject.configurationCount: integer; +begin + result := fRules.Count; +end; + +procedure TMakeProject.setActiveConfigurationIndex(index: integer); +begin + if fRuleIndex = index then + exit; + fRuleIndex := min(fRules.Count - 1, index); + fRuleIndex := max(0, fRuleIndex); + subjProjChanged(fProjectSubject, fAsProjectItf); +end; + +function TMakeProject.configurationName(index: integer): string; +begin + result := fRules[index]; +end; + +function TMakeProject.getActiveConfigurationIndex: integer; +begin + result := fRuleIndex; +end; + +function TMakeProject.sourcesCount: integer; +begin + result := fSrcs.count; +end; + +function TMakeProject.sourceAbsolute(index: integer): string; +var + fname: string; +begin + fname := fSrcs[index]; + if FilenameIsAbsolute(fname) then + result := fname + else + result := expandFilenameEx(fBasePath, fname); +end; + +function TMakeProject.sourceRelative(index: integer): string; +begin + result := fSrcs[index]; +end; + +function TMakeProject.isSource(const aFilename: string): boolean; +var + str: string; +begin + str := fFilename.extractFileDir; + result := aFilename.StartsWith(str); +end; + +function TMakeProject.importsPathCount: integer; +begin + result := 0; +end; + +function TMakeProject.importPath(index: integer): string; +begin + result := ''; +end; + +procedure TMakeProject.makeProcOutput(proc: TObject); +var + lst: TStringList; + str: string; +begin + lst := TStringList.Create; + try + fMakeProc.getFullLines(lst); + fMsgs.beginMessageCall(); + for str in lst do + fMsgs.message(str, fAsProjectItf, amcProj, amkAuto); + fMsgs.endMessageCall(); + finally + lst.Free; + end; +end; + +procedure TMakeProject.makeProcTerminated(proc: TObject); +var + n: string; +begin + makeProcOutput(proc); + n := shortenPath(filename); + fCompiled := fMakeProc.ExitStatus = 0; + if fCompiled then + begin + fMsgs.message(n + ' has been successfully compiled', fAsProjectItf, amcProj, amkInf); + end + else + begin + fMsgs.message(n + ' has not been successfully compiled', fAsProjectItf, amcProj, amkWarn); + fMsgs.message(format('error: make has returned the status %s', + [prettyReturnStatus(fMakeProc)]), fAsProjectItf, amcProj, amkErr); + if fMakeProc.autoKilled then + fMsgs.message(format('the process was autokilled because the size of its output exceeded %d', + [fMakeProc.autoKillProcThreshold]), nil, amcProj, amkWarn); + end; + subjProjCompiled(fProjectSubject, fAsProjectItf, fCompiled); +end; + +procedure TMakeProject.compile; +begin + if fMakeProc.isAssigned and fMakeProc.Active then + begin + fMsgs.message('the project is already being processed by DUB', fAsProjectItf, amcProj, amkWarn); + exit; + end; + killProcess(fMakeProc); + fCompiled := false; + + fMsgs.clearByData(fAsProjectItf); + subjProjCompiling(fProjectSubject, fAsProjectItf); + + fMakeProc := TDexedProcess.create(nil); + fMakeProc.executable := 'make'; + fMakeProc.Parameters.AddStrings([ '-f', fFilename]); + if not fRuleIndex.equals(0) then + fMakeProc.Parameters.Add(fRules[fRuleIndex]); + fMakeProc.Options := fMakeProc.Options + [poStderrToOutPut, poUsePipes]; + fMakeProc.ShowWindow := swoHIDE; + fMakeProc.CurrentDirectory := fFilename.extractFilePath; + fMakeProc.XTermProgram:=consoleProgram; + fMakeProc.OnTerminate:= @makeProcTerminated; + fMakeProc.OnReadData:= @makeProcOutput; + fMakeProc.execute; +end; + +procedure TMakeProject.checkSemantics; +begin +end; + +function TMakeProject.compiled: boolean; +begin + result := fCompiled; +end; + +procedure TMakeProject.run(const runArgs: string = ''); +begin +end; + +procedure TMakeProject.test; +begin +end; + +function TMakeProject.targetUpToDate: boolean; +begin + result := false; +end; + +end. + diff --git a/src/u_projgroup.lfm b/src/u_projgroup.lfm index 0e46fd23..852c091e 100644 --- a/src/u_projgroup.lfm +++ b/src/u_projgroup.lfm @@ -106,6 +106,7 @@ inherited ProjectGroupWidget: TProjectGroupWidget end end inherited toolbar: TDexedToolBar + Height = 30 Width = 320 object BtnAddProj: TDexedToolButton[0] Left = 1 diff --git a/src/u_projgroup.pas b/src/u_projgroup.pas index d26c8773..844d091c 100644 --- a/src/u_projgroup.pas +++ b/src/u_projgroup.pas @@ -770,7 +770,7 @@ var prj: TProjectGroupItem; fmt: TProjectFormat; const - typeStr: array[TProjectFormat] of string = ('DEXED','DUB'); + typeStr: array[TProjectFormat] of string = ('DEXED','DUB','MAKE'); begin if fUpdating then exit; @@ -787,8 +787,9 @@ begin Data:= prj; fmt := prj.project.getFormat; case fmt of - pfDEXED: Caption := prj.fFilename.extractFileName; - pfDUB: Caption := TDubProject(prj.project.getProject).packageName; + pfDEXED : Caption := prj.fFilename.extractFileName; + pfDUB : Caption := TDubProject(prj.project.getProject).packageName; + pfMAKE : Caption := prj.fFilename.extractFileDir.extractFileName; end; SubItems.Add(typeStr[fmt]); SubItems.Add(asyncStr[prj.fAsyncMode]); diff --git a/src/u_projutils.pas b/src/u_projutils.pas index b5db3c91..f05e8a6c 100644 --- a/src/u_projutils.pas +++ b/src/u_projutils.pas @@ -9,7 +9,7 @@ uses u_dlang, u_stringrange; type - TProjectFileFormat = (pffNone, pffDexed, pffDub); + TProjectFileFormat = (pffNone, pffDexed, pffDub, pffMake); TLexNameCallback = class private @@ -49,7 +49,7 @@ function projectSourcePath(project: ICommonProject): string; implementation uses - u_ceproject, u_dubproject; + u_ceproject, u_dubproject, u_makeproject; var clbck: TLexNameCallback; @@ -79,15 +79,19 @@ begin result := pffDub; end else if (ext = '.DPRJ') and isValidNativeProject(filename) then - result := pffDexed; + result := pffDexed + else if (ext = '.MAK') or (filename.extractFileName.upperCase = 'MAKEFILE')then + result := pffMake; end; function loadProject(const filename: string; discret: boolean): ICommonProject; var isDubProject: boolean = false; isCeProject: boolean = false; + isMkProject: boolean = true; dubProj: TDubProject; ceProj: TNativeProject; + mkProj: TMakeProject; begin result := nil; if not filename.fileExists then @@ -97,9 +101,11 @@ begin if isValidDubProject(filename) then isDubProject := true else if isValidNativeProject(filename) then - isCeProject := true; + isCeProject := true + else if (filename.extractFileName.upperCase = 'MAKEFILE') or (filename.extractFileExt.upperCase = '.MAK') then + isMkProject := true; EntitiesConnector.endUpdate; - if not isDubProject and not isCeProject then + if not isDubProject and not isCeProject and not isMkProject then exit; if discret then @@ -110,10 +116,16 @@ begin dubproj.loadFromFile(filename); result := dubProj as ICommonProject; end - else begin + else if isDubProject then begin ceProj := TNativeProject.create(nil); ceProj.loadFromFile(filename); result := ceProj as ICommonProject; + end + else + begin + mkProj := TMakeProject.create(nil); + mkProj.loadFromFile(filename); + result := mkProj as ICommonProject; end; if discret then EntitiesConnector.endUpdate;