1 /*
2 * This file is part of the FortranProject plugin for Code::Blocks IDE
3 * and licensed under the GNU General Public License, version 3
4 * http://www.gnu.org/licenses/gpl-3.0.html
5 *
6 * Author: Darius Markauskas
7 *
8 */
9
10 #include "projectdependencies.h"
11
12 #include <sdk.h>
13 #ifndef CB_PRECOMP
14 #include <wx/dir.h>
15 #include <wx/filefn.h>
16
17 #include <compiler.h>
18 #include <compilerfactory.h>
19 #include <logmanager.h>
20 #include <macrosmanager.h>
21 #include <projectmanager.h>
22 #endif
23
24 #include "nativeparserf.h"
25
26
ProjectDependencies(cbProject * project)27 ProjectDependencies::ProjectDependencies(cbProject* project)
28 {
29 m_Project = project;
30 //ctor
31 }
32
~ProjectDependencies()33 ProjectDependencies::~ProjectDependencies()
34 {
35 //dtor
36 Clear();
37 }
38
Clear()39 void ProjectDependencies::Clear()
40 {
41 m_prFilesArr.clear();
42 m_FileIndexMap.clear();
43 for (size_t i=0; i<m_pUseModules.size(); i++)
44 {
45 delete m_pUseModules[i];
46 }
47 m_pUseModules.clear();
48 for (size_t i=0; i<m_pDeclaredModules.size(); i++)
49 {
50 delete m_pDeclaredModules[i];
51 }
52 m_pDeclaredModules.clear();
53 for (size_t i=0; i<m_pExtendsSModules.size(); i++)
54 {
55 delete m_pExtendsSModules[i];
56 }
57 m_pExtendsSModules.clear();
58 for (size_t i=0; i<m_pDeclaredSubmodules.size(); i++)
59 {
60 delete m_pDeclaredSubmodules[i];
61 }
62 m_pDeclaredSubmodules.clear();
63
64 for (size_t i=0; i<m_pIncludes.size(); i++)
65 {
66 delete m_pIncludes[i];
67 }
68 m_pIncludes.clear();
69
70 m_ModuleFileIdxMap.clear();
71 m_SubmoduleFileIdxMap.clear();
72 m_IncludeFileIdxMap.clear();
73
74 for (size_t i=0; i<m_ChildrenTable.size(); i++)
75 {
76 delete m_ChildrenTable[i];
77 }
78 m_ChildrenTable.clear();
79 m_WasInfiniteLoop = false;
80 m_FileWeights.Empty();
81
82 m_MadeChildrenSet.clear();
83 }
84
MakeProjectFilesDependencies(ProjectFilesArray & prFilesArr,ParserF & parser)85 void ProjectDependencies::MakeProjectFilesDependencies(ProjectFilesArray& prFilesArr, ParserF& parser)
86 {
87 Clear();
88
89 m_prFilesArr = prFilesArr;
90 wxArrayString fnames;
91
92 size_t nfil = m_prFilesArr.size();
93 for (size_t i = 0; i < nfil; ++i)
94 {
95 ProjectFile* pf = m_prFilesArr[i];
96 wxString ffp = pf->file.GetFullPath();
97 m_FileIndexMap.insert(std::make_pair(ffp,i));
98
99 wxString fname = pf->file.GetName() + _T(".") + pf->file.GetExt();
100 fnames.Add(fname);
101 }
102
103 for (size_t i = 0; i < nfil; ++i)
104 {
105 StringSet* fileUseModules = new StringSet;
106 StringSet* fileDeclaredModules = new StringSet;
107 StringSet* fileExtendsSModules = new StringSet;
108 StringSet* fileDeclaredSubmodules = new StringSet;
109 StringSet* fileIncludes = new StringSet;
110
111 parser.ObtainUsedDeclaredModules(m_prFilesArr[i]->file.GetFullPath(), fileUseModules, fileDeclaredModules,
112 fileExtendsSModules, fileDeclaredSubmodules, fileIncludes);
113 m_pUseModules.push_back(fileUseModules);
114 m_pDeclaredModules.push_back(fileDeclaredModules);
115 m_pExtendsSModules.push_back(fileExtendsSModules);
116 m_pDeclaredSubmodules.push_back(fileDeclaredSubmodules);
117 m_pIncludes.push_back(fileIncludes);
118
119 StringSet::iterator pos;
120 for (pos = fileDeclaredModules->begin(); pos != fileDeclaredModules->end(); ++pos)
121 {
122 if (!m_ModuleFileIdxMap.count(*pos))
123 m_ModuleFileIdxMap[*pos] = i;
124 }
125
126 for (pos = fileDeclaredSubmodules->begin(); pos != fileDeclaredSubmodules->end(); ++pos)
127 {
128 if (!m_SubmoduleFileIdxMap.count(*pos))
129 m_SubmoduleFileIdxMap[*pos] = i;
130 }
131
132 for (pos = fileIncludes->begin(); pos != fileIncludes->end(); ++pos)
133 {
134 wxString inc = *pos;
135 for (size_t j=0; j < nfil; ++j)
136 {
137 wxString fn = fnames.Item(j);
138 if (inc.IsSameAs(fn) || inc.IsSameAs(fn.BeforeLast('.')))
139 {
140 m_IncludeFileIdxMap[*pos] = j;
141 break;
142 }
143 }
144 }
145 }
146
147 m_MadeChildrenSet.resize(nfil,false);
148 m_ChildrenTable.resize(nfil);
149
150 for (size_t i = 0; i < nfil; ++i)
151 {
152 if (m_MadeChildrenSet[i] == false)
153 {
154 IntSet* children = new IntSet;
155 m_Deep = 0;
156 m_BreakChain = false;
157 MakeFileChildren(children, i);
158 m_ChildrenTable[i] = children;
159 }
160 }
161
162 //PrintChildrenTable();
163
164 m_FileWeights.Alloc(nfil);
165 m_FileWeights.Add(-1,nfil);
166 }
167
168
HasInfiniteDependences()169 bool ProjectDependencies::HasInfiniteDependences()
170 {
171 return m_WasInfiniteLoop;
172 }
173
174
GetFileWeight(wxString & fileName)175 unsigned short int ProjectDependencies::GetFileWeight(wxString& fileName)
176 {
177 if (!m_FileIndexMap.count(fileName))
178 return 50; //error. default value
179
180 m_Deep = 0;
181 m_BreakChain = false;
182 unsigned short int wt = GetFileWeightByIndex(m_FileIndexMap[fileName]);
183 return wt;
184 }
185
186
GetFileWeightByIndex(size_t idx)187 unsigned short int ProjectDependencies::GetFileWeightByIndex(size_t idx)
188 {
189 if (m_FileWeights[idx] != -1)
190 return m_FileWeights[idx];
191 if (m_Deep > 99)
192 {
193 m_WasInfiniteLoop = true;
194 m_BreakChain = true;
195 return 0;
196 }
197 else if (m_BreakChain)
198 {
199 return 0;
200 }
201 unsigned short int wt;
202 unsigned short int wt_max = 0;
203 StringSet* fileUseModules = m_pUseModules[idx];
204 StringSet::iterator pos;
205 for (pos = fileUseModules->begin(); pos != fileUseModules->end(); ++pos)
206 {
207 if (m_ModuleFileIdxMap.count(*pos) != 1)
208 {
209 continue;
210 }
211 else
212 {
213 size_t fidx = m_ModuleFileIdxMap[*pos];
214 if (fidx == idx)
215 continue; // module defined and is used in the same file.
216 m_Deep++;
217 wt = 1 + GetFileWeightByIndex(fidx);
218 m_Deep--;
219
220 if (wt > wt_max)
221 wt_max = wt;
222 }
223 }
224
225 StringSet* fileExtendsSModules = m_pExtendsSModules[idx];
226 for (pos = fileExtendsSModules->begin(); pos != fileExtendsSModules->end(); ++pos)
227 {
228 size_t fidx;
229 bool found = false;
230 if (m_ModuleFileIdxMap.count(*pos) == 1)
231 {
232 fidx = m_ModuleFileIdxMap[*pos];
233 found = true;
234 }
235 else if (m_SubmoduleFileIdxMap.count(*pos) == 1)
236 {
237 fidx = m_SubmoduleFileIdxMap[*pos];
238 found = true;
239 }
240
241 if (!found)
242 continue;
243 else
244 {
245 if (fidx == idx)
246 continue; // module defined and is used in the same file.
247 m_Deep++;
248 wt = 1 + GetFileWeightByIndex(fidx);
249 m_Deep--;
250
251 if (wt > wt_max)
252 wt_max = wt;
253 }
254 }
255
256 StringSet* fileIncludes = m_pIncludes[idx];
257 for (pos = fileIncludes->begin(); pos != fileIncludes->end(); ++pos)
258 {
259 if (m_IncludeFileIdxMap.count(*pos) != 1)
260 {
261 continue;
262 }
263 else
264 {
265 size_t fidx = m_IncludeFileIdxMap[*pos];
266 if (fidx == idx)
267 continue; // error, includes self
268 m_Deep++;
269 wt = 1 + GetFileWeightByIndex(fidx);
270 m_Deep--;
271
272 if (wt > wt_max)
273 wt_max = wt;
274 }
275 }
276 m_FileWeights[idx] = wt_max;
277 return wt_max;
278 }
279
MakeFileChildren(IntSet * children,size_t fileIndex)280 void ProjectDependencies::MakeFileChildren(IntSet* children, size_t fileIndex)
281 {
282 if (m_Deep > 99)
283 {
284 m_BreakChain = true;
285 return; // maybe infinite reference loop?
286 }
287 else if (m_BreakChain)
288 {
289 return;
290 }
291
292 StringSet* fileDeclaredModules = m_pDeclaredModules[fileIndex];
293 StringSet::iterator pos;
294 for (pos = fileDeclaredModules->begin(); pos != fileDeclaredModules->end(); ++pos)
295 {
296 wxString modName = *pos;
297 size_t nUseModules = m_pUseModules.size();
298 for (size_t k=0; k < nUseModules; ++k)
299 {
300 if (fileIndex==k)
301 continue; // declared and used in the same file
302
303 if (m_pUseModules[k]->count(modName))
304 {
305 children->insert(k);
306
307 if (m_MadeChildrenSet[k] == true)
308 {
309 children->insert(m_ChildrenTable[k]->begin(),m_ChildrenTable[k]->end());
310 }
311 else
312 {
313 IntSet* childrenNew = new IntSet;
314 m_Deep++;
315 MakeFileChildren(childrenNew, k);
316 m_Deep--;
317 children->insert(childrenNew->begin(),childrenNew->end());
318 m_ChildrenTable[k] = childrenNew;
319 m_MadeChildrenSet[k] = true;
320 }
321 }
322 }
323
324 size_t nExtendsSMod = m_pExtendsSModules.size();
325 for (size_t k=0; k < nExtendsSMod; ++k)
326 {
327 if (fileIndex==k)
328 continue; // declared and used in the same file
329
330 if (m_pExtendsSModules[k]->count(modName))
331 {
332 children->insert(k);
333
334 if (m_MadeChildrenSet[k] == true)
335 {
336 children->insert(m_ChildrenTable[k]->begin(),m_ChildrenTable[k]->end());
337 }
338 else
339 {
340 IntSet* childrenNew = new IntSet;
341 m_Deep++;
342 MakeFileChildren(childrenNew, k);
343 m_Deep--;
344 children->insert(childrenNew->begin(),childrenNew->end());
345 m_ChildrenTable[k] = childrenNew;
346 m_MadeChildrenSet[k] = true;
347 }
348 }
349 }
350 }
351
352 StringSet* fileDeclaredSubmodules = m_pDeclaredSubmodules[fileIndex];
353 for (pos = fileDeclaredSubmodules->begin(); pos != fileDeclaredSubmodules->end(); ++pos)
354 {
355 wxString submodName = *pos;
356 size_t nExtendsSMod = m_pExtendsSModules.size();
357 for (size_t k=0; k < nExtendsSMod; ++k)
358 {
359 if (fileIndex==k)
360 continue; // declared and used in the same file
361
362 if (m_pExtendsSModules[k]->count(submodName))
363 {
364 children->insert(k);
365
366 if (m_MadeChildrenSet[k] == true)
367 {
368 children->insert(m_ChildrenTable[k]->begin(),m_ChildrenTable[k]->end());
369 }
370 else
371 {
372 IntSet* childrenNew = new IntSet;
373 m_Deep++;
374 MakeFileChildren(childrenNew, k);
375 m_Deep--;
376 children->insert(childrenNew->begin(),childrenNew->end());
377 m_ChildrenTable[k] = childrenNew;
378 m_MadeChildrenSet[k] = true;
379 }
380 }
381 }
382 }
383
384 ProjectFile* pf = m_prFilesArr[fileIndex];
385 wxString fname = pf->file.GetName();
386 wxString fnameExt = fname + _T(".") + pf->file.GetExt();
387 size_t nIncludes = m_pIncludes.size();
388 for (size_t k=0; k < nIncludes; ++k)
389 {
390 if (fileIndex==k)
391 continue;
392
393 if (m_pIncludes[k]->count(fname) || m_pIncludes[k]->count(fnameExt))
394 {
395 children->insert(k);
396
397 if (m_MadeChildrenSet[k] == true)
398 {
399 children->insert(m_ChildrenTable[k]->begin(),m_ChildrenTable[k]->end());
400 }
401 else
402 {
403 IntSet* childrenNew = new IntSet;
404 m_Deep++;
405 MakeFileChildren(childrenNew, k);
406 m_Deep--;
407 children->insert(childrenNew->begin(),childrenNew->end());
408 m_ChildrenTable[k] = childrenNew;
409 m_MadeChildrenSet[k] = true;
410 }
411 }
412 }
413 }
414
EnsureUpToDateObjs()415 void ProjectDependencies::EnsureUpToDateObjs()
416 {
417 size_t nfile = m_prFilesArr.size();
418 for (size_t j=0; j<nfile; ++j)
419 {
420 ProjectFile* pf = m_prFilesArr[j];
421 const wxArrayString& btarr = pf->GetBuildTargets();
422 if (btarr.IsEmpty())
423 continue;
424 ProjectBuildTarget* bTarget = m_Project->GetBuildTarget(btarr[0]);
425 const pfDetails& pfd = pf->GetFileDetails(bTarget);
426 time_t time_src = wxFileModificationTime(pfd.source_file_absolute_native);
427
428 IntSet* children = m_ChildrenTable[j];
429 IntSet::iterator pos;
430 for (pos=children->begin(); pos != children->end(); ++pos)
431 {
432 ProjectFile* pfChild = m_prFilesArr[*pos];
433
434 const wxArrayString& btChild_arr = pfChild->GetBuildTargets();
435 size_t nChTag = btChild_arr.size();
436 for (size_t iCh=0; iCh < nChTag; ++iCh)
437 {
438 ProjectBuildTarget* bTargetChild = m_Project->GetBuildTarget(btChild_arr[iCh]);
439 Compiler* compilerChild = CompilerFactory::GetCompiler(bTargetChild->GetCompilerID());
440 if(!compilerChild)
441 continue;
442
443 const pfDetails& pfdChild = pfChild->GetFileDetails(bTargetChild);
444 wxString objectAbsChild = (compilerChild->GetSwitches().UseFlatObjects)?
445 pfdChild.object_file_flat_absolute_native : pfdChild.object_file_absolute_native;
446
447 if (wxFileExists(objectAbsChild))
448 {
449 time_t time_obj = wxFileModificationTime(objectAbsChild);
450 if (time_src > time_obj)
451 {
452 wxRemoveFile(objectAbsChild);
453 }
454 }
455 }
456 }
457 }
458 }
459
RemoveModFiles(cbProject * pr,ProjectBuildTarget * bTarget,NativeParserF * nativeParser)460 void ProjectDependencies::RemoveModFiles(cbProject* pr, ProjectBuildTarget* bTarget, NativeParserF* nativeParser)
461 {
462 //Remove all *.mod files
463 if (!pr || !bTarget || pr->IsMakefileCustom())
464 return;
465
466 wxString comID = bTarget->GetCompilerID();
467 if (!CompilerFactory::CompilerInheritsFrom(comID, _T("gfortran")) &&
468 !CompilerFactory::CompilerInheritsFrom(comID, _T("g95")) &&
469 !CompilerFactory::CompilerInheritsFrom(comID, _T("ifcwin")) &&
470 !CompilerFactory::CompilerInheritsFrom(comID, _T("ifclin")) &&
471 !CompilerFactory::CompilerInheritsFrom(comID, _T("pgfortran")) &&
472 !CompilerFactory::CompilerInheritsFrom(comID, _T("oracfortran")) )
473 {
474 bool haveFortran = false;
475 for (FilesList::iterator it = pr->GetFilesList().begin(); it != pr->GetFilesList().end(); ++it)
476 {
477 ProjectFile* prjfile = *it;
478 if (nativeParser->IsFileFortran(prjfile->file.GetFullPath()))
479 {
480 haveFortran = true;
481 break;
482 }
483 }
484 if (!haveFortran)
485 return;
486 }
487
488 wxString objDir = bTarget->GetBasePath() + bTarget->GetObjectOutput();
489 wxDir odir;
490 if (odir.Open(objDir))
491 {
492 wxString filename;
493 wxFileName fname;
494 fname.AssignDir(objDir);
495 wxString filespec = _T("*.mod");
496 bool cont = odir.GetFirst(&filename, filespec, wxDIR_FILES);
497 while (cont)
498 {
499 fname.SetFullName(filename);
500 wxRemoveFile(fname.GetFullPath());
501 cont = odir.GetNext(&filename);
502 }
503
504 filespec = _T("*.smod");
505 cont = odir.GetFirst(&filename, filespec, wxDIR_FILES);
506 while (cont)
507 {
508 fname.SetFullName(filename);
509 wxRemoveFile(fname.GetFullPath());
510 cont = odir.GetNext(&filename);
511 }
512 }
513 }
514
RemoveModFilesWS(NativeParserF * nativeParser)515 void ProjectDependencies::RemoveModFilesWS(NativeParserF* nativeParser)
516 {
517 //Remove all *.mod files in Workspace
518 ProjectsArray* projects = Manager::Get()->GetProjectManager()->GetProjects();
519 for (size_t i = 0; i < projects->GetCount(); ++i)
520 {
521 cbProject* pr = projects->Item(i);
522 if (!pr->IsMakefileCustom())
523 {
524 ProjectBuildTarget* bTarget = pr->GetBuildTarget(pr->GetActiveBuildTarget());
525 RemoveModFiles(pr, bTarget, nativeParser);
526 }
527 }
528 }
529
PrintChildrenTable()530 void ProjectDependencies::PrintChildrenTable()
531 {
532 Manager::Get()->GetLogManager()->DebugLog(_T("\nProjectDependencies::PrintChildrenTable"));
533
534 for(size_t i=0; i < m_ChildrenTable.size(); i++)
535 {
536 ProjectFile* pfile = m_prFilesArr[i];
537
538 Manager::Get()->GetLogManager()->DebugLog(_T("\n")+pfile->file.GetName());
539
540 IntSet* children = m_ChildrenTable[i];
541 IntSet::iterator pos;
542 for (pos=children->begin(); pos != children->end(); ++pos)
543 {
544 ProjectFile* pf = m_prFilesArr[*pos];
545 wxString fname = pf->file.GetName();
546 Manager::Get()->GetLogManager()->DebugLog(_T(" ")+fname);
547 }
548 }
549 }
550
GetSizeFiles()551 size_t ProjectDependencies::GetSizeFiles()
552 {
553 return m_prFilesArr.size();
554 }
555
GetUseFilesFile(const wxString & filename,wxArrayString & useFiles)556 void ProjectDependencies::GetUseFilesFile(const wxString& filename, wxArrayString& useFiles)
557 {
558 if (m_FileIndexMap.count(filename) == 0)
559 return;
560 size_t fileIndex = m_FileIndexMap[filename];
561 StringSet* useModules = m_pUseModules[fileIndex];
562 std::set<size_t> fidxSet;
563 StringSet::iterator pos;
564 for (pos = useModules->begin(); pos != useModules->end(); ++pos)
565 {
566 wxString modName = *pos;
567 if (m_ModuleFileIdxMap.count(modName) == 1)
568 {
569 size_t fidx = m_ModuleFileIdxMap[modName];
570 if (fidx != fileIndex && fidxSet.count(fidx) == 0)
571 {
572 StringIntMap::const_iterator it;
573 for (it = m_FileIndexMap.begin(); it != m_FileIndexMap.end(); ++it)
574 {
575 if (it->second == (int) fidx)
576 {
577 useFiles.Add(it->first);
578 fidxSet.insert(fidx);
579 break;
580 }
581 }
582 }
583 }
584 }
585 }
586
GetExtendsFilesFile(const wxString & filename,wxArrayString & extFiles)587 void ProjectDependencies::GetExtendsFilesFile(const wxString& filename, wxArrayString& extFiles)
588 {
589 if (m_FileIndexMap.count(filename) == 0)
590 return;
591 size_t fileIndex = m_FileIndexMap[filename];
592 StringSet* extSModules = m_pExtendsSModules[fileIndex];
593 std::set<size_t> fidxSet;
594 StringSet::iterator pos;
595 for (pos = extSModules->begin(); pos != extSModules->end(); ++pos)
596 {
597 wxString modName = *pos;
598 size_t fidx;
599 if (m_ModuleFileIdxMap.count(modName) == 1)
600 fidx = m_ModuleFileIdxMap[modName];
601 else if (m_SubmoduleFileIdxMap.count(modName) == 1)
602 fidx = m_SubmoduleFileIdxMap[modName];
603 else
604 continue;
605
606 if (fidx != fileIndex && fidxSet.count(fidx) == 0)
607 {
608 StringIntMap::const_iterator it;
609 for (it = m_FileIndexMap.begin(); it != m_FileIndexMap.end(); ++it)
610 {
611 if (it->second == (int) fidx)
612 {
613 extFiles.Add(it->first);
614 fidxSet.insert(fidx);
615 break;
616 }
617 }
618 }
619 }
620 }
621
GetIncludeFilesFile(const wxString & filename,wxArrayString & includeFiles)622 void ProjectDependencies::GetIncludeFilesFile(const wxString& filename, wxArrayString& includeFiles)
623 {
624 if (m_FileIndexMap.count(filename) == 0)
625 return;
626 size_t fileIndex = m_FileIndexMap[filename];
627 StringSet* incls = m_pIncludes[fileIndex];
628 std::set<size_t> fidxSet;
629 StringSet::iterator pos;
630 for (pos = incls->begin(); pos != incls->end(); ++pos)
631 {
632 wxString incName = *pos;
633 if (m_IncludeFileIdxMap.count(incName) == 1)
634 {
635 size_t fidx = m_IncludeFileIdxMap[incName];
636 if (fidx != fileIndex && fidxSet.count(fidx) == 0)
637 {
638 StringIntMap::const_iterator it;
639 for (it = m_FileIndexMap.begin(); it != m_FileIndexMap.end(); ++it)
640 {
641 if (it->second == (int) fidx)
642 {
643 includeFiles.Add(it->first);
644 fidxSet.insert(fidx);
645 break;
646 }
647 }
648 }
649 }
650 }
651 }
652