root/trunk/Projects.pas

Revision 18, 12.7 kB (checked in by DavidM, 7 years ago)

Beta 8

Line 
1 unit Projects;
2
3 interface
4
5 uses classes, Menus, SourceFiles, SimpleXML;
6
7 { Common configurable project info }
8 type
9     TProjectCfg = class
10        optimize     : boolean ;   { -O }
11        inlineFn     : boolean ;   { -inline }
12        debugVersion : boolean;    { -debug }
13        debugSymbols : boolean;    { -g }
14        profileHooks : boolean;    { -gt }
15        unittests    : boolean;    { -unittest }
16        releaseVersion : boolean ; { -release }
17
18        linkerFlags  : TStringList;  { -L... }
19        versions     : TStringList;  { -version=... }
20        versionNumber : string;
21
22        constructor Create;
23        destructor  Free;
24        function  ToXml : Node;
25        procedure FromXML( xml : Node );
26        procedure  CopyTo( other : TProjectCfg );
27      end;
28
29 { Main Project class }    
30 type    
31     TProject = class
32       parent      : TObject;      { workspace attached to }
33       config      : TProjectCfg;  { configuration }
34       name        : string;       { title for the project }
35       destfilename : string ;     { destination filename }
36
37       filename    : string;       { path to project file project.prx) }
38       fullbuild   : boolean ;     { Compile all files each Build }
39       enabled     : TStringList;  { enabled versions for build }
40       saved       : boolean ;
41
42       basepath    : string;       { root path of project, defaults to project path }
43       outPath     : string ;      { object file/exe/lib destination -od<dir> }
44       importPaths : TStringList;  { -I... }     
45       sources     : TSourceFiles; { list of TSourceFile objects}
46
47       constructor  Create;
48       destructor   Free;
49       procedure    Save;
50       procedure    SaveAs( fname : string );
51
52
53       { Returns true if the version(specified by index) is active }
54       function  CheckVersion( N:Integer) : boolean  ;
55
56       function   ExeName : string;
57       function   LibName : string;
58
59       { Adds a file to the project }             
60       procedure Add( fname : string );
61
62       { Enables and disables versions }
63       procedure EnableVersion( N : Integer );
64       procedure DisableVersion( N : Integer );
65
66       { Attempts to find a file, given only its name }
67       function FindFilePath( name : string ) : string ;
68
69       { returns the compile options for this project }
70       function CompileOptions : string ;
71
72       { returns link options for this project }
73       function LinkOptions : string;
74
75       { returns the resulting file of compiling the file passed }
76       function GetResultFile( fn : string ) : string;
77
78       { stores all the object files for this project in list }
79       function GetObjectFiles( list : TStringList ) : Integer;
80     end;
81
82
83     { Loads a project from a file, returns nil if failure }
84     function LoadProject( filename : string ) :TProject;
85
86 const
87    FileVersion = '002';
88
89 implementation
90
91 uses SysUtils, Workspaces, MyUtils, FileCtrl, Windows;
92
93
94
95 function  TProject.ExeName : string;
96 begin
97   result := Path( basepath, destfilename + '.exe' );
98 end;
99
100
101 function  TProject.LibName : string;
102 begin
103   result := Path( basepath, destfilename + '.lib' );
104 end;
105
106
107 function TProject.CheckVersion( N : Integer ) : boolean;
108 var
109   I : Integer;
110 begin
111   Result := false;
112   if N>= config.versions.Count then Exit;
113   I := enabled.IndexOf( config.versions[N] );
114   result := ( I>=0 );
115 end;
116
117 procedure TProject.EnableVersion( N : Integer );
118 begin
119   if N>=config.versions.Count then Exit;
120   enabled.Add( config.versions[N] );
121 end;
122
123
124 procedure TProject.DisableVersion( N : Integer );
125 var
126   I : Integer;
127 begin
128   if N>=config.versions.Count then Exit;
129   I := enabled.IndexOf( config.versions[N] );
130   if I>=0 then enabled.Delete( I );
131 end;
132
133
134
135 procedure TProject.Add( fname : string );
136 begin
137   sources.Add( fname );
138 end;
139
140
141 function LoadProject( filename : string ) :TProject;
142 var
143   xml, tmp  : Node;
144   proj   : TProject;
145   str,dir : string;
146   N : Integer;
147 begin
148   Result := nil;
149   if not  FileExists( filename ) then Exit;
150
151   xml := LoadXML( filename );
152   if Not Assigned( xml ) then Exit;
153
154   proj := TProject.Create;
155   proj.filename := filename;
156   dir := ExtractFilePath( filename );
157
158   tmp := xml.FindNode( 'ProjectConfig' );
159   if Assigned( tmp ) then
160   begin
161     proj.config.FromXML( tmp );
162   end;
163
164   proj.name:= xml.FindText( 'Name' );
165   proj.destfilename := xml.FindText( 'DestFileName' );
166
167   tmp := xml.FindNode( 'BasePath' );
168   if not Assigned(tmp ) then proj.basepath := dir
169   else proj.basePath:= FullPath( dir, tmp.data );
170  
171   proj.outPath := xml.FindText('OutputPath' );
172   proj.outPath := FullPath( dir, proj.outPath );
173  
174   str:= xml.FindText('FullBuild' );
175   proj.fullbuild := LowerCase(str) = 'true';
176
177   tmp:= xml.FindNode( 'ProjectFiles' );
178   if Assigned(tmp) then proj.sources.FromXml( tmp, dir );
179
180   tmp := xml.FindNode( 'ImportPaths' );
181   if Assigned(tmp) then
182     for N:=0 to tmp.Count-1 do proj.importPaths.Add( FullPath( dir, tmp[N].data ) );
183
184   tmp:= xml.FindNode( 'Enabled' );
185   if Assigned( tmp ) then
186     for N:=0 to tmp.Count-1 do proj.enabled.Add( tmp[N].data );
187
188   xml.Free;
189   Result := proj;
190 end;
191
192
193 procedure TProject.Save;
194 begin
195   SaveAs( Self.filename );
196 end;
197
198 procedure TProject.SaveAs( fname : string );
199 var
200   xml, tmp : Node;
201   N : Integer;
202   base : string; // directory of project file
203 begin
204   filename:= fname;
205   base := ExtractFilePath( fname );
206   SetCurrentDir( base );
207   xml := Node.Create( 'Project' );
208   xml.Add( 'Name', Self.name );
209   xml.Add( 'DestFileName',  destfilename );
210
211   if self.basepath <> base then  xml.Add( 'BasePath', RelativePath( base, basepath ) );
212   xml.Add( 'OutputPath', RelativePath( base, outPath ) );
213   xml.AddBool( 'FullBuild', fullbuild );
214   tmp := xml.Add( 'Enabled' );
215   for N:=0 to enabled.Count -1 do
216         tmp.Add( 'Version', enabled[N] );
217
218   tmp := xml.Add( 'ImportPaths' );
219   for N:=0 to importPaths.Count-1 do
220         tmp.Add( 'Path', RelativePath( base, importPaths[N] ));
221
222   xml.AddChild( config.ToXml );
223   xml.AddChild( sources.ToXml( base ) );
224   SaveXML( xml, fname );
225   xml.Free;
226   saved:= true;
227 end;
228
229
230 constructor TProject.Create;
231 begin
232   name := '';
233   filename := '';
234   destfilename := ''; 
235   saved := false;
236   basepath := '';
237   outPath := '';
238   config := TProjectCfg.Create;
239   importPaths := TStringList.Create;
240   sources := TSourceFiles.Create( Self );
241   enabled := TStringList.Create;
242 end;
243
244
245 destructor TProject.Free;
246 begin
247   config.Free;
248   sources.Free;
249   enabled.Free;
250   importPaths.Free;
251 end;
252
253
254
255 function TProject.GetResultFile( fn : string ) : string;
256 var
257   dir, name, ext : string;
258 begin
259   Result:= '';
260   if (not FileExists( fn )) and FileExists( self.basepath + fn )
261   then fn := basepath + fn;
262
263   if not FileExists( fn ) then Exit;
264
265   dir := ExtractFilePath( fn );
266   name := ExtractFileName( fn );
267   if Pos( ' ', dir )>0 then dir := ExtractShortPathName( dir );
268   ext := Lowercase(ExtractFileExt( fn ));
269
270   if ext <> '.d' then Exit ; { unknown result file }
271
272   if not Empty( Self.outPath ) then dir:= self.outPath ;
273   name := ChangeFileExt( name, '.obj' );
274   result := Path(dir , name );
275 end;
276
277
278
279 function TProject.LinkOptions : string;
280 var
281   files : TStringList;
282   options : TStringList;
283
284   N : LongInt;
285 begin
286   files := TStringList.Create;
287   files.Duplicates := dupIgnore ;
288   GetObjectFiles( files );
289   files.AddStrings( sources.objfiles );
290   files.AddStrings( sources.libfiles );
291
292   MyUtils.GetShortNames( files );
293
294   options := TStringList.Create; 
295   if not Empty( destfilename ) then options.Add( '-of' + destfilename )
296   else options.Add( '-of' + Self.name );
297
298   with config do begin
299     if profileHooks then options.Add( '-gt' );
300     if debugSymbols then options.Add( '-g' );
301     if releaseVersion then options.Add( '-release' );
302   end;
303
304   with config do
305   if LinkerFlags.Count > 0 then
306   begin
307     for N:=0 to LinkerFlags.Count-1 do
308         if Pos( '.lib', LowerCase(LinkerFlags[N]) )>0 then
309            options.Add( linkerflags[N] )
310         else options.Add( '-L' + config.linkerFlags[N] );
311   end;
312   Result:= Join( files, ' ' ) + ' ' + Join( options, ' ' );
313 end;
314
315 {Build up a command line string for compiling }
316 function TProject.CompileOptions: string;
317 var
318   cmd : TStringList;
319   temp : TStringList;
320   ws : TWorkspace;
321   N : Integer;
322   vsn : LongInt;
323 begin
324   ws := TWorkspace(Self.Parent);
325   cmd := TStringList.Create;
326
327   with config do
328   begin
329     if optimize then cmd.Add( '-O' );
330     if inlineFn then cmd.Add( '-inline' );
331     if debugVersion then cmd.Add( '-debug' );
332     if debugSymbols then cmd.Add( '-g' );
333     if profileHooks then cmd.Add( '-gt' );
334     if unittests then cmd.Add( '-unittest' );
335     if ParseInt( versionNumber, vsn ) then  cmd.Add( '-version=' + versionNumber );
336   end;
337
338   for N:=0 to self.enabled.Count-1 do
339   begin
340     if config.versions.IndexOf( enabled[N] ) >=0 then cmd.add( '-version=' + enabled[N] );
341   end;
342
343   temp := TStringList.Create;
344   temp.Duplicates := dupIgnore;
345   temp.Add( self.basepath );
346   temp.AddStrings( importPaths );
347   temp.AddStrings( ws.config.paths );
348
349   MyUtils.GetShortPaths( temp );
350   cmd.Add( '-I' + Join( temp, ';' ) );
351   Result:= Join( cmd, ' ' );
352   result:= result + Format( ' -od%s' , [self.outPath]);
353 end;
354
355
356 function TProject.GetObjectFiles( list : TStringList ) : Integer;
357 var
358   N, Count: Integer;
359   str : string;
360 begin
361   Count:= 0;
362   with sources do
363   for N:= 0 to dfiles.Count-1 do begin
364     str := GetResultFile( dfiles[N] );
365     if Length( str ) > 0 then begin
366       list.Add( str );
367       Inc( count );
368     end
369   end;
370   result:= Count;
371 end;
372
373
374 function SearchPaths( pathlist : TStringList ; name : string ) : string;
375 var
376   path : string;
377   N: Integer;
378 begin
379   for N:=0 to pathlist.Count-1 do begin
380     path := pathlist[N];
381     if FileExists( path + name ) then begin
382       Result:= path;
383       Exit;
384     end;
385   end;
386   Result := '';
387 end;
388
389
390 function TProject.FindFilePath( name : string ) : string ;
391 var
392   ws : TWorkspace;
393 begin
394   Result :=  SearchPaths( importPaths , name );
395   if Length( Result ) > 0 then Exit;
396   if not Assigned( Self.parent ) then Exit;
397   ws := TWorkspace(Self.parent);
398   Result :=  SearchPaths( ws.config.paths , name );
399   Exit;
400 end;
401
402
403
404 constructor TProjectCfg.Create;
405 begin
406   optimize := false;
407   inlineFn := false;
408   debugVersion := false;
409   debugSymbols := false;
410   profileHooks := false;
411   unittests    := false;
412
413
414   versions := TStringList.Create;
415   linkerFlags := TStringList.Create;
416 end;
417
418
419 destructor TProjectCfg.Free;
420 begin
421   versions.Free;
422   linkerFlags.Free;
423 end;
424
425 procedure TProjectCfg.CopyTo( other : TProjectCfg );
426 begin
427   other.optimize := optimize;
428   other.inlineFn := inlineFn;
429   other.debugVersion := debugVersion;
430   other.debugSymbols := debugSymbols;
431   other.profileHooks := profileHooks;
432   other.unittests := unittests;
433   other.linkerFlags.Clear;
434   other.linkerFlags.AddStrings( linkerFlags );
435   other.versions.Clear;
436   other.versions.AddStrings( versions );
437   other.versionNumber := versionNumber;
438   other.releaseVersion := releaseVersion;
439 end;
440
441
442
443
444
445 function TProjectCfg.ToXML : Node;
446 var
447   cfg, tmp  : Node;
448   N : Integer;
449 begin
450   cfg := Node.Create( 'ProjectConfig' );
451   cfg.AddBool( 'Optimize', optimize );
452   cfg.AddBool( 'InlineFunctions', inlineFn );
453   cfg.AddBool( 'DebugVersion', debugVersion );
454   cfg.AddBool( 'DebugSymbols', debugSymbols );
455   cfg.AddBool( 'ProfileHooks', profileHooks );
456   cfg.AddBool( 'UnitTests', unittests );
457   cfg.AddBool( 'ReleaseVersion', releaseVersion );
458   cfg.Add( 'VersionNumber', versionNumber );
459   tmp:=cfg.Add( 'Versions' );
460   for N:=0 to versions.Count-1 do tmp.Add('Version', versions[n] );
461
462   tmp := cfg.Add( 'LinkOptions' );
463   for N:=0 to linkerFlags.Count-1 do tmp.Add( 'Option', linkerFlags[N] );
464   result:= cfg;
465
466 end;
467
468
469 procedure TProjectCfg.FromXml( xml : Node );
470 var
471   tmp : Node;
472   N : Integer;
473 begin
474   optimize := xml.FindText( 'Optimize' ) = 'true';
475   inlineFn := xml.FindText( 'InlineFunctions' ) = 'true';
476   debugVersion := xml.FindText( 'DebugVersion' ) = 'true';
477   debugSymbols := xml.FindText( 'DebugSymbols' ) = 'true';
478   profileHooks := xml.FindText( 'ProfileHooks' ) = 'true';
479   unittests := xml.FindText( 'UnitTests' ) = 'true';
480   releaseVersion := xml.FindText( 'ReleaseVersion' ) = 'true';
481   versionNumber := xml.FindText( 'VersionNumber' );
482
483   tmp:= xml.FindNode( 'Versions' );
484   if Assigned(tmp) then
485   begin
486     for N:= 0 to tmp.Count-1 do versions.Add( tmp[N].data );
487   end;
488   //reader.ReadStrings( importPaths );
489   tmp:= xml.FindNode( 'LinkOptions' );
490   if Assigned(tmp) then
491   begin
492     for N:= 0 to tmp.Count-1 do linkerFlags.Add( tmp[N].data );
493   end;
494
495 end;
496
497 end.
Note: See TracBrowser for help on using the browser.