1 /* $Id: proj_tree_builder.cpp 602953 2020-03-04 19:52:40Z gouriano $
2  * ===========================================================================
3  *
4  *                            PUBLIC DOMAIN NOTICE
5  *               National Center for Biotechnology Information
6  *
7  *  This software/database is a "United States Government Work" under the
8  *  terms of the United States Copyright Act.  It was written as part of
9  *  the author's official duties as a United States Government employee and
10  *  thus cannot be copyrighted.  This software/database is freely available
11  *  to the public for use. The National Library of Medicine and the U.S.
12  *  Government have not placed any restriction on its use or reproduction.
13  *
14  *  Although all reasonable efforts have been taken to ensure the accuracy
15  *  and reliability of the software and data, the NLM and the U.S.
16  *  Government do not and cannot warrant the performance or results that
17  *  may be obtained by using this software or data. The NLM and the U.S.
18  *  Government disclaim all warranties, express or implied, including
19  *  warranties of performance, merchantability or fitness for any particular
20  *  purpose.
21  *
22  *  Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author:  Viatcheslav Gorelenkov
27  *
28  */
29 
30 #include <ncbi_pch.hpp>
31 #include "proj_tree_builder.hpp"
32 #include "proj_builder_app.hpp"
33 #include "proj_src_resolver.hpp"
34 #include "msvc_prj_defines.hpp"
35 
36 #include "proj_projects.hpp"
37 #include <algorithm>
38 
39 #include "ptb_err_codes.hpp"
40 
41 BEGIN_NCBI_SCOPE
42 
43 const char* s_check_separator = " ____ ";
44 static map<string,size_t> s_buildOrder_byname;
45 static size_t s_BuildOrder=0;
46 
s_WriteBuildOrder(const string & dir_name,const string & mkname)47 void s_WriteBuildOrder(const string& dir_name, const string& mkname)
48 {
49     string name( CDirEntry::ConcatPath(dir_name,mkname));
50     s_buildOrder_byname[name] = ++s_BuildOrder;
51 }
52 
VerifyBuildOrder(const CProjItem & item,list<string> dependencies,const CProjectItemsTree & tree)53 bool CProjectTreeBuilder::VerifyBuildOrder(
54     const CProjItem& item, list<string> dependencies, const CProjectItemsTree&  tree)
55 {
56     bool res = true;
57     if (item.m_MkName.empty()) {
58 // error?
59         return res;
60     }
61     ITERATE(list<string>, d, dependencies) {
62         CProjectItemsTree::TProjects::const_iterator n =
63             tree.m_Projects.find(CreateProjKey(*d));
64             if (n != tree.m_Projects.end()) {
65                 const CProjItem& dep_item = n->second;
66                 if (dep_item.m_MkName.empty()) {
67                     //error?
68                 } else if (s_buildOrder_byname[dep_item.m_MkName] >
69                            s_buildOrder_byname[item.m_MkName]) {
70                     PTB_WARNING_EX(item.m_MkName,
71                         ePTB_InvalidMakefile,
72                         "should be built after: " << dep_item.m_MkName);
73                     res = false;
74                 }
75             }
76 
77     }
78     return res;
79 }
80 
81 
82 struct PLibExclude
83 {
PLibExcludePLibExclude84     PLibExclude(const string& prj_name, const list<string>& excluded_lib_ids)
85         : m_Prj(prj_name)
86     {
87         copy(excluded_lib_ids.begin(), excluded_lib_ids.end(),
88              inserter(m_ExcludedLib, m_ExcludedLib.end()) );
89     }
90 
operator ()PLibExclude91     bool operator() (const string& lib_id) const
92     {
93         if (m_ExcludedLib.find(lib_id) != m_ExcludedLib.end()) {
94             PTB_WARNING_EX(kEmptyStr,ePTB_ProjectExcluded,"Project " << m_Prj << ": library excluded by request: " << lib_id);
95             return true;
96         }
97         return false;
98     }
99 
100 private:
101     string m_Prj;
102     set<string> m_ExcludedLib;
103 };
104 
105 
106 //-----------------------------------------------------------------------------
GetProjType(const string & base_dir,const string & projname,SMakeInInfo::TMakeinType type)107 CProjItem::TProjType SMakeProjectT::GetProjType(const string& base_dir,
108                                                 const string& projname,
109                                                 SMakeInInfo::TMakeinType type)
110 {
111     string fname = "Makefile." + projname;
112 
113     string fname_base = CDirEntry::ConcatPath(base_dir, fname);
114     string fname_app = CDirEntry::ConcatPath(base_dir, fname + ".app");
115     string fname_lib = CDirEntry::ConcatPath(base_dir, fname + ".lib");
116     string fname_dll = CDirEntry::ConcatPath(base_dir, fname + ".dll");
117     string fname_msvc= CDirEntry::ConcatPath(base_dir, fname);
118     string fname_msvc2(fname_msvc);
119 
120     if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eMsvcWin32 ||
121         CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eMsvcX64) {
122         fname_msvc += ".msvcproj";
123     } else {
124         fname_msvc2 += ".in";
125     }
126 
127     switch (type) {
128     case SMakeInInfo::eApp:
129         if ( CDirEntry(fname_app).Exists()) {
130             return CProjKey::eApp;
131         }
132         break;
133     case SMakeInInfo::eLib:
134         if ( CDirEntry(fname_lib).Exists()) {
135             return CProjKey::eLib;
136         }
137         break;
138     case SMakeInInfo::eDll:
139         if ( CDirEntry(fname_dll).Exists()) {
140             return CProjKey::eDll;
141         }
142         break;
143     case SMakeInInfo::eMsvc:
144         if ( CDirEntry(fname_msvc).Exists() || CDirEntry(fname_msvc2).Exists()) {
145             return CProjKey::eMsvc;
146         }
147         break;
148 
149     default:
150         break;
151     }
152 
153     if ( CDirEntry(fname_lib).Exists() )
154         return CProjKey::eLib;
155     else if (CDirEntry(fname_dll).Exists() )
156         return CProjKey::eDll;
157     else if (CDirEntry(fname_app).Exists() )
158         return CProjKey::eApp;
159     else if (CDirEntry(fname_msvc).Exists() || CDirEntry(fname_msvc2).Exists() )
160         return CProjKey::eMsvc;
161     else if (CDirEntry(CDirEntry::ConcatPath(base_dir, fname + ".metal")).Exists() )
162         return CProjKey::eLib;
163 
164     switch (type) {
165     case SMakeInInfo::eApp:
166         PTB_WARNING_EX(fname_app, ePTB_MissingMakefile,
167                        "Makefile not found");
168         break;
169 
170     case SMakeInInfo::eLib:
171         PTB_WARNING_EX(fname_lib, ePTB_MissingMakefile,
172                        "Makefile not found");
173         break;
174 
175     case SMakeInInfo::eDll:
176         PTB_WARNING_EX(fname_dll, ePTB_MissingMakefile,
177                        "Makefile not found");
178         break;
179 
180     case SMakeInInfo::eMsvc:
181         PTB_WARNING_EX(fname_msvc, ePTB_MissingMakefile,
182                        "Makefile not found");
183         break;
184 
185     default:
186         PTB_WARNING_EX(fname_base, ePTB_MissingMakefile,
187                        "Makefile not found");
188         break;
189     }
190     return CProjKey::eNoProj;
191 }
192 
193 
IsMakeInFile(const string & name)194 bool SMakeProjectT::IsMakeInFile(const string& name)
195 {
196     return name == "Makefile.in";
197 }
198 
199 
IsMakeLibFile(const string & name)200 bool SMakeProjectT::IsMakeLibFile(const string& name)
201 {
202     return NStr::StartsWith(name, "Makefile")  &&
203 	       NStr::EndsWith(name, ".lib");
204 }
205 
IsMakeDllFile(const string & name)206 bool SMakeProjectT::IsMakeDllFile(const string& name)
207 {
208     return NStr::StartsWith(name, "Makefile")  &&
209 	       NStr::EndsWith(name, ".dll");
210 }
211 
212 
IsMakeAppFile(const string & name)213 bool SMakeProjectT::IsMakeAppFile(const string& name)
214 {
215     return NStr::StartsWith(name, "Makefile")  &&
216 	       NStr::EndsWith(name, ".app");
217 }
218 
219 
220 /*
221 bool SMakeProjectT::IsUserProjFile(const string& name)
222 {
223     return NStr::StartsWith(name, "Makefile")  &&
224 	       NStr::EndsWith(name, ".msvcproj");
225 }
226 */
227 
228 
DoResolveDefs(CSymResolver & resolver,TFiles & files,const set<string> & keys)229 void SMakeProjectT::DoResolveDefs(CSymResolver& resolver,
230                                   TFiles& files,
231                                   const set<string>& keys)
232 {
233     const CMsvcSite& site = GetApp().GetSite();
234     set<string> defs_unresolved;
235     map<string,string> defs_resolved;
236     NON_CONST_ITERATE(CProjectTreeBuilder::TFiles, p, files) {
237 
238         CMsvcProjectMakefile msvc_prj(p->first + "." + GetApp().GetRegSettings().m_MakefilesExt);
239         bool msvc_empty = msvc_prj.IsEmpty();
240 
241 	    NON_CONST_ITERATE(CSimpleMakeFileContents::TContents,
242                           n,
243                           p->second.m_Contents) {
244 
245             const string& key    = n->first;
246             list<string>& values = n->second;
247             bool cppflags = key == "CPPFLAGS";
248 
249 //		    if (keys.find(key) != keys.end())
250 		    {
251                 bool modified = false;
252                 list<string> new_vals;
253                 list<string>  redef_values;
254                 modified = msvc_prj.Redefine(values,redef_values);
255                 NON_CONST_ITERATE(list<string>, k, redef_values) {
256 //                NON_CONST_ITERATE(list<string>, k, values) {
257                     //iterate all values and try to resolve
258                     const string& val = *k;
259                     if (cppflags && site.IsCppflagDescribed(val)) {
260                         if (msvc_empty) {
261                             new_vals.push_back(val);
262                         } else {
263                             msvc_prj.Append(new_vals,val);
264                         }
265                     } else if( !CSymResolver::HasDefine(val) ) {
266                         if (msvc_empty) {
267                             new_vals.push_back(val);
268                         } else {
269                             msvc_prj.Append(new_vals,val);
270                         }
271                     } else {
272                         list<string> resolved_def;
273                         string val_define = FilterDefine(val);
274 	                    resolver.Resolve(val, &resolved_def, p->second);
275 	                    if ( resolved_def.empty() ) {
276                             defs_unresolved.insert(val);
277 		                    new_vals.push_back(val_define); //not resolved - keep old val
278                         } else {
279                             defs_resolved[val] = NStr::Join( resolved_def, " ");
280                             //was resolved
281                             ITERATE(list<string>, l, resolved_def) {
282                                 const string& define = *l;
283                                 if ( IsConfigurableDefine(define) ) {
284                                     string stripped = StripConfigurableDefine(define);
285                                     string resolved_def_str;
286                                     list<string> libchoices_includes ;
287                                     site.GetLibChoiceIncludes(stripped, &libchoices_includes);
288                                     if (!libchoices_includes.empty()) {
289                                         resolved_def_str = NStr::Join( libchoices_includes, " ");
290                                     } else {
291                                         resolved_def_str = site.GetDefinesEntry(stripped);
292                                     }
293                                     if ( !resolved_def_str.empty() ) {
294                                         defs_resolved[define] = resolved_def_str;
295                                         list<string> resolved_defs;
296                                         NStr::Split(resolved_def_str,
297                                                     LIST_SEPARATOR,
298                                                     resolved_defs, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
299                                         if (msvc_empty) {
300                                             copy(resolved_defs.begin(),
301                                                 resolved_defs.end(),
302                                                 back_inserter(new_vals));
303                                         } else {
304                                             msvc_prj.Append(new_vals,resolved_defs);
305                                         }
306                                     } else {
307 // configurable definitions could be described in terms of components
308                                         list<string> components;
309                                         site.GetComponents(stripped, &components);
310                                         if (!components.empty()) {
311                                             defs_resolved[define] = "Component= " + NStr::Join( components, ", ");
312                                         } else {
313                                             defs_unresolved.insert(define);
314                                         }
315                                         if (msvc_empty) {
316                                             new_vals.push_back(define);
317                                         } else {
318                                             msvc_prj.Append(new_vals,define);
319                                         }
320                                     }
321 
322                                 } else if (HasConfigurableDefine(define)) {
323                                     string def(define);
324                                     while (HasConfigurableDefine(def)) {
325                                         string raw = ExtractConfigurableDefine(def);
326                                         string stripped = StripConfigurableDefine(raw);
327                                         string resolved_def_str = site.GetDefinesEntry(stripped);
328                                         if (resolved_def_str == " ") {
329                                             resolved_def_str.erase();
330                                         }
331                                         NStr::ReplaceInPlace(def, raw, resolved_def_str);
332                                     }
333                                     if (msvc_empty) {
334                                         new_vals.push_back( def);
335                                     } else {
336                                         msvc_prj.Append(new_vals,def);
337                                     }
338                                 } else {
339                                     if (msvc_empty) {
340                                         new_vals.push_back(define);
341                                     } else {
342                                         msvc_prj.Append(new_vals,define);
343                                     }
344                                 }
345                             }
346 		                    modified = true;
347                         }
348                     }
349                 }
350                 if (modified) {
351                     msvc_prj.Redefine(new_vals,redef_values);
352                     values = redef_values; // by ref!
353                 }
354 		    }
355         }
356     }
357 
358     if (!defs_resolved.empty()) {
359         string s;
360         for (map<string,string>::const_iterator r = defs_resolved.begin();
361             r != defs_resolved.end(); ++r) {
362             s += ' ';
363             s += r->first;
364             s += " = ";
365             s += r->second;
366             s += ";";
367         }
368         PTB_INFO("Resolved macro definitions: " << s);
369     }
370     if (!defs_unresolved.empty()) {
371         string s;
372         for (set<string>::const_iterator u = defs_unresolved.begin();
373             u != defs_unresolved.end(); ++u) {
374             s += ' ';
375             s += *u;
376         }
377         PTB_WARNING_EX(kEmptyStr, ePTB_MacroUndefined,
378                        "Unresolved macro definitions:" << s);
379     }
380 }
381 
382 
GetOneIncludeDir(const string & flag,const string & token)383 string SMakeProjectT::GetOneIncludeDir(const string& flag, const string& token)
384 {
385     size_t token_pos = flag.find(token);
386     if (token_pos != NPOS &&
387         token_pos + token.length() < flag.length()) {
388         return flag.substr(token_pos + token.length());
389     }
390     return "";
391 }
392 
393 
CreateIncludeDirs(const list<string> & cpp_flags,const string & source_base_dir,list<string> * include_dirs)394 void SMakeProjectT::CreateIncludeDirs(const list<string>& cpp_flags,
395                                       const string&       source_base_dir,
396                                       list<string>*       include_dirs)
397 {
398     include_dirs->clear();
399     ITERATE(list<string>, p, cpp_flags) {
400         const string& flag = *p;
401 //        string token("-I$(includedir)");
402 
403         // process -I$(includedir)
404         string token_val;
405         token_val = SMakeProjectT::GetOneIncludeDir(flag, "-I$(includedir)");
406         if ( !token_val.empty() ) {
407             string dir =
408                 CDirEntry::ConcatPath(GetApp().GetProjectTreeInfo().m_Include,
409                                       token_val);
410             dir = CDirEntry::NormalizePath(dir);
411             dir = CDirEntry::AddTrailingPathSeparator(dir);
412 
413             include_dirs->push_back(dir);
414         }
415         token_val = SMakeProjectT::GetOneIncludeDir(flag, "-I$(incdir)");
416         if ( !token_val.empty() ) {
417             string dir = CDirEntry::ConcatPath(GetApp().m_IncDir,token_val);
418             dir = CDirEntry::NormalizePath(dir);
419             dir = CDirEntry::AddTrailingPathSeparator(dir);
420 
421             include_dirs->push_back(dir);
422         }
423 
424         // process -I$(srcdir)
425         token_val = SMakeProjectT::GetOneIncludeDir(flag, "-I$(srcdir)");
426         if ( !token_val.empty() || flag == "-I$(srcdir)" )  {
427             string dir =
428                 CDirEntry::ConcatPath(source_base_dir,
429                                       token_val);
430             dir = CDirEntry::NormalizePath(dir);
431             dir = CDirEntry::AddTrailingPathSeparator(dir);
432 
433             include_dirs->push_back(dir);
434         }
435 
436         // process -Ipath
437         token_val = SMakeProjectT::GetOneIncludeDir(flag, "-I");
438         if ( !token_val.empty() && token_val[0] != '$' && token_val[0] != '@' && token_val[0] != ':' )  {
439             string dir = CDirEntry::NormalizePath(token_val);
440             dir = CDirEntry::AddTrailingPathSeparator(dir);
441             include_dirs->push_back(dir);
442         }
443 
444         // process defines like NCBI_C_INCLUDE
445         if(CSymResolver::IsDefine(flag)) {
446             string dir_all;
447             GetApp().GetSite().ResolveDefine(CSymResolver::StripDefine(flag), dir_all);
448             if ( !dir_all.empty() ) {
449                 list<string> dir_list;
450                 NStr::Split(dir_all, LIST_SEPARATOR, dir_list, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate | NStr::fSplit_CanQuote);
451                 ITERATE(list<string>, dir_item, dir_list) {
452                     const string& dir = *dir_item;
453                     if ( CDirEntry(dir).IsDir() ) {
454                         include_dirs->push_back(dir);
455                     } else if (CDirEntry::IsAbsolutePath(dir)) {
456                         PTB_WARNING_EX(kEmptyStr, ePTB_FileNotFound, "In " << source_base_dir << ": "
457                             << flag << " = " << dir << ": "
458                             << dir << " not found");
459                         include_dirs->push_back(dir);
460                     } else {
461                         string d =
462                             CDirEntry::ConcatPath(GetApp().GetProjectTreeInfo().m_Include, dir);
463                         d = CDirEntry::NormalizePath(d);
464                         d = CDirEntry::AddTrailingPathSeparator(d);
465                         if ( CDirEntry(d).IsDir() ) {
466                             include_dirs->push_back(d);
467                         }
468 /*
469                         else {
470                             LOG_POST(Warning << flag << " = " << dir << ": "
471                                         << dir << " not found");
472                         }
473 */
474                     }
475                 }
476             }
477         }
478 
479         // process additional include dirs for LibChoices
480         if(CSymResolver::IsDefine(flag)) {
481             string sflag = CSymResolver::StripDefine(flag);
482             list<string> libchoices_abs_includes ;
483             GetApp().GetSite().GetLibChoiceIncludes(sflag,
484                                                     &libchoices_abs_includes);
485             ITERATE(list<string>, n, libchoices_abs_includes) {
486                 const string& dir = *n;
487                 if ( !dir.empty() ) {
488                     include_dirs->push_back(dir);
489                 }
490             }
491         }
492     }
493     include_dirs->sort();
494     include_dirs->unique();
495 }
496 
497 
CreateDefines(const list<string> & cpp_flags,list<string> * defines)498 void SMakeProjectT::CreateDefines(const list<string>& cpp_flags,
499                                   list<string>*       defines)
500 {
501     defines->clear();
502 
503     ITERATE(list<string>, p, cpp_flags) {
504         const string& flag = *p;
505         if ( NStr::StartsWith(flag, "-D") ) {
506             defines->push_back(flag.substr(2));
507         }
508     }
509 }
510 
511 
Create3PartyLibs(const list<string> & libs_flags,const list<string> & expected_flags,list<string> * libs_list,const string * mkname)512 void SMakeProjectT::Create3PartyLibs(
513     const list<string>& libs_flags, const list<string>& expected_flags,
514     list<string>*   libs_list,  const string* mkname)
515 {
516     bool liborder_found = mkname != NULL && GetApp().m_LibraryOrder.find(*mkname) != GetApp().m_LibraryOrder.end();
517     set<string> done;
518     list<string> unkflags;
519     list<CProjKey> libs3;
520     ITERATE(list<string>, p, libs_flags) {
521         string flag = *p;
522         if (flag == "#") {
523             break;
524         } else if ( IsConfigurableDefine(flag) ) {
525             libs_list->push_back(StripConfigurableDefine(flag));
526             done.insert(flag);
527         } else if (NStr::StartsWith(flag, "-l")) {
528             string suffix;
529 	    CSymResolver::StripSuffix(flag, &suffix);
530             if (liborder_found && find(
531                     GetApp().m_LibraryOrder[*mkname].begin(),
532                     GetApp().m_LibraryOrder[*mkname].end(), flag.substr(2)) !=
533                         GetApp().m_LibraryOrder[*mkname].end()) {
534                 continue;
535             }
536             libs3.push_back( CProjKey(CProjKey::eLib, flag.substr(2), suffix));
537 // user cannot be trusted
538 //            GetApp().m_3PartyLibs.insert(flag.substr(2));
539             done.insert(flag.substr(2));
540         } else if ( NStr::CompareCase(flag, "-framework") == 0 ) {
541             if (p != libs_flags.end()) {
542                 GetApp().m_3PartyLibs.insert(*(++p));
543                 GetApp().m_Frameworks.insert(*p);
544                 done.insert(flag);
545             }
546         } else {
547             unkflags.push_back(flag);
548         }
549     }
550     bool added = false;
551     if (GetApp().m_AddMissingDep) {
552         ITERATE(list<string>, p, expected_flags) {
553             const string& flag = *p;
554             if (NStr::StartsWith(flag, "-l")) {
555                 if (done.find(flag.substr(2)) == done.end()) {
556                     libs3.push_back( CProjKey(CProjKey::eLib, flag.substr(2)));
557                     done.insert(flag.substr(2));
558                     added = true;
559                 }
560             } else if (IsConfigurableDefine(flag)) {
561                 if (done.find(flag) == done.end()) {
562                     libs3.push_back( CProjKey(CProjKey::eLib, flag));
563                     done.insert(flag);
564                     added = true;
565                 }
566             } else {
567                 if (find(unkflags.begin(), unkflags.end(), flag) == unkflags.end()) {
568                     unkflags.push_back(flag);
569                     added = true;
570                 }
571             }
572         }
573     }
574     if (mkname != NULL && !GetApp().IsScanningWholeTree() && !libs3.empty()) {
575         list<string> liborder;
576         if (added) {
577             liborder.push_back("");
578         }
579         VerifyLibDepends(libs3, *mkname, liborder);
580         if (!liborder.empty()) {
581             GetApp().m_3PartyLibraryOrder[*mkname] = unkflags;
582             ITERATE( list<string>, s, liborder) {
583                 if (!s->empty()) {
584                     GetApp().m_3PartyLibraryOrder[*mkname].push_back(*s);
585                     if (libs_list && find(libs_list->begin(), libs_list->end(), *s) == libs_list->end()) {
586                         if ( IsConfigurableDefine(*s) ) {
587                             libs_list->push_back(StripConfigurableDefine(*s));
588                         } else {
589                             libs_list->push_back(*s);
590                         }
591                     }
592                 }
593             }
594         }
595     }
596 }
597 
598 
AnalyzeMakeIn(const CSimpleMakeFileContents & makein_contents,TMakeInInfoList * info)599 void SMakeProjectT::AnalyzeMakeIn
600     (const CSimpleMakeFileContents& makein_contents,
601      TMakeInInfoList*               info)
602 {
603     info->clear();
604     CSimpleMakeFileContents::TContents::const_iterator p;
605 
606     p = makein_contents.m_Contents.find("LIB_PROJ");
607     if (p != makein_contents.m_Contents.end()) {
608 
609         info->push_back(SMakeInInfo(SMakeInInfo::eLib, p->second,
610             makein_contents.GetMakeType()));
611     }
612     p = makein_contents.m_Contents.find("EXPENDABLE_LIB_PROJ");
613     if (p != makein_contents.m_Contents.end()) {
614 
615         info->push_back(SMakeInInfo(SMakeInInfo::eLib, p->second,
616             max(makein_contents.GetMakeType(),eMakeType_Expendable)));
617     }
618     p = makein_contents.m_Contents.find("POTENTIAL_LIB_PROJ");
619     if (p != makein_contents.m_Contents.end()) {
620 
621         info->push_back(SMakeInInfo(SMakeInInfo::eLib, p->second,
622             max(makein_contents.GetMakeType(),eMakeType_Potential)));
623     }
624 
625     p = makein_contents.m_Contents.find("DLL_PROJ");
626     if (p != makein_contents.m_Contents.end()) {
627 
628         info->push_back(SMakeInInfo(SMakeInInfo::eDll, p->second,
629             makein_contents.GetMakeType()));
630     }
631     p = makein_contents.m_Contents.find("EXPENDABLE_DLL_PROJ");
632     if (p != makein_contents.m_Contents.end()) {
633 
634         info->push_back(SMakeInInfo(SMakeInInfo::eDll, p->second,
635             max(makein_contents.GetMakeType(),eMakeType_Expendable)));
636     }
637     p = makein_contents.m_Contents.find("POTENTIAL_DLL_PROJ");
638     if (p != makein_contents.m_Contents.end()) {
639 
640         info->push_back(SMakeInInfo(SMakeInInfo::eDll, p->second,
641             max(makein_contents.GetMakeType(),eMakeType_Potential)));
642     }
643 
644     p = makein_contents.m_Contents.find("APP_PROJ");
645     if (p != makein_contents.m_Contents.end()) {
646 
647         info->push_back(SMakeInInfo(SMakeInInfo::eApp, p->second,
648             makein_contents.GetMakeType()));
649     }
650     p = makein_contents.m_Contents.find("EXPENDABLE_APP_PROJ");
651     if (p != makein_contents.m_Contents.end()) {
652 
653         info->push_back(SMakeInInfo(SMakeInInfo::eApp, p->second,
654             max(makein_contents.GetMakeType(),eMakeType_Expendable)));
655     }
656     p = makein_contents.m_Contents.find("POTENTIAL_APP_PROJ");
657     if (p != makein_contents.m_Contents.end()) {
658 
659         info->push_back(SMakeInInfo(SMakeInInfo::eApp, p->second,
660             max(makein_contents.GetMakeType(),eMakeType_Potential)));
661     }
662 
663     p = makein_contents.m_Contents.find("ASN_PROJ");
664     if (p != makein_contents.m_Contents.end()) {
665 
666         info->push_back(SMakeInInfo(SMakeInInfo::eASN, p->second,
667             makein_contents.GetMakeType()));
668     }
669     p = makein_contents.m_Contents.find("DTD_PROJ");
670     if (p != makein_contents.m_Contents.end()) {
671 
672         info->push_back(SMakeInInfo(SMakeInInfo::eDTD, p->second,
673             makein_contents.GetMakeType()));
674     }
675     p = makein_contents.m_Contents.find("XSD_PROJ");
676     if (p != makein_contents.m_Contents.end()) {
677 
678         info->push_back(SMakeInInfo(SMakeInInfo::eXSD, p->second,
679             makein_contents.GetMakeType()));
680     }
681     p = makein_contents.m_Contents.find("WSDL_PROJ");
682     if (p != makein_contents.m_Contents.end()) {
683 
684         info->push_back(SMakeInInfo(SMakeInInfo::eWSDL, p->second,
685             makein_contents.GetMakeType()));
686     }
687     p = makein_contents.m_Contents.find("JSD_PROJ");
688     if (p != makein_contents.m_Contents.end()) {
689 
690         info->push_back(SMakeInInfo(SMakeInInfo::eJSD, p->second,
691             makein_contents.GetMakeType()));
692     }
693     p = makein_contents.m_Contents.find("PROTOBUF_PROJ");
694     if (p != makein_contents.m_Contents.end()) {
695 
696         info->push_back(SMakeInInfo(SMakeInInfo::eProtobuf, p->second,
697             makein_contents.GetMakeType()));
698     }
699 
700     if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eUnix) {
701         p = makein_contents.m_Contents.find("UNIX_PROJ");
702     } else if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eXCode) {
703         p = makein_contents.m_Contents.find("XCODE_PROJ");
704     } else {
705         p = makein_contents.m_Contents.find("MSVC_PROJ");
706     }
707     if (p != makein_contents.m_Contents.end()) {
708 
709         info->push_back(SMakeInInfo(SMakeInInfo::eMsvc, p->second,
710             makein_contents.GetMakeType()));
711     }
712 
713     if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eUnix) {
714         p = makein_contents.m_Contents.find("EXPENDABLE_UNIX_PROJ");
715         if (p != makein_contents.m_Contents.end()) {
716 
717             info->push_back(SMakeInInfo(SMakeInInfo::eMsvc, p->second,
718                 max(makein_contents.GetMakeType(),eMakeType_Expendable)));
719         }
720     }
721     p = makein_contents.m_Contents.find("METAL_PROJ");
722     if (p != makein_contents.m_Contents.end()) {
723 
724         info->push_back(SMakeInInfo(SMakeInInfo::eMetal, p->second,
725             makein_contents.GetMakeType()));
726     }
727 }
728 
729 
CreateMakeAppLibFileName(const string & base_dir,const string & projname,SMakeInInfo::TMakeinType type)730 string SMakeProjectT::CreateMakeAppLibFileName
731                 (const string&            base_dir,
732                  const string&            projname,
733                  SMakeInInfo::TMakeinType type)
734 {
735     CProjItem::TProjType proj_type =
736             SMakeProjectT::GetProjType(base_dir, projname, type);
737 
738     string fname = "Makefile." + projname;
739     switch (proj_type) {
740     case CProjKey::eLib:  fname += type == SMakeInInfo::eMetal ? ".metal" : ".lib"; break;
741     case CProjKey::eDll:  fname += ".dll"; break;
742     case CProjKey::eApp:  fname += ".app"; break;
743     case CProjKey::eMsvc:
744         if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eUnix) {
745             if (!CDirEntry( CDirEntry::ConcatPath(base_dir,fname)).Exists()) {
746                 fname += ".in";
747             }
748         } else if (CMsvc7RegSettings::GetMsvcPlatform() != CMsvc7RegSettings::eXCode) {
749             fname += ".msvcproj";
750         }
751         break;
752     default: break;
753     }
754     return CDirEntry::ConcatPath(base_dir, fname);
755 }
756 
757 
CreateFullPathes(const string & dir,const list<string> files,list<string> * full_pathes)758 void SMakeProjectT::CreateFullPathes(const string&      dir,
759                                      const list<string> files,
760                                      list<string>*      full_pathes)
761 {
762     ITERATE(list<string>, p, files) {
763         string full_path = CDirEntry::ConcatPath(dir, *p);
764         full_pathes->push_back(full_path);
765     }
766 }
767 
768 static
s_CollectAllLeaves(const map<string,set<string>> & source_dep,const map<string,set<string>> & source_flags,const string & branch,set<string> & all_dep,set<string> & all_flags)769 void s_CollectAllLeaves(const map<string, set<string> >& source_dep,
770                         const map<string, set<string> >& source_flags,
771                         const string& branch,
772                         set<string>& all_dep,
773                         set<string>& all_flags)
774 {
775     if (all_dep.find(branch) != all_dep.end()) {
776         return;
777     }
778     all_dep.insert(branch);
779     if (source_flags.find(branch) != source_flags.end()) {
780         const set<string>& flags(source_flags.find(branch)->second);
781         ITERATE(set<string>, f, flags) {
782             all_flags.insert(*f);
783         }
784     }
785     if (source_dep.find(branch) != source_dep.end()) {
786         const set<string>& branches(source_dep.find(branch)->second);
787         ITERATE(set<string>, b, branches) {
788             s_CollectAllLeaves(source_dep, source_flags, *b, all_dep, all_flags);
789         }
790     }
791 }
792 
VerifyLibDepends(list<CProjKey> & depends_ids_arg,const string & mkname,list<string> & liborder,const set<string> * libs_3party,list<string> * expected_3party)793 void  SMakeProjectT::VerifyLibDepends(
794      list<CProjKey>&  depends_ids_arg, const string& mkname, list<string>& liborder,
795      const set<string>* libs_3party, list<string>* expected_3party)
796 {
797     if (depends_ids_arg.empty()) {
798         return;
799     }
800     if (GetApp().m_GraphDepPrecedes.empty()) {
801         return;
802     }
803     CProjBulderApp& app(GetApp());
804     list<string> warnings;
805     list<string> original;
806     list<string> duplicates;
807     list<string> missing;
808     map<string, string> missing_suffix;
809     set<string> alldepends;
810     set<string> allflags;
811     list<CProjKey>  depends_ids( depends_ids_arg);
812 
813     for(list<CProjKey>::const_iterator p = depends_ids.begin();
814         p != depends_ids.end(); ++p) {
815         for(list<CProjKey>::const_iterator i = p;
816             ++i != depends_ids.end();) {
817             if (*i == *p) {
818                 duplicates.push_back(i->Id());
819                 break;
820             }
821         }
822         original.push_back(p->Id());
823         s_CollectAllLeaves( app.m_GraphDepPrecedes, app.m_GraphDepFlags, p->Id(), alldepends, allflags);
824     }
825     if (expected_3party != nullptr) {
826         ITERATE( set<string>, s, allflags) {
827             expected_3party->push_back(*s);
828         }
829     }
830     ITERATE( set<string>, s, alldepends) {
831         string id(*s);
832         string s_suffix;
833         CSymResolver::StripSuffix(id, &s_suffix);
834         list<CProjKey>::const_iterator p = depends_ids.begin();
835         for(; p != depends_ids.end(); ++p) {
836             if (p->Id() == id) {
837                 break;
838             }
839         }
840         if (p == depends_ids.end()) {
841             for(p = depends_ids.begin(); p != depends_ids.end(); ++p) {
842                 if (app.m_GraphDepIncludes[p->Id()].find(id) != app.m_GraphDepIncludes[p->Id()].end()) {
843                     break;
844                 }
845             }
846             if (p == depends_ids.end()) {
847                 if (libs_3party == nullptr ||
848                     libs_3party->find(id) == libs_3party->end()) {
849                     if (!SMakeProjectT::IsConfigurableDefine(id) &&
850                         !app.GetSite().IsLibWithChoice(id) &&
851                         !app.GetSite().Is3PartyLibWithChoice(id)) {
852                         missing.push_back(id);
853                         missing_suffix[id] = s_suffix;
854                     }
855                 } else if (expected_3party != nullptr) {
856                     if (SMakeProjectT::IsConfigurableDefine(id)) {
857                         expected_3party->push_back( id);
858                     } else {
859                         expected_3party->push_back( "-l" + id);
860                     }
861                 }
862             }
863         }
864     }
865     if (!missing.empty()) {
866         warnings.push_back("missing dependencies: " + NStr::Join(missing,","));
867         if (app.m_AddMissingDep && libs_3party != nullptr) {
868             ITERATE( list<string>, m,  missing) {
869                 depends_ids.push_back(CProjKey(CProjKey::eLib, *m, missing_suffix[*m]));
870             }
871         }
872     }
873     if (!duplicates.empty()) {
874         warnings.push_back("duplicate dependencies: " + NStr::Join(duplicates,","));
875     }
876 #if 1
877     set<string> projlibs;
878     bool fix = (!liborder.empty() && liborder.begin()->empty()) ||
879                  !duplicates.empty() || depends_ids_arg.size() != depends_ids.size();
880     if (fix) {
881         liborder.clear();
882     }
883     if (!app.m_GraphDepPrecedes.empty()) {
884         set<string> libsofar;
885         for(list<CProjKey>::const_iterator p = depends_ids.begin();
886             p != depends_ids.end(); ++p) {
887             list<string> wrong;
888             bool obsolete = false;
889             ITERATE(set<string>, s, libsofar) {
890                 if (app.m_GraphDepPrecedes.find(p->Id()) != app.m_GraphDepPrecedes.end()) {
891                     if (app.m_GraphDepPrecedes[p->Id()].find(*s) != app.m_GraphDepPrecedes[p->Id()].end()) {
892                         wrong.push_back(*s);
893                     }
894                 }
895                 if (app.m_GraphDepIncludes[p->Id()].find(*s) != app.m_GraphDepIncludes[p->Id()].end()) {
896                     fix=true;
897                     obsolete = true;
898                     projlibs.erase(*s);
899                     projlibs.insert(p->Id());
900                     warnings.push_back("obsolete library: " + *s + " already included into " + p->Id());
901                 }
902                 if (app.m_GraphDepIncludes[*s].find(p->Id()) != app.m_GraphDepIncludes[*s].end()) {
903                     fix=true;
904                     obsolete = true;
905                     projlibs.erase(p->Id());
906                     projlibs.insert(*s);
907                     warnings.push_back("obsolete library: " + p->Id() + " already included into " + *s);
908                 }
909             }
910             if (!wrong.empty()) {
911                 fix=true;
912 #if 0
913                 if (find(missing.begin(), missing.end(), p->Id()) == missing.end()) {
914                     warnings.push_back("wrong library order: " + p->Id() + " should precede " + NStr::Join(wrong,","));
915                 }
916 #endif
917             }
918             libsofar.insert(p->Id());
919             if (!obsolete) {
920                 projlibs.insert(p->Id());
921             }
922         }
923 // all libs should be known
924         {
925             list<string> unknown;
926             ITERATE (set<string>, p,  projlibs) {
927                 if (app.m_GraphDepPrecedes.find(*p) == app.m_GraphDepPrecedes.end()) {
928                     unknown.push_back(*p);
929                 }
930             }
931             if (!unknown.empty()) {
932                 fix = false;
933                 warnings.push_back("unknown libraries: "  + NStr::Join(unknown,","));
934             }
935         }
936     }
937     if (fix) {
938         if (app.m_GraphDepRank.empty()) {
939             ITERATE (set<string>, p,  projlibs) {
940                 liborder.push_back(*p);
941             }
942         } else {
943             vector< list<string> > recommend;
944             for (set<string>::const_iterator p= projlibs.begin(); p != projlibs.end(); ++p) {
945                 size_t rank = app.m_GraphDepRank[*p];
946                 while (recommend.size() < rank+1) {
947                     list<string> t;
948                     recommend.push_back(t);
949                 }
950                 recommend[rank].push_back(*p);
951             }
952             list<string> advice;
953             for (size_t a= recommend.size(); a!= 0; --a) {
954                 advice.insert(advice.end(), recommend[a-1].begin(), recommend[a-1].end());
955             }
956 #if 0
957             warnings.push_back("present     library order: " + NStr::Join(original,","));
958             warnings.push_back("recommended library order: " + NStr::Join(advice,","));
959 #endif
960             list<string> advice_full;
961             ITERATE( list<string>, a, advice) {
962                 for(list<CProjKey>::const_iterator p = depends_ids.begin();
963                     p != depends_ids.end(); ++p) {
964                     if (*a == p->Id()) {
965                         advice_full.push_back( p->FullId());
966                         break;
967                     }
968                 }
969             }
970             liborder = advice_full;
971         }
972     }
973 #if 0
974     if (!warnings.empty() && expected_3party != nullptr) {
975         if (libs_3party == nullptr) {
976             warnings.push_front("====== Library order warnings (3rd party libs) ======");
977         } else {
978             warnings.push_front("====== Library order warnings (toolkit libs) ======");
979         }
980         PTB_WARNING_EX(mkname,ePTB_InvalidMakefile,
981             NStr::Join(warnings,"\n"));
982     }
983 #endif
984 #else
985 /*
986     this compares dependency rank,
987     BUT rank does not mean that one library really needs another one;
988     maybe, they are just in different dependency branches.
989     That is, while, in general, it is good to place higher rank libs first,
990     in reality, it is not necessarily a problem.
991 
992     ALSO, this is very slow, most likely because of large number of warning generated
993 */
994     if (!app.m_GraphDepRank.empty()) {
995         set<string> libsofar;
996         for(list<CProjKey>::const_iterator p = depends_ids.begin();
997             p != depends_ids.end(); ++p) {
998             list<string> wrong;
999             ITERATE(set<string>, s, libsofar) {
1000                 if (app.m_GraphDepRank[*s] < app.m_GraphDepRank[p->Id()]) {
1001                     wrong.push_back(*s);
1002                 }
1003                 if (app.m_GraphDepIncludes[p->Id()].find(*s) != app.m_GraphDepIncludes[p->Id()].end()) {
1004                     PTB_WARNING_EX(mkname,ePTB_InvalidMakefile,
1005                         "obsolete library: " << *s << " already included into " << p->Id());
1006                 }
1007                 if (app.m_GraphDepIncludes[*s].find(p->Id()) != app.m_GraphDepIncludes[*s].end()) {
1008                     PTB_WARNING_EX(mkname,ePTB_InvalidMakefile,
1009                         "obsolete library: " << p->Id() << " already included into " << *s);
1010                 }
1011             }
1012             if (!wrong.empty()) {
1013                 PTB_WARNING_EX(mkname,ePTB_InvalidMakefile,
1014                     "wrong library order: " << p->Id() << " should precede " << NStr::Join(wrong,","));
1015             }
1016             libsofar.insert(p->Id());
1017         }
1018     }
1019 #endif
1020     if (depends_ids_arg.size() != depends_ids.size()) {
1021         depends_ids_arg = depends_ids;
1022     }
1023 }
1024 
ConvertLibDepends(const list<string> & depends,list<CProjKey> * depends_ids,const string * mkname,list<string> * expected_3party)1025 void SMakeProjectT::ConvertLibDepends(const list<string>& depends,
1026                                       list<CProjKey>*     depends_ids,
1027                                       const string* mkname,
1028                                       list<string>* expected_3party)
1029 {
1030     list<string> depends_libs;
1031     SMakeProjectT::ConvertLibDependsMacro(depends, depends_libs);
1032 
1033     const CMsvcSite& site = GetApp().GetSite();
1034     ITERATE(list<string>, p, depends_libs) {
1035         string id = *p;
1036         string suffix;
1037         CSymResolver::StripSuffix(id, &suffix);
1038         if(CSymResolver::IsDefine(id)) {
1039             string def;
1040             GetApp().GetSite().ResolveDefine(CSymResolver::StripDefine(id), def);
1041             list<string> resolved_def;
1042             NStr::Split(def, LIST_SEPARATOR, resolved_def, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
1043             ITERATE(list<string>, r, resolved_def) {
1044                 id = *r;
1045                 if (!site.IsLibWithChoice(id) ||
1046                      site.GetChoiceForLib(id) == CMsvcSite::eLib) {
1047                     depends_ids->push_back(CProjKey(CProjKey::eLib, id, suffix));
1048                 }
1049             }
1050         } else if (SMakeProjectT::IsConfigurableDefine(id)) {
1051         } else if (id.empty()) {
1052         } else {
1053             if (!site.IsLibWithChoice(id) ||
1054                  site.GetChoiceForLib(id) == CMsvcSite::eLib) {
1055                 depends_ids->push_back(CProjKey(CProjKey::eLib, id, suffix));
1056             }
1057         }
1058     }
1059 
1060     if (mkname != NULL && !GetApp().IsScanningWholeTree()) {
1061         VerifyLibDepends(*depends_ids, *mkname, GetApp().m_LibraryOrder[ *mkname],
1062             &GetApp().m_3PartyLibs, expected_3party);
1063     }
1064 
1065     depends_ids->sort();
1066     depends_ids->unique();
1067 }
1068 
ConvertLibDependsMacro(const list<string> & depends,list<string> & depends_libs)1069 void SMakeProjectT::ConvertLibDependsMacro(const list<string>& depends,
1070                                            list<string>& depends_libs)
1071 {
1072     const CMsvcSite& site = GetApp().GetSite();
1073     ITERATE(list<string>, p, depends) {
1074         const string& id = *p;
1075         if (id[0] == '#') {
1076             break;
1077         }
1078         string lib = site.ProcessMacros(id,false);
1079         if (!lib.empty()) {
1080             depends_libs.push_back(lib);
1081         } else {
1082             if (CSymResolver::IsDefine(id) &&
1083                 site.GetMacros().GetValue(CSymResolver::StripDefine(id),lib)) {
1084                 list<string> res;
1085                 NStr::Split(lib, LIST_SEPARATOR, res, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
1086                 ITERATE( list<string>, r, res) {
1087                     if (NStr::StartsWith(*r, "-l")) {
1088                         depends_libs.push_back(r->substr(2));
1089                     } else {
1090                         depends_libs.push_back(*r);
1091                     }
1092                 }
1093             } else {
1094                 depends_libs.push_back(id);
1095             }
1096         }
1097     }
1098 }
1099 
1100 
IsConfigurableDefine(const string & define)1101 bool SMakeProjectT::IsConfigurableDefine(const string& define)
1102 {
1103     if (NStr::StartsWith(define, "@")) {
1104         string::size_type end = define.find("@",1);
1105         return end != string::npos && ( ++end == define.size() || define[end] == '\0');
1106     }
1107     return false;
1108 
1109 }
1110 
1111 
StripConfigurableDefine(const string & define)1112 string SMakeProjectT::StripConfigurableDefine(const string& define)
1113 {
1114     return IsConfigurableDefine(define) ?
1115                 define.substr(1, define.length() - 2): "";
1116 }
1117 
HasConfigurableDefine(const string & define)1118 bool   SMakeProjectT::HasConfigurableDefine(const string& define)
1119 {
1120     return define.find("@") != string::npos;
1121 }
1122 
ExtractConfigurableDefine(const string & define)1123 string SMakeProjectT::ExtractConfigurableDefine (const string& define)
1124 {
1125     string::size_type start, end;
1126     start = define.find("@");
1127     end = define.find("@",start+1);
1128     if (end == string::npos) {
1129         PTB_WARNING_EX(kEmptyStr, ePTB_MacroInvalid, "Possibly incorrect MACRO definition in: " + define);
1130         return define;
1131     }
1132     return define.substr(start,end-start+1);
1133 }
1134 
1135 //-----------------------------------------------------------------------------
CreateNcbiCToolkitLibs(const CSimpleMakeFileContents & makefile,list<string> * libs_list)1136 void SAppProjectT::CreateNcbiCToolkitLibs(const CSimpleMakeFileContents& makefile,
1137                                           list<string>* libs_list)
1138 {
1139     CSimpleMakeFileContents::TContents::const_iterator k =
1140     makefile.m_Contents.find("NCBI_C_LIBS");
1141     if (k == makefile.m_Contents.end()) {
1142         return;
1143     }
1144     const list<string>& values = k->second;
1145 
1146     ITERATE(list<string>, p, values) {
1147         const string& val = *p;
1148         if ( NStr::StartsWith(val, "-l") ) {
1149             string lib_id = val.substr(2);
1150             libs_list->push_back(lib_id);
1151         } else {
1152             libs_list->push_back(val);
1153         }
1154     }
1155 
1156     libs_list->sort();
1157     libs_list->unique();
1158 }
1159 
DoCreate(const string & source_base_dir,const string & proj_name,const string & applib_mfilepath,const TFiles & makeapp,CProjectItemsTree * tree,EMakeFileType maketype)1160 CProjKey SAppProjectT::DoCreate(const string& source_base_dir,
1161                                 const string& proj_name,
1162                                 const string& applib_mfilepath,
1163                                 const TFiles& makeapp ,
1164                                 CProjectItemsTree* tree,
1165                                 EMakeFileType maketype)
1166 {
1167     CProjectItemsTree::TFiles::const_iterator m = makeapp.find(applib_mfilepath);
1168     if (m == makeapp.end()) {
1169         /// FIXME: items may not be really missing here; they may just be
1170         /// excluded based on user preference
1171         /**
1172         PTB_WARNING_EX(applib_mfilepath, ePTB_MissingMakefile,
1173                        "Makefile not found");
1174                        **/
1175         return CProjKey();
1176     }
1177 
1178     const CSimpleMakeFileContents& makefile = m->second;
1179     string full_makefile_name = CDirEntry(applib_mfilepath).GetName();
1180     string full_makefile_path = applib_mfilepath;
1181 
1182     CSimpleMakeFileContents::TContents::const_iterator k;
1183     //project id
1184     k = makefile.m_Contents.find("APP");
1185     if (k == makefile.m_Contents.end()  ||  k->second.empty()) {
1186         if (GetApp().IsScanningWholeTree()) {
1187             PTB_WARNING_EX(full_makefile_path, ePTB_InvalidMakefile,
1188                         "APP is not specified: " << full_makefile_name);
1189         } else {
1190             PTB_ERROR_EX(full_makefile_path, ePTB_InvalidMakefile,
1191                         "APP is not specified: " << full_makefile_name);
1192         }
1193         return CProjKey();
1194     }
1195     string proj_id = k->second.front();
1196     {{
1197         CProjKey proj_key(CProjKey::eApp, proj_id);
1198         CProjectItemsTree::TProjects::const_iterator z = tree->m_Projects.find(proj_key);
1199         if (z != tree->m_Projects.end()) {
1200             if (z->second.m_MakeType < eMakeType_Excluded) {
1201                 PTB_WARNING_EX(full_makefile_path, ePTB_ConfigurationError,
1202                             "Application " << proj_id << " already defined at "
1203                             << tree->m_Projects[proj_key].m_SourcesBaseDir);
1204                 if (maketype == eMakeType_Excluded || GetApp().IsScanningWholeTree()) {
1205                     return CProjKey();
1206                 } else {
1207                     GetApp().RegisterSuspiciousProject(proj_key);
1208                 }
1209             } else {
1210                 tree->m_Projects.erase(proj_key);
1211             }
1212         }
1213     }}
1214 
1215     k = makefile.m_Contents.find("SRC");
1216     if (k == makefile.m_Contents.end()) {
1217         if (GetApp().IsScanningWholeTree()) {
1218             PTB_WARNING_EX(full_makefile_path, ePTB_InvalidMakefile,
1219                         "SRC is not specified: " << full_makefile_name);
1220         } else {
1221             PTB_ERROR_EX(full_makefile_path, ePTB_InvalidMakefile,
1222                         "SRC is not specified: " << full_makefile_name);
1223         }
1224         return CProjKey();
1225     }
1226 
1227     //sources - relative  paths from source_base_dir
1228     //We'll create relative pathes from them
1229     CProjSRCResolver src_resolver(applib_mfilepath,
1230                                   source_base_dir, k->second);
1231     list<string> sources;
1232     src_resolver.ResolveTo(&sources);
1233 
1234     if (CMsvc7RegSettings::GetMsvcPlatform() >= CMsvc7RegSettings::eUnix) {
1235         k = makefile.m_Contents.find("UNIX_SRC");
1236         if (k != makefile.m_Contents.end()) {
1237             CProjSRCResolver unix_src_resolver(applib_mfilepath,
1238                                         source_base_dir, k->second);
1239             list<string> unix_sources;
1240             unix_src_resolver.ResolveTo(&unix_sources);
1241             copy(unix_sources.begin(), unix_sources.end(), back_inserter(sources));
1242         }
1243     }
1244 
1245     //depends
1246     list<string> depends;
1247     k = makefile.m_Contents.find("LIB");
1248     if (GetApp().GetBuildType().GetType() == CBuildType::eStatic) {
1249         CSimpleMakeFileContents::TContents::const_iterator tmp_k =
1250             makefile.m_Contents.find("STATIC_LIB");
1251         if (tmp_k != makefile.m_Contents.end()) {
1252             k = tmp_k;
1253         }
1254     }
1255     if (k != makefile.m_Contents.end()) {
1256 //        depends = k->second;
1257         ITERATE(list<string>, i, k->second) {
1258 #if 0
1259             depends.push_back(
1260                 NStr::Replace(NStr::Replace(*i, "-dll", kEmptyStr),
1261                               "-static", kEmptyStr));
1262 #else
1263             depends.push_back( *i);
1264 #endif
1265         }
1266     }
1267     //Adjust depends by information from msvc Makefile
1268     CMsvcProjectMakefile project_makefile( CDirEntry::ConcatPath(
1269         source_base_dir, CreateMsvcProjectMakefileName(proj_name, CProjKey::eApp)));
1270 
1271     list<string> added_depends;
1272     project_makefile.GetAdditionalLIB(SConfigInfo(), &added_depends);
1273 
1274     list<string> excluded_depends;
1275     project_makefile.GetExcludedLIB(SConfigInfo(), &excluded_depends);
1276 
1277     list<string> adj_depends(depends);
1278     copy(added_depends.begin(),
1279          added_depends.end(), back_inserter(adj_depends));
1280 
1281     PLibExclude pred(proj_name, excluded_depends);
1282     EraseIf(adj_depends, pred);
1283 
1284     list<string> expected_3party;
1285     list<CProjKey> depends_ids;
1286     SMakeProjectT::ConvertLibDepends(adj_depends, &depends_ids,
1287                                      &applib_mfilepath, &expected_3party);
1288 
1289     list<CProjKey> unconditional_depends_ids;
1290     k = m->second.m_Contents.find("USR_DEP");
1291     if (k != m->second.m_Contents.end()) {
1292         const list<string> depends = k->second;
1293         SMakeProjectT::ConvertLibDepends(depends, &unconditional_depends_ids);
1294         copy(unconditional_depends_ids.begin(),
1295              unconditional_depends_ids.end(), back_inserter(depends_ids));
1296     }
1297     k = m->second.m_Contents.find("MSVC_DEP");
1298     if (k != m->second.m_Contents.end()) {
1299         const list<string> deps = k->second;
1300         ITERATE(list<string>, p, deps) {
1301             depends_ids.push_back(CProjKey(CProjKey::eMsvc, *p));
1302         }
1303     }
1304     ///////////////////////////////////
1305 
1306     //requires
1307     list<string> requires;
1308     list<string> req_lst;
1309     if (makefile.CollectValues("REQUIRES", req_lst,
1310         CSimpleMakeFileContents::eSortUnique)) {
1311         project_makefile.Redefine(req_lst,requires);
1312     }
1313 
1314     //LIBS
1315     list<string> libs_3_party;
1316     k = makefile.m_Contents.find("LIBS");
1317     if (GetApp().GetBuildType().GetType() == CBuildType::eStatic) {
1318         CSimpleMakeFileContents::TContents::const_iterator tmp_k =
1319             makefile.m_Contents.find("STATIC_LIBS");
1320         if (tmp_k != makefile.m_Contents.end()) {
1321             k = tmp_k;
1322         }
1323     }
1324     if (k != makefile.m_Contents.end() || !expected_3party.empty()) {
1325         list<string> libs_flags;
1326         if (k != makefile.m_Contents.end()) {
1327             libs_flags = k->second;
1328         }
1329         SMakeProjectT::Create3PartyLibs(libs_flags, expected_3party, &libs_3_party, &applib_mfilepath);
1330     }
1331 
1332     //CPPFLAGS
1333     list<string> include_dirs;
1334     list<string> defines;
1335     k = makefile.m_Contents.find("CPPFLAGS");
1336     if (k != makefile.m_Contents.end()) {
1337         const list<string>& cpp_flags = k->second;
1338         SMakeProjectT::CreateIncludeDirs(cpp_flags,
1339                                          source_base_dir, &include_dirs);
1340         SMakeProjectT::CreateDefines(cpp_flags, &defines);
1341     }
1342     bool style_objcpp = false;
1343     k = makefile.m_Contents.find("CXXFLAGS");
1344     if (k != makefile.m_Contents.end()) {
1345         const list<string>& cxx_flags = k->second;
1346         style_objcpp = find(cxx_flags.begin(), cxx_flags.end(), "objective-c++") != cxx_flags.end();
1347     }
1348 
1349     //NCBI_C_LIBS - Special case for NCBI C Toolkit
1350     k = makefile.m_Contents.find("NCBI_C_LIBS");
1351     list<string> ncbi_clibs;
1352     if (k != makefile.m_Contents.end()) {
1353         libs_3_party.push_back("NCBI_C_LIBS");
1354         CreateNcbiCToolkitLibs(makefile, &ncbi_clibs);
1355     }
1356 
1357     CProjItem project(CProjKey::eApp,
1358                       proj_name,
1359                       proj_id,
1360                       source_base_dir,
1361                       sources,
1362                       depends_ids,
1363                       requires,
1364                       libs_3_party,
1365                       include_dirs,
1366                       defines,
1367                       maketype,
1368         IdentifySlnGUID(source_base_dir, CProjKey(CProjKey::eApp, proj_id)));
1369     //
1370     project.m_NcbiCLibs = ncbi_clibs;
1371     project.m_StyleObjcpp = style_objcpp;
1372     project.m_MkName = applib_mfilepath;
1373     project.m_DataSource = CSimpleMakeFileContents(applib_mfilepath);;
1374 
1375     //DATATOOL_SRC
1376     list<CDataToolGeneratedSrc> datatool_sources;
1377     k = makefile.m_Contents.find("DATATOOL_SRC");
1378     if ( k != makefile.m_Contents.end() ) {
1379         const list<string> datatool_src_list = k->second;
1380         ITERATE(list<string>, i, datatool_src_list) {
1381 
1382             const string& src = *i;
1383             //Will process .asn or .dtd files
1384             string source_file_path =
1385                 CDirEntry::ConcatPath(source_base_dir, src);
1386             source_file_path = CDirEntry::NormalizePath(source_file_path);
1387             if ( CDirEntry(source_file_path + ".asn").Exists() )
1388                 source_file_path += ".asn";
1389             else if ( CDirEntry(source_file_path + ".dtd").Exists() )
1390                 source_file_path += ".dtd";
1391             else if ( CDirEntry(source_file_path + ".xsd").Exists() )
1392                 source_file_path += ".xsd";
1393 
1394             CDataToolGeneratedSrc data_tool_src;
1395             CDataToolGeneratedSrc::LoadFrom(source_file_path, &data_tool_src);
1396             if ( !data_tool_src.IsEmpty() )
1397                 datatool_sources.push_back(data_tool_src);
1398         }
1399     }
1400     if ( !datatool_sources.empty() ) {
1401         project.m_DatatoolSources = datatool_sources;
1402         if (GetApp().m_Dtdep && !GetApp().GetDatatoolId().empty()) {
1403               project.m_Depends.push_back(CProjKey(CProjKey::eApp, GetApp().GetDatatoolId()));
1404         }
1405     }
1406 
1407 // assemble check info
1408     string check_info;
1409     string check_dir = CDirEntry::CreateRelativePath(
1410         GetApp().GetProjectTreeInfo().m_Src, source_base_dir);
1411     NStr::ReplaceInPlace(check_dir,"\\","/");
1412     if (NStr::EndsWith(check_dir,'/')) {
1413         check_dir.erase(check_dir.size()-1,1);
1414     }
1415     string check_testname(proj_name);
1416     string check_appname(proj_id);
1417 
1418     string check_copy;
1419     k = makefile.m_Contents.find("CHECK_COPY");
1420     if ( k != makefile.m_Contents.end() && !k->second.empty() ) {
1421         check_copy = NStr::Join(k->second, " ");
1422     }
1423     string check_timeout("200");
1424     k = makefile.m_Contents.find("CHECK_TIMEOUT");
1425     if ( k != makefile.m_Contents.end() && !k->second.empty() ) {
1426         check_timeout = NStr::Join(k->second, " ");
1427     }
1428     bool check_requires_ok = true;
1429     string check_requires;
1430     k = makefile.m_Contents.find("CHECK_REQUIRES");
1431     if ( k != makefile.m_Contents.end() && !k->second.empty() ) {
1432         ITERATE(list<string>, p, k->second) {
1433             if ( !GetApp().GetSite().IsProvided(*p) ) {
1434                 check_requires_ok = false;
1435                 break;
1436             }
1437         }
1438         check_requires = NStr::Join(k->second, " ");
1439     }
1440     if (check_requires_ok) {
1441         k = makefile.m_Contents.find("REQUIRES");
1442         if ( k != makefile.m_Contents.end() && !k->second.empty() ) {
1443             if (!check_requires.empty()) {
1444                 check_requires += " ";
1445             }
1446             check_requires += NStr::Join(k->second, " ");
1447         }
1448     }
1449 
1450     string check_authors;
1451     list<string> lst_authors;
1452     if (makefile.CollectValues("WATCHERS", lst_authors,
1453         CSimpleMakeFileContents::eSortUnique)) {
1454         check_authors = NStr::Join(lst_authors, " ");
1455         project.m_Watchers = check_authors;
1456     } else {
1457         k = makefile.m_Contents.find("CHECK_AUTHORS");
1458         if ( k != makefile.m_Contents.end() && !k->second.empty() ) {
1459             check_authors = NStr::Join(k->second, " ");
1460         }
1461     }
1462 
1463     k = makefile.m_Contents.find("CHECK_CMD");
1464     if ( check_requires_ok && k != makefile.m_Contents.end() ) {
1465         const list<string> check_cmd_list = k->second;
1466         string test_name("/CHECK_NAME=");
1467         ITERATE(list<string>, i, check_cmd_list) {
1468             string check_cmd(*i), check_name;
1469             string::size_type  n = check_cmd.find(test_name);
1470             if (n != string::npos) {
1471                 check_name = check_cmd.substr(n+test_name.size());
1472                 check_cmd = check_cmd.substr(0,n);
1473             }
1474             NStr::TruncateSpacesInPlace(check_cmd);
1475             CNcbiOstrstream check;
1476             check << check_dir
1477                 << s_check_separator << check_testname
1478                 << s_check_separator << check_appname
1479                 << s_check_separator << check_cmd
1480                 << s_check_separator << check_name
1481                 << s_check_separator << check_copy
1482                 << s_check_separator << check_timeout
1483                 << s_check_separator << check_requires
1484                 << s_check_separator << check_authors;
1485             project.m_CheckInfo.push_back( CNcbiOstrstreamToString(check) );
1486         }
1487     }
1488 
1489     project.m_ProjTags.push_back("exe");
1490     if (find(requires.begin(), requires.end(), "internal") == requires.end() ) {
1491         project.m_ProjTags.push_back("public");
1492     } else {
1493         project.m_ProjTags.push_back("internal");
1494     }
1495     makefile.CollectValues("PROJ_TAG", project.m_ProjTags,
1496         CSimpleMakeFileContents::eMergePlusMinus);
1497 
1498     list<string> pch_lst;
1499     if (makefile.CollectValues("USE_PCH", pch_lst,
1500         CSimpleMakeFileContents::eFirstNonempty)) {
1501         project.m_Pch = pch_lst.front();
1502     }
1503 
1504     CProjKey proj_key(CProjKey::eApp, proj_id);
1505     tree->m_Projects[proj_key] = project;
1506 
1507     return proj_key;
1508 }
1509 
1510 
1511 //-----------------------------------------------------------------------------
DoCreate(const string & source_base_dir,const string & proj_name,const string & applib_mfilepath,const TFiles & makelib,CProjectItemsTree * tree,EMakeFileType maketype)1512 CProjKey SLibProjectT::DoCreate(const string& source_base_dir,
1513                                 const string& proj_name,
1514                                 const string& applib_mfilepath,
1515                                 const TFiles& makelib ,
1516                                 CProjectItemsTree* tree,
1517                                 EMakeFileType maketype)
1518 {
1519     TFiles::const_iterator m = makelib.find(applib_mfilepath);
1520     if (m == makelib.end()) {
1521         /// FIXME: items may not be really missing here; they may just be
1522         /// excluded based on user preference
1523         /**
1524         PTB_WARNING_EX(applib_mfilepath, ePTB_MissingMakefile,
1525                        "Makefile not found");
1526                        **/
1527         return CProjKey();
1528     }
1529 
1530 //    const CSimpleMakeFileContents& makefile = m->second;
1531     string full_makefile_name = CDirEntry(applib_mfilepath).GetName();
1532     string full_makefile_path = applib_mfilepath;
1533 
1534     CSimpleMakeFileContents::TContents::const_iterator k;
1535     //project name
1536     k = m->second.m_Contents.find("LIB");
1537     if (GetApp().GetBuildType().GetType() == CBuildType::eStatic) {
1538         CSimpleMakeFileContents::TContents::const_iterator tmp_k =
1539             m->second.m_Contents.find("STATIC_LIB");
1540         if (tmp_k != m->second.m_Contents.end()) {
1541             k = tmp_k;
1542         }
1543     }
1544     if (k == m->second.m_Contents.end()  ||
1545                                            k->second.empty()) {
1546         if (GetApp().IsScanningWholeTree()) {
1547             PTB_WARNING_EX(full_makefile_path, ePTB_InvalidMakefile,
1548                         "LIB is not specified: " << full_makefile_name);
1549         } else {
1550             PTB_ERROR_EX(full_makefile_path, ePTB_InvalidMakefile,
1551                         "LIB is not specified: " << full_makefile_name);
1552         }
1553         return CProjKey();
1554     }
1555     string proj_id = k->second.front();
1556     {{
1557         CProjKey proj_key(CProjKey::eLib, proj_id);
1558         CProjectItemsTree::TProjects::const_iterator z = tree->m_Projects.find(proj_key);
1559         if (z != tree->m_Projects.end()) {
1560             if (z->second.m_MakeType < eMakeType_Excluded) {
1561                 PTB_WARNING_EX(full_makefile_path, ePTB_ConfigurationError,
1562                             "Library " << proj_id << " already defined at "
1563                             << tree->m_Projects[proj_key].m_SourcesBaseDir);
1564                 if (maketype == eMakeType_Excluded || GetApp().IsScanningWholeTree()) {
1565                     return CProjKey();
1566                 } else {
1567                     GetApp().RegisterSuspiciousProject(proj_key);
1568                 }
1569             } else {
1570                 tree->m_Projects.erase(proj_key);
1571             }
1572 
1573         }
1574     }}
1575 
1576     k = m->second.m_Contents.find("SRC");
1577     if (k == m->second.m_Contents.end()) {
1578         if (GetApp().IsScanningWholeTree()) {
1579             PTB_WARNING_EX(full_makefile_path, ePTB_InvalidMakefile,
1580                         "SRC is not specified: " << full_makefile_name);
1581         } else {
1582             PTB_ERROR_EX(full_makefile_path, ePTB_InvalidMakefile,
1583                         "SRC is not specified: " << full_makefile_name);
1584         }
1585         return CProjKey();
1586     }
1587 
1588     // sources - relative pathes from source_base_dir
1589     // We'll create relative pathes from them)
1590     CProjSRCResolver src_resolver(applib_mfilepath,
1591                                   source_base_dir, k->second);
1592     list<string> sources;
1593     src_resolver.ResolveTo(&sources);
1594 
1595     if (CMsvc7RegSettings::GetMsvcPlatform() >= CMsvc7RegSettings::eUnix) {
1596         k = m->second.m_Contents.find("UNIX_SRC");
1597         if (k != m->second.m_Contents.end()) {
1598             CProjSRCResolver unix_src_resolver(applib_mfilepath,
1599                                         source_base_dir, k->second);
1600             list<string> unix_sources;
1601             unix_src_resolver.ResolveTo(&unix_sources);
1602             copy(unix_sources.begin(), unix_sources.end(), back_inserter(sources));
1603         }
1604     }
1605 
1606     // depends
1607     list<CProjKey> depends_ids;
1608     list<CProjKey> unconditional_depends_ids;
1609     k = m->second.m_Contents.find("ASN_DEP");
1610     if (k != m->second.m_Contents.end()) {
1611         const list<string> depends = k->second;
1612         SMakeProjectT::ConvertLibDepends(depends, &unconditional_depends_ids);
1613         copy(unconditional_depends_ids.begin(),
1614              unconditional_depends_ids.end(), back_inserter(depends_ids));
1615     }
1616     k = m->second.m_Contents.find("USR_DEP");
1617     if (k != m->second.m_Contents.end()) {
1618         const list<string> depends = k->second;
1619         SMakeProjectT::ConvertLibDepends(depends, &unconditional_depends_ids);
1620         copy(unconditional_depends_ids.begin(),
1621              unconditional_depends_ids.end(), back_inserter(depends_ids));
1622     }
1623     k = m->second.m_Contents.find("MSVC_DEP");
1624     if (k != m->second.m_Contents.end()) {
1625         const list<string> deps = k->second;
1626         ITERATE(list<string>, p, deps) {
1627             depends_ids.push_back(CProjKey(CProjKey::eMsvc, *p));
1628         }
1629     }
1630 
1631     string dll_host;
1632     string lib_or_dll;
1633     k = m->second.m_Contents.find("LIB_OR_DLL");
1634     if (k != m->second.m_Contents.end()) {
1635         lib_or_dll = k->second.front();
1636     }
1637     if (NStr::CompareNocase(lib_or_dll,"dll") == 0 ||
1638         NStr::CompareNocase(lib_or_dll,"both") == 0 ||
1639         NStr::CompareNocase(lib_or_dll,"@USUAL_AND_DLL@") == 0) {
1640 		dll_host = proj_id;
1641     }
1642     bool need_dll = (!dll_host.empty() &&
1643                       GetApp().GetBuildType().GetType() == CBuildType::eDll);
1644 
1645     //requires
1646     list<string> requires;
1647     list<string> req_lst;
1648     if (m->second.CollectValues("REQUIRES",req_lst,
1649         CSimpleMakeFileContents::eSortUnique)) {
1650         CMsvcProjectMakefile project_makefile( CDirEntry::ConcatPath(
1651             source_base_dir, CreateMsvcProjectMakefileName(proj_name, CProjKey::eLib)));
1652         project_makefile.Redefine(req_lst,requires);
1653     }
1654 
1655     //CPPFLAGS
1656     list<string> include_dirs;
1657     list<string> defines;
1658     k = m->second.m_Contents.find("CPPFLAGS");
1659     if (k != m->second.m_Contents.end()) {
1660         const list<string>& cpp_flags = k->second;
1661         SMakeProjectT::CreateIncludeDirs(cpp_flags,
1662                                          source_base_dir, &include_dirs);
1663         SMakeProjectT::CreateDefines(cpp_flags, &defines);
1664 
1665     }
1666     bool style_objcpp = false;
1667     k = m->second.m_Contents.find("CXXFLAGS");
1668     if (k != m->second.m_Contents.end()) {
1669         const list<string>& cxx_flags = k->second;
1670         style_objcpp = find(cxx_flags.begin(), cxx_flags.end(), "objective-c++") != cxx_flags.end();
1671     }
1672 
1673     bool isbundle = false;
1674     k = m->second.m_Contents.find("DLL_TYPE");
1675     if (k != m->second.m_Contents.end() && k->second.front() == "plugin") {
1676         isbundle = true;
1677     }
1678 //    if (!lib_or_dll.empty() ||
1679 //        CMsvc7RegSettings::GetMsvcPlatform() >= CMsvc7RegSettings::eUnix) {
1680 //        if (GetApp().GetBuildType().GetType() == CBuildType::eDll) {
1681             list<string> dll_depends;
1682             k = m->second.m_Contents.find("DLL_LIB");
1683             if (GetApp().m_AllDllBuild) {
1684                 CSimpleMakeFileContents::TContents::const_iterator tmp_k =
1685                     m->second.m_Contents.find("DLL_DLIB");
1686                 if (tmp_k != m->second.m_Contents.end()) {
1687                     k = tmp_k;
1688                 }
1689             }
1690             if (k != m->second.m_Contents.end()) {
1691                 ITERATE(list<string>, i, k->second) {
1692 #if 0
1693                     dll_depends.push_back(
1694                         NStr::Replace(NStr::Replace(*i, "-dll", kEmptyStr),
1695                               "-static", kEmptyStr));
1696 #else
1697                     dll_depends.push_back(*i);
1698 #endif
1699                 }
1700             }
1701             list<string> expected_3party;
1702             list<CProjKey> dll_depends_ids;
1703             SMakeProjectT::ConvertLibDepends(dll_depends, &dll_depends_ids,
1704                 need_dll ? &applib_mfilepath : NULL,
1705                 need_dll ? &expected_3party  : NULL);
1706             copy(dll_depends_ids.begin(),
1707                     dll_depends_ids.end(),
1708                     back_inserter(depends_ids));
1709 //        }
1710 //    }
1711 
1712     //LIBS
1713     list<string> libs_3_party;
1714     k = m->second.m_Contents.find("LIBS");
1715     if (GetApp().GetBuildType().GetType() == CBuildType::eStatic) {
1716         CSimpleMakeFileContents::TContents::const_iterator tmp_k =
1717             m->second.m_Contents.find("STATIC_LIBS");
1718         if (tmp_k != m->second.m_Contents.end()) {
1719             k = tmp_k;
1720         }
1721     }
1722     if (k != m->second.m_Contents.end() || !expected_3party.empty()) {
1723         list<string> libs_flags;
1724         if (k != m->second.m_Contents.end()) {
1725             libs_flags = k->second;
1726         }
1727         SMakeProjectT::Create3PartyLibs(libs_flags, expected_3party, &libs_3_party,
1728             need_dll ? &applib_mfilepath : NULL);
1729     }
1730 
1731     CProjKey proj_key(CProjKey::eLib, proj_id);
1732     tree->m_Projects[proj_key] = CProjItem(CProjKey::eLib,
1733                                            proj_name,
1734                                            proj_id,
1735                                            source_base_dir,
1736                                            sources,
1737                                            depends_ids,
1738                                            requires,
1739                                            libs_3_party,
1740                                            include_dirs,
1741                                            defines,
1742                                            maketype,
1743         IdentifySlnGUID(source_base_dir, proj_key));
1744     (tree->m_Projects[proj_key]).m_StyleObjcpp = style_objcpp;
1745     (tree->m_Projects[proj_key]).m_MkName = applib_mfilepath;
1746     (tree->m_Projects[proj_key]).m_DataSource = CSimpleMakeFileContents(applib_mfilepath);
1747     if (CDirEntry(full_makefile_name).GetExt() == ".metal") {
1748         (tree->m_Projects[proj_key]).m_IsMetallib = true;
1749     }
1750 
1751     k = m->second.m_Contents.find("HEADER_EXPORT");
1752     if (k != m->second.m_Contents.end()) {
1753         (tree->m_Projects[proj_key]).m_ExportHeaders = k->second;
1754     }
1755     k = m->second.m_Contents.find("PACKAGE_EXPORT");
1756     if (k != m->second.m_Contents.end()) {
1757         (tree->m_Projects[proj_key]).m_ExportHeadersDest = k->second.front();
1758     }
1759     list<string> lst_watchers;
1760     if (m->second.CollectValues("WATCHERS", lst_watchers,
1761         CSimpleMakeFileContents::eSortUnique)) {
1762         tree->m_Projects[proj_key].m_Watchers = NStr::Join(lst_watchers, " ");
1763     }
1764 
1765     tree->m_Projects[proj_key].m_ProjTags.push_back("lib");
1766     if (find(requires.begin(), requires.end(), "internal") == requires.end() ) {
1767         tree->m_Projects[proj_key].m_ProjTags.push_back("public");
1768     } else {
1769         tree->m_Projects[proj_key].m_ProjTags.push_back("internal");
1770     }
1771     m->second.CollectValues("PROJ_TAG", tree->m_Projects[proj_key].m_ProjTags,
1772         CSimpleMakeFileContents::eMergePlusMinus);
1773 
1774     list<string> pch_lst;
1775     if (m->second.CollectValues("USE_PCH", pch_lst,
1776         CSimpleMakeFileContents::eFirstNonempty)) {
1777         tree->m_Projects[proj_key].m_Pch = pch_lst.front();
1778     }
1779 
1780     if (!dll_host.empty() && GetApp().GetBuildType().GetType() == CBuildType::eDll) {
1781         tree->m_Projects[proj_key].m_DllHost = dll_host;
1782         CProjKey proj_dll(CProjKey::eDll, dll_host);
1783         if (tree->m_Projects.find(proj_dll) == tree->m_Projects.end()) {
1784         CProjItem item_dll = tree->m_Projects[proj_dll];
1785         item_dll.m_ProjType = CProjKey::eDll;
1786 #if 0
1787         item_dll.m_Name = dll_host;
1788         item_dll.m_ID = dll_host;
1789 #else
1790         item_dll.m_Name = proj_name;
1791         item_dll.m_ID = proj_id;
1792 #endif
1793         item_dll.m_SourcesBaseDir = source_base_dir;
1794         item_dll.m_MakeType = maketype;
1795         item_dll.m_HostedLibs.push_back(proj_id);
1796         item_dll.m_GUID  = IdentifySlnGUID(source_base_dir, proj_dll);
1797         item_dll.m_IsBundle = isbundle;
1798         item_dll.m_External = true;
1799         item_dll.m_StyleObjcpp = style_objcpp;
1800         item_dll.m_MkName = applib_mfilepath;
1801         item_dll.m_DataSource = CSimpleMakeFileContents(applib_mfilepath);
1802         item_dll.m_ProjTags = tree->m_Projects[proj_key].m_ProjTags;
1803         item_dll.m_ProjTags.push_back("dll");
1804         tree->m_Projects[proj_dll] = item_dll;
1805         }
1806     }
1807     ITERATE(list<CProjKey>, u,  unconditional_depends_ids) {
1808         (tree->m_Projects[proj_key]).m_UnconditionalDepends.insert( *u);
1809     }
1810     return proj_key;
1811 }
1812 
DoCreateDataSpec(const string & source_base_dir,const string & proj_name,const string & proj_id,CProjectItemsTree * tree,EMakeFileType maketype)1813 CProjKey SLibProjectT::DoCreateDataSpec(
1814             const string& source_base_dir,
1815             const string& proj_name,
1816             const string& proj_id,
1817             CProjectItemsTree* tree,
1818             EMakeFileType maketype)
1819 {
1820     string spec_proj_name = proj_name;
1821     string spec_proj_id   = proj_id;
1822 
1823     list<string>   s_empty;
1824     list<CProjKey> d_empty;
1825     CProjKey::TProjType type = CProjKey::eDataSpec;
1826     CProjKey proj_key(type, spec_proj_id);
1827     tree->m_Projects[proj_key] = CProjItem(type,
1828                                            spec_proj_name,
1829                                            spec_proj_id,
1830                                            source_base_dir,
1831                                            s_empty,
1832                                            d_empty,
1833                                            s_empty,
1834                                            s_empty,
1835                                            s_empty,
1836                                            s_empty,
1837                                            maketype,
1838         IdentifySlnGUID(source_base_dir, proj_key));
1839     return proj_key;
1840 }
1841 
CreateUtilityProjectItem(const string & prj_dir,const string & name)1842 CProjItem CreateUtilityProjectItem( const string& prj_dir, const string& name)
1843 {
1844     string spec_proj_name = name;
1845     string spec_proj_id   = NStr::Replace(name, "-", "_");
1846 
1847     list<string>   s_empty;
1848     list<CProjKey> d_empty;
1849     CProjKey::TProjType type = CProjKey::eUtility;
1850     CProjKey proj_key(type, spec_proj_id);
1851     return CProjItem(type,
1852                 spec_proj_name,
1853                 spec_proj_id,
1854                 prj_dir,
1855                 s_empty,
1856                 d_empty,
1857                 s_empty,
1858                 s_empty,
1859                 s_empty,
1860                 s_empty,
1861                 eMakeType_Undefined,
1862                 IdentifySlnGUID(prj_dir, proj_key));
1863 }
1864 
1865 //-----------------------------------------------------------------------------
DoCreate(const string & source_base_dir,const string & proj_name,const string & applib_mfilepath,const TFiles & makedll,CProjectItemsTree * tree,EMakeFileType maketype)1866 CProjKey SDllProjectT::DoCreate(const string& source_base_dir,
1867                                 const string& proj_name,
1868                                 const string& applib_mfilepath,
1869                                 const TFiles& makedll ,
1870                                 CProjectItemsTree* tree,
1871                                 EMakeFileType maketype)
1872 {
1873     TFiles::const_iterator m = makedll.find(applib_mfilepath);
1874     if (m == makedll.end()) {
1875 
1876         PTB_WARNING_EX(kEmptyStr, ePTB_ProjectNotFound, "Dll Makefile not found: " << applib_mfilepath);
1877         return CProjKey();
1878     }
1879     CSimpleMakeFileContents::TContents::const_iterator k;
1880 
1881     //DLL
1882     k = m->second.m_Contents.find("DLL");
1883     if (k == m->second.m_Contents.end()  ||
1884                                            k->second.empty()) {
1885         PTB_WARNING_EX(kEmptyStr, ePTB_ConfigurationError, "No DLL specified in Makefile." << proj_name
1886                       << ".dll  at " << applib_mfilepath);
1887         return CProjKey();
1888     }
1889     string proj_id = k->second.front();
1890     {{
1891         CProjKey proj_key(CProjKey::eDll, proj_id);
1892         CProjectItemsTree::TProjects::const_iterator z = tree->m_Projects.find(proj_key);
1893         if (z != tree->m_Projects.end()) {
1894             if (z->second.m_MakeType < eMakeType_Excluded) {
1895                 const CProjItem& item = tree->m_Projects[proj_key];
1896                 if (item.m_HostedLibs.size() != 1 || item.m_HostedLibs.front() != proj_id) {
1897                     string full_makefile_path = applib_mfilepath;
1898                     PTB_WARNING_EX(full_makefile_path, ePTB_ConfigurationError,
1899                                 "DLL " << proj_id << " already defined at "
1900                                 << tree->m_Projects[proj_key].m_SourcesBaseDir);
1901                     if (maketype == eMakeType_Excluded || GetApp().IsScanningWholeTree()) {
1902                         return CProjKey();
1903                     } else {
1904                         GetApp().RegisterSuspiciousProject(proj_key);
1905                     }
1906                 }
1907             } else {
1908                 tree->m_Projects.erase(proj_key);
1909             }
1910         }
1911     }}
1912 
1913     //CPPFLAGS
1914     list<string> include_dirs;
1915     list<string> defines;
1916     k = m->second.m_Contents.find("CPPFLAGS");
1917     if (k != m->second.m_Contents.end()) {
1918         const list<string>& cpp_flags = k->second;
1919         SMakeProjectT::CreateIncludeDirs(cpp_flags,
1920                                          source_base_dir, &include_dirs);
1921         SMakeProjectT::CreateDefines(cpp_flags, &defines);
1922 
1923     }
1924     bool style_objcpp = false;
1925     k = m->second.m_Contents.find("CXXFLAGS");
1926     if (k != m->second.m_Contents.end()) {
1927         const list<string>& cxx_flags = k->second;
1928         style_objcpp = find(cxx_flags.begin(), cxx_flags.end(), "objective-c++") != cxx_flags.end();
1929     }
1930 
1931     list<CProjKey> depends_ids;
1932     k = m->second.m_Contents.find("DEPENDENCIES");
1933     if (k != m->second.m_Contents.end()) {
1934         const list<string> depends = k->second;
1935         SMakeProjectT::ConvertLibDepends(depends, &depends_ids /*, &applib_mfilepath*/);
1936     }
1937 
1938     list<string> requires;
1939     requires.push_back("DLL");
1940 
1941     list<string> sources;
1942     list<string> libs_3_party;
1943 
1944     CProjKey proj_key(CProjKey::eDll, proj_id);
1945     tree->m_Projects[proj_key] = CProjItem(CProjKey::eDll,
1946                                            proj_name,
1947                                            proj_id,
1948                                            source_base_dir,
1949                                            sources,
1950                                            depends_ids,
1951                                            requires,
1952                                            libs_3_party,
1953                                            include_dirs,
1954                                            defines,
1955                                            maketype,
1956         IdentifySlnGUID(source_base_dir, proj_key));
1957     tree->m_Projects[proj_key].m_External = true;
1958     tree->m_Projects[proj_key].m_StyleObjcpp = style_objcpp;
1959     tree->m_Projects[proj_key].m_MkName = applib_mfilepath;
1960     tree->m_Projects[proj_key].m_DataSource = CSimpleMakeFileContents(applib_mfilepath);;
1961 
1962     k = m->second.m_Contents.find("HOSTED_LIBS");
1963     if (k != m->second.m_Contents.end()) {
1964         tree->m_Projects[proj_key].m_HostedLibs = k->second;
1965     }
1966     k = m->second.m_Contents.find("DLL_TYPE");
1967     if (k != m->second.m_Contents.end() && k->second.front() == "plugin") {
1968         tree->m_Projects[proj_key].m_IsBundle = true;
1969     }
1970     list<string> lst_watchers;
1971     if (m->second.CollectValues("WATCHERS", lst_watchers,
1972         CSimpleMakeFileContents::eSortUnique)) {
1973         tree->m_Projects[proj_key].m_Watchers = NStr::Join(lst_watchers, " ");
1974     }
1975     tree->m_Projects[proj_key].m_ProjTags.push_back("dll");
1976     m->second.CollectValues("PROJ_TAG", tree->m_Projects[proj_key].m_ProjTags,
1977         CSimpleMakeFileContents::eMergePlusMinus);
1978     return proj_key;
1979 }
1980 
1981 //-----------------------------------------------------------------------------
DoCreate(const string & source_base_dir,const string & proj_name,const string & applib_mfilepath,const TFiles & makeapp,const TFiles & makelib,CProjectItemsTree * tree,const SMakeProjectT::SMakeInInfo & makeinfo)1982 CProjKey SAsnProjectT::DoCreate(const string& source_base_dir,
1983                                 const string& proj_name,
1984                                 const string& applib_mfilepath,
1985                                 const TFiles& makeapp,
1986                                 const TFiles& makelib,
1987                                 CProjectItemsTree* tree,
1988                                 const SMakeProjectT::SMakeInInfo& makeinfo)
1989 {
1990     TAsnType asn_type = GetAsnProjectType(applib_mfilepath, makeapp, makelib);
1991     if (asn_type == eMultiple) {
1992         return SAsnProjectMultipleT::DoCreate(source_base_dir,
1993                                               proj_name,
1994                                               applib_mfilepath,
1995                                               makeapp,
1996                                               makelib,
1997                                               tree, makeinfo);
1998     }
1999     if(asn_type == eSingle) {
2000         return SAsnProjectSingleT::DoCreate(source_base_dir,
2001                                               proj_name,
2002                                               applib_mfilepath,
2003                                               makeapp,
2004                                               makelib,
2005                                               tree, makeinfo);
2006     }
2007     return CProjKey();
2008 }
2009 
2010 
GetAsnProjectType(const string & applib_mfilepath,const TFiles & makeapp,const TFiles & makelib)2011 SAsnProjectT::TAsnType SAsnProjectT::GetAsnProjectType(const string& applib_mfilepath,
2012                                                        const TFiles& makeapp,
2013                                                        const TFiles& makelib)
2014 {
2015     TFiles::const_iterator p = makeapp.find(applib_mfilepath);
2016     if ( p != makeapp.end() ) {
2017         const CSimpleMakeFileContents& fc = p->second;
2018         if (fc.m_Contents.find("ASN") != fc.m_Contents.end() )
2019             return eMultiple;
2020         else
2021             return eSingle;
2022     }
2023 
2024     p = makelib.find(applib_mfilepath);
2025     if ( p != makelib.end() ) {
2026         const CSimpleMakeFileContents& fc = p->second;
2027         if (fc.m_Contents.find("ASN") != fc.m_Contents.end() )
2028             return eMultiple;
2029         else
2030             return eSingle;
2031     }
2032     return eNoAsn;
2033 }
2034 
2035 
2036 //-----------------------------------------------------------------------------
DoCreate(const string & source_base_dir,const string & proj_name,const string & applib_mfilepath,const TFiles & makeapp,const TFiles & makelib,CProjectItemsTree * tree,const SMakeProjectT::SMakeInInfo & makeinfo)2037 CProjKey SAsnProjectSingleT::DoCreate(const string& source_base_dir,
2038                                       const string& proj_name,
2039                                       const string& applib_mfilepath,
2040                                       const TFiles& makeapp,
2041                                       const TFiles& makelib,
2042                                       CProjectItemsTree* tree,
2043                                       const SMakeProjectT::SMakeInInfo& makeinfo)
2044 {
2045     EMakeFileType maketype = makeinfo.m_MakeType;
2046     CProjItem::TProjType proj_type =
2047         IsMakeLibFile( CDirEntry(applib_mfilepath).GetName()) ? CProjKey::eLib : CProjKey::eApp;
2048 
2049     CProjKey proj_id =
2050         proj_type == CProjKey::eLib?
2051             SLibProjectT::DoCreate(source_base_dir,
2052                                proj_name, applib_mfilepath, makelib, tree, maketype) :
2053             SAppProjectT::DoCreate(source_base_dir,
2054                                proj_name, applib_mfilepath, makeapp, tree, maketype);
2055     if ( proj_id.Id().empty() )
2056         return CProjKey();
2057 
2058     TProjects::iterator p = tree->m_Projects.find(proj_id);
2059     if (p == tree->m_Projects.end()) {
2060         PTB_ERROR_EX(kEmptyStr, ePTB_ProjectNotFound, "ASN project not found: " + proj_id.Id());
2061         return CProjKey();
2062     }
2063     CProjItem& project = p->second;
2064 
2065     //Will process .asn or .dtd files
2066     string source_file_path = CDirEntry::ConcatPath(source_base_dir, proj_name);
2067     switch (makeinfo.m_Type) {
2068     case SMakeProjectT::SMakeInInfo::eASN:
2069         if ( CDirEntry(source_file_path + ".asn").Exists() )
2070             source_file_path += ".asn";
2071         break;
2072     case SMakeProjectT::SMakeInInfo::eDTD:
2073         if ( CDirEntry(source_file_path + ".dtd").Exists() )
2074             source_file_path += ".dtd";
2075         break;
2076     case SMakeProjectT::SMakeInInfo::eXSD:
2077         if ( CDirEntry(source_file_path + ".xsd").Exists() )
2078             source_file_path += ".xsd";
2079         break;
2080     case SMakeProjectT::SMakeInInfo::eWSDL:
2081         if ( CDirEntry(source_file_path + ".wsdl").Exists() )
2082             source_file_path += ".wsdl";
2083         break;
2084     case SMakeProjectT::SMakeInInfo::eJSD:
2085         if ( CDirEntry(source_file_path + ".jsd").Exists() )
2086             source_file_path += ".jsd";
2087         break;
2088     case SMakeProjectT::SMakeInInfo::eProtobuf:
2089         if ( CDirEntry(source_file_path + ".proto").Exists() )
2090             source_file_path += ".proto";
2091         break;
2092     default:
2093         break;
2094     }
2095     if ( !CDirEntry(source_file_path).Exists() ) {
2096         ERR_POST(
2097             (GetApp().IsScanningWholeTree() ? Warning : Error)
2098              << MDiagFile(kEmptyStr)
2099             << "Data specification for ASN project not found: " << source_file_path);
2100         return CProjKey();
2101     }
2102 
2103     CDataToolGeneratedSrc data_tool_src;
2104     CDataToolGeneratedSrc::LoadFrom(source_file_path, &data_tool_src);
2105     if ( !data_tool_src.IsEmpty()) {
2106         project.m_DatatoolSources.push_back(data_tool_src);
2107         if (GetApp().m_Dtdep && !GetApp().GetDatatoolId().empty() && makeinfo.m_Type != SMakeProjectT::SMakeInInfo::eProtobuf) {
2108               project.m_Depends.push_back(CProjKey(CProjKey::eApp, GetApp().GetDatatoolId()));
2109         }
2110         if (makeinfo.m_Type == SMakeProjectT::SMakeInInfo::eProtobuf) {
2111             string rel_path = CDirEntry::CreateRelativePath(GetApp().GetProjectTreeInfo().m_Src, source_base_dir);
2112             string incl_path = CDirEntry::NormalizePath( CDirEntry::ConcatPath(GetApp().GetProjectTreeInfo().m_Include, rel_path));
2113             project.m_IncludeDirs.push_back(incl_path);
2114             project.m_Pch = "FALSE";
2115         }
2116     }
2117 
2118     return proj_id;
2119 }
2120 
2121 
2122 //-----------------------------------------------------------------------------
DoCreate(const string & source_base_dir,const string & proj_name,const string & applib_mfilepath,const TFiles & makeapp,const TFiles & makelib,CProjectItemsTree * tree,const SMakeProjectT::SMakeInInfo & makeinfo)2123 CProjKey SAsnProjectMultipleT::DoCreate(const string& source_base_dir,
2124                                         const string& proj_name,
2125                                         const string& applib_mfilepath,
2126                                         const TFiles& makeapp,
2127                                         const TFiles& makelib,
2128                                         CProjectItemsTree* tree,
2129                                         const SMakeProjectT::SMakeInInfo& makeinfo)
2130 {
2131     EMakeFileType maketype = makeinfo.m_MakeType;
2132     CProjItem::TProjType proj_type =
2133         IsMakeLibFile( CDirEntry(applib_mfilepath).GetName()) ? CProjKey::eLib : CProjKey::eApp;
2134 
2135 
2136     const TFiles& makefile = proj_type == CProjKey::eLib? makelib : makeapp;
2137     TFiles::const_iterator m = makefile.find(applib_mfilepath);
2138     if (m == makefile.end()) {
2139 
2140         PTB_WARNING_EX(kEmptyStr, ePTB_ProjectNotFound, "AsnProject Makefile not found: " << applib_mfilepath);
2141         return CProjKey();
2142     }
2143     const CSimpleMakeFileContents& fc = m->second;
2144 
2145     // ASN
2146     CSimpleMakeFileContents::TContents::const_iterator k =
2147         fc.m_Contents.find("ASN");
2148     if (k == fc.m_Contents.end()) {
2149 
2150         PTB_WARNING_EX(kEmptyStr, ePTB_ConfigurationError, "No ASN specified in Makefile: project " << proj_name
2151                       << "  at " << applib_mfilepath);
2152         return CProjKey();
2153     }
2154     const list<string> asn_names = k->second;
2155 
2156     list<CDataToolGeneratedSrc> datatool_sources;
2157     ITERATE(list<string>, p, asn_names) {
2158         const string& asn = *p;
2159 
2160         // this dir
2161         string asn_path_abs = CDirEntry::NormalizePath(source_base_dir);
2162         asn_path_abs = CDirEntry::AddTrailingPathSeparator(asn_path_abs);
2163         asn_path_abs = CDirEntry::ConcatPath(asn_path_abs, asn);
2164         if ( CDirEntry(asn_path_abs + ".asn").Exists() )
2165             asn_path_abs += ".asn";
2166         else if ( CDirEntry(asn_path_abs + ".dtd").Exists() )
2167             asn_path_abs += ".dtd";
2168         else if ( CDirEntry(asn_path_abs + ".xsd").Exists() )
2169             asn_path_abs += ".xsd";
2170         else {
2171             // one level up
2172             string parent_dir_abs = ParentDir(source_base_dir);
2173             string asn_dir_abs = CDirEntry::ConcatPath(parent_dir_abs, asn);
2174             asn_dir_abs = CDirEntry::NormalizePath(asn_dir_abs);
2175             asn_dir_abs = CDirEntry::AddTrailingPathSeparator(asn_dir_abs);
2176 
2177             asn_path_abs = CDirEntry::ConcatPath(asn_dir_abs, asn);
2178             if ( CDirEntry(asn_path_abs + ".asn").Exists() )
2179                 asn_path_abs += ".asn";
2180             else if ( CDirEntry(asn_path_abs + ".dtd").Exists() )
2181                 asn_path_abs += ".dtd";
2182             else if ( CDirEntry(asn_path_abs + ".xsd").Exists() )
2183                 asn_path_abs += ".xsd";
2184             else {
2185                 // one level down
2186                 string asn_dir_abs = CDirEntry::ConcatPath(source_base_dir, asn);
2187                 asn_dir_abs = CDirEntry::NormalizePath(asn_dir_abs);
2188                 asn_dir_abs = CDirEntry::AddTrailingPathSeparator(asn_dir_abs);
2189 
2190                 asn_path_abs = CDirEntry::ConcatPath(asn_dir_abs, asn);
2191                 if ( CDirEntry(asn_path_abs + ".asn").Exists() )
2192                     asn_path_abs += ".asn";
2193                 else if ( CDirEntry(asn_path_abs + ".dtd").Exists() )
2194                     asn_path_abs += ".dtd";
2195                 else if ( CDirEntry(asn_path_abs + ".xsd").Exists() )
2196                     asn_path_abs += ".xsd";
2197                 else {
2198                     PTB_ERROR_EX(asn_path_abs, ePTB_FileNotFound,
2199                                 "ASN spec file not found");
2200                 }
2201             }
2202         }
2203 
2204         CDataToolGeneratedSrc data_tool_src;
2205         CDataToolGeneratedSrc::LoadFrom(asn_path_abs, &data_tool_src);
2206         if ( !data_tool_src.IsEmpty() )
2207             datatool_sources.push_back(data_tool_src);
2208 
2209     }
2210 
2211     // SRC
2212     k = fc.m_Contents.find("SRC");
2213     if (k == fc.m_Contents.end()) {
2214 
2215         PTB_WARNING_EX(kEmptyStr, ePTB_ConfigurationError, "No SRC specified in Makefile: project " << proj_name
2216                       << "  at " << applib_mfilepath);
2217         return CProjKey();
2218     }
2219     list<string> src_list = k->second;
2220     if (CMsvc7RegSettings::GetMsvcPlatform() >= CMsvc7RegSettings::eUnix) {
2221         k = fc.m_Contents.find("UNIX_SRC");
2222         if (k != fc.m_Contents.end()) {
2223             copy(k->second.begin(), k->second.end(), back_inserter(src_list));
2224         }
2225     }
2226     list<string> sources;
2227     ITERATE(list<string>, p, src_list) {
2228         const string& src = *p;
2229         if ( !CSymResolver::IsDefine(src) )
2230             sources.push_back(src);
2231     }
2232 
2233     CProjKey proj_id =
2234         proj_type == CProjKey::eLib?
2235         SLibProjectT::DoCreate(source_base_dir,
2236                                proj_name, applib_mfilepath, makelib, tree, maketype) :
2237         SAppProjectT::DoCreate(source_base_dir,
2238                                proj_name, applib_mfilepath, makeapp, tree, maketype);
2239     if ( proj_id.Id().empty() )
2240         return CProjKey();
2241 
2242     TProjects::iterator pid = tree->m_Projects.find(proj_id);
2243     if (pid == tree->m_Projects.end()) {
2244         PTB_WARNING_EX(kEmptyStr, ePTB_ProjectNotFound, "ASN project not found: " << proj_id.Id()
2245                        << " at " << applib_mfilepath);
2246         return CProjKey();
2247     }
2248     CProjItem& project = pid->second;
2249 
2250     // Adjust created proj item
2251     //SRC -
2252     project.m_Sources.clear();
2253     ITERATE(list<string>, p, src_list) {
2254         const string& src = *p;
2255         if ( !CSymResolver::IsDefine(src) )
2256             project.m_Sources.push_front(src);
2257     }
2258     ITERATE( list<CDataToolGeneratedSrc>, dts, datatool_sources) {
2259         const string& asn = dts->m_SourceCPP;
2260         project.m_Sources.remove(asn);
2261         project.m_Sources.remove(asn + "__");
2262         project.m_Sources.remove(asn + "___");
2263         string src = CDirEntry::ConcatPath(CDirEntry::CreateRelativePath( source_base_dir, dts->m_SourceBaseDir), asn);
2264         project.m_Sources.push_back(src + "__");
2265         project.m_Sources.push_back(src + "___");
2266     }
2267 
2268     if ( !datatool_sources.empty() ) {
2269         project.m_DatatoolSources = datatool_sources;
2270         if (GetApp().m_Dtdep && !GetApp().GetDatatoolId().empty()) {
2271               project.m_Depends.push_back(CProjKey(CProjKey::eApp, GetApp().GetDatatoolId()));
2272         }
2273     }
2274 
2275     return proj_id;
2276 }
2277 
2278 //-----------------------------------------------------------------------------
DoCreate(const string & source_base_dir,const string & proj_name,const string & applib_mfilepath,const TFiles & makemsvc,CProjectItemsTree * tree,EMakeFileType maketype)2279 CProjKey SMsvcProjectT::DoCreate(const string&      source_base_dir,
2280                                  const string&      proj_name,
2281                                  const string&      applib_mfilepath,
2282                                  const TFiles&      makemsvc,
2283                                  CProjectItemsTree* tree,
2284                                  EMakeFileType maketype)
2285 {
2286     TFiles::const_iterator m = makemsvc.find(applib_mfilepath);
2287     if (m == makemsvc.end()) {
2288 
2289         PTB_WARNING_EX(kEmptyStr, ePTB_ProjectNotFound, "Native Makefile not found: " << applib_mfilepath);
2290         return CProjKey();
2291     }
2292 
2293     CSimpleMakeFileContents::TContents::const_iterator k;
2294     //project id
2295     string proj_id;
2296     if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eUnix) {
2297         proj_id = proj_name;
2298     } else {
2299         bool is_xcode = CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eXCode;
2300         k = m->second.m_Contents.find(is_xcode ? "XCODE_PROJ" : "MSVC_PROJ");
2301         if (k == m->second.m_Contents.end()  ||
2302                                                k->second.empty()) {
2303 
2304             PTB_WARNING_EX(kEmptyStr, ePTB_ConfigurationError, "No MSVC_PROJ specified in Makefile: project " << proj_name
2305                           << "  at " << applib_mfilepath);
2306             return CProjKey();
2307         }
2308         proj_id = k->second.front();
2309     }
2310     {{
2311         CProjKey proj_key(CProjKey::eMsvc, proj_id);
2312         CProjectItemsTree::TProjects::const_iterator z = tree->m_Projects.find(proj_key);
2313         if (z != tree->m_Projects.end()) {
2314             if (z->second.m_MakeType < eMakeType_Excluded) {
2315                 string full_makefile_path = applib_mfilepath;
2316                 PTB_WARNING_EX(full_makefile_path, ePTB_ConfigurationError,
2317                             "Native project \'" << proj_id << "\' already defined at "
2318                             << tree->m_Projects[proj_key].m_SourcesBaseDir);
2319                 if (maketype == eMakeType_Excluded || GetApp().IsScanningWholeTree()) {
2320                     return CProjKey();
2321                 } else {
2322                     GetApp().RegisterSuspiciousProject(proj_key);
2323                 }
2324             } else {
2325                 tree->m_Projects.erase(proj_key);
2326             }
2327         }
2328     }}
2329 
2330     string vcproj_file;
2331     list<string> sources;
2332     if (CMsvc7RegSettings::GetMsvcPlatform() != CMsvc7RegSettings::eUnix &&
2333         CMsvc7RegSettings::GetMsvcPlatform() != CMsvc7RegSettings::eXCode) {
2334         // VCPROJ - will map to src
2335         string vcproj_key("VCPROJ");
2336         if (CMsvc7RegSettings::GetMsvcVersion() >= CMsvc7RegSettings::eMsvc1000) {
2337             vcproj_key = "VCXPROJ";
2338         }
2339         k = m->second.m_Contents.find(vcproj_key);
2340         if (k == m->second.m_Contents.end()) {
2341 
2342             PTB_WARNING_EX(kEmptyStr, ePTB_ConfigurationError, "No " << vcproj_key <<" specified in Makefile: project " << proj_name
2343                           << "  at " << applib_mfilepath);
2344             return CProjKey();
2345         }
2346         ITERATE(list<string>, s, k->second) {
2347             string d = GetApp().ProcessLocationMacros( *s );
2348             vcproj_file = d;
2349             if (CDirEntry::IsAbsolutePath(d)) {
2350                 d = CDirEntry::CreateRelativePath( source_base_dir, d);
2351             }
2352             sources.push_back( d );
2353             break;
2354         }
2355     }
2356 
2357     // depends -
2358     list<CProjKey> depends_ids;
2359     k = m->second.m_Contents.find("LIB_DEP");
2360     if (k != m->second.m_Contents.end()) {
2361         const list<string> deps = k->second;
2362         ITERATE(list<string>, p, deps) {
2363             depends_ids.push_back(CProjKey(CProjKey::eLib, *p));
2364         }
2365     }
2366     k = m->second.m_Contents.find("APP_DEP");
2367     if (k != m->second.m_Contents.end()) {
2368         const list<string> deps = k->second;
2369         ITERATE(list<string>, p, deps) {
2370             depends_ids.push_back(CProjKey(CProjKey::eApp, *p));
2371         }
2372     }
2373     k = m->second.m_Contents.find("DLL_DEP");
2374     if (k != m->second.m_Contents.end()) {
2375         const list<string> deps = k->second;
2376         ITERATE(list<string>, p, deps) {
2377             depends_ids.push_back(CProjKey(CProjKey::eDll, *p));
2378         }
2379     }
2380     k = m->second.m_Contents.find("MSVC_DEP");
2381     if (k != m->second.m_Contents.end()) {
2382         const list<string> deps = k->second;
2383         ITERATE(list<string>, p, deps) {
2384             depends_ids.push_back(CProjKey(CProjKey::eMsvc, *p));
2385         }
2386     }
2387     k = m->second.m_Contents.find("USR_DEP");
2388     if (k != m->second.m_Contents.end()) {
2389         const list<string> deps = k->second;
2390         list<CProjKey> ids;
2391         SMakeProjectT::ConvertLibDepends(deps, &ids);
2392         copy(ids.begin(), ids.end(), back_inserter(depends_ids));
2393     }
2394 
2395     //requires
2396     list<string> requires;
2397     list<string> req_lst;
2398     if (m->second.CollectValues("REQUIRES", req_lst,
2399         CSimpleMakeFileContents::eSortUnique)) {
2400         CMsvcProjectMakefile project_makefile( CDirEntry::ConcatPath(
2401             source_base_dir, CreateMsvcProjectMakefileName(proj_name, CProjKey::eMsvc)));
2402         project_makefile.Redefine(req_lst,requires);
2403     }
2404 
2405     list<string> libs_3_party;
2406     list<string> include_dirs;
2407     list<string> defines;
2408 
2409     CMsvcProjectMakefile project_makefile
2410                        ((CDirEntry::ConcatPath( source_base_dir,
2411                            CreateMsvcProjectMakefileName(proj_name,
2412                                                          CProjKey::eMsvc))));
2413     CProjKey proj_key(CProjKey::eMsvc, proj_id);
2414     CProjItem project(CProjKey::eMsvc,
2415                        proj_name,
2416                        proj_id,
2417                        source_base_dir,
2418                        sources,
2419                        depends_ids,
2420                        requires,
2421                        libs_3_party,
2422                        include_dirs,
2423                        defines,
2424                        maketype,
2425         IdentifySlnGUID(vcproj_file, proj_key));
2426 
2427     m->second.CollectValues("PROJ_TAG", project.m_ProjTags,
2428         CSimpleMakeFileContents::eMergePlusMinus);
2429 
2430     list<string> watchers;
2431     if (m->second.CollectValues("WATCHERS", watchers,
2432         CSimpleMakeFileContents::eSortUnique)) {
2433         project.m_Watchers = NStr::Join(watchers, " ");
2434     }
2435 
2436     project.m_MkName = applib_mfilepath;
2437     tree->m_Projects[proj_key] = project;
2438 
2439     return proj_key;
2440 }
2441 //-----------------------------------------------------------------------------
2442 
s_AnalyzeLibraryOrder(CSymResolver & resolver,const CProjectItemsTree & tree)2443 void s_AnalyzeLibraryOrder( CSymResolver& resolver, const CProjectItemsTree&  tree)
2444 {
2445     CProjBulderApp& app(GetApp());
2446     CProjectItemsTree::TProjects::const_iterator p;
2447     for (p = tree.m_Projects.begin(); p != tree.m_Projects.end(); ++p) {
2448         if (p->first.Type() != CProjKey::eApp) {
2449             continue;
2450         }
2451         const CProjItem& project = p->second;
2452 
2453         list<string> list_lib;
2454         if (!project.m_DataSource.GetValue("LIB", list_lib)) {
2455             continue;
2456         }
2457         list<string> lib_list_in, lib_list_in0;
2458         for( const string& lib : list_lib) {
2459             if (lib.at(0) == '#') {
2460                 break;
2461             }
2462             else if (!CSymResolver::IsDefine(lib) && CSymResolver::HasDefine(lib)) {
2463                 string def = FilterDefine(lib);
2464                 string val = CSymResolver::StripDefine(def);
2465                 list<string> tmp;
2466                 if (project.m_DataSource.GetValue(val, tmp)) {
2467                     copy(tmp.begin(), tmp.end(), back_inserter(lib_list_in));
2468                 } else {
2469                     lib_list_in.push_back(def);
2470                 }
2471             } else {
2472                 lib_list_in.push_back(lib);
2473             }
2474         }
2475         if (lib_list_in.empty()) {
2476             continue;
2477         }
2478         lib_list_in0 = lib_list_in;
2479 
2480         map< string,  set<string> > lib_contents;
2481         map< string,  set<string> > lib_dependencies;
2482 
2483         list<string> lib_list_out[2];
2484         size_t pass=0;
2485         for (pass=0; pass<4; ++pass) {
2486 
2487             if (pass > 1) {
2488                 lib_list_out[0] = lib_list_out[1];
2489                 lib_list_out[1].clear();
2490             }
2491             list<string>& list_in  = pass == 0 ? lib_list_in     : lib_list_out[0];
2492             list<string>& list_out = pass == 0 ? lib_list_out[0] : lib_list_out[1];
2493 
2494             bool failed = false;
2495             for (list<string>::const_iterator l = list_in.begin(); ; ++l) {
2496 
2497 // list_in may change (grow) during the cycle
2498                 if (l == list_in.end()) {
2499                     break;
2500                 }
2501                 const string& lib = *l;
2502                 if (failed) {
2503                     list_out.push_back(lib);
2504                     continue;
2505                 }
2506 
2507 // this item contents
2508                 list<string> resolved;
2509                 if (!CSymResolver::IsDefine(lib) ||
2510                     !project.m_DataSource.GetValue(CSymResolver::StripDefine(lib), resolved)) {
2511                     resolver.Resolve(lib, &resolved);
2512                 }
2513                 for_each(resolved.begin(), resolved.end(), [&lib_contents, &lib](const string& ce) {
2514                     string e(ce);
2515                     CSymResolver::StripSuffix(e);
2516                     if (!e.empty() && e.at(0) != '@') {
2517                         lib_contents[lib].insert(e);
2518                     }});
2519 
2520 // this item dependencies
2521                 set<string> alldepends;
2522                 set<string> allflags;
2523                 for( const string& lib_item : lib_contents[lib]) {
2524                     s_CollectAllLeaves( app.m_GraphDepPrecedes, app.m_GraphDepFlags, lib_item, alldepends, allflags);
2525                 }
2526                 for_each(alldepends.begin(), alldepends.end(), [&lib_dependencies, &lib](const string& ce){
2527                     string e(ce);
2528                     CSymResolver::StripSuffix(e);
2529                     if (!e.empty() && e.at(0) != '@') {
2530                         lib_dependencies[lib].insert(e);
2531                     }});
2532 
2533                 list<string>::iterator iout = list_out.begin();
2534                 bool do_append = true;
2535 
2536 // check that this item dependencies do not contain items in 'out' list
2537                 for (; iout != list_out.end(); ++iout) {
2538                     for( const string& lib_dep : lib_dependencies[lib]) {
2539                         if (lib_contents[*iout].find(lib_dep) != lib_contents[*iout].end()) {
2540                             do_append = false;
2541                             break;
2542                         }
2543                     }
2544                     if (!do_append) {
2545                         break;
2546                     }
2547                 }
2548 
2549                 // good to append
2550                 if (do_append) {
2551                     list_out.push_back(lib);
2552                     continue;
2553                 }
2554 
2555                 list<string>::const_iterator i = iout;
2556                 set<string> already_there;
2557                 bool do_replace = false;
2558 
2559 // maybe we could drop item at iout, because new one includes it
2560 // compare lib_contents[*iout] with the contents of the new item
2561                 already_there.clear();
2562                 for( const string& lib_item : lib_contents[*iout]) {
2563                     if (lib_contents[lib].find(lib_item) != lib_contents[lib].end()) {
2564                         already_there.insert(lib_item);
2565                     }
2566                 }
2567                 if (already_there.size() == lib_contents[*iout].size() &&
2568                     already_there.size() != lib_contents[lib].size()) {
2569                     // it seems that the new item can replace old one
2570                     // make a note to check that it indeed may be inserted here
2571                     do_replace = true;
2572                 }
2573 
2574 // is there a need to add this item?
2575 // compare this item contents with what is already there
2576                 already_there.clear();
2577                 for (i = iout; i != list_out.end(); ++i) {
2578                     for( const string& lib_item : lib_contents[lib]) {
2579                         if (lib_contents[*i].find(lib_item) != lib_contents[*i].end()) {
2580                             already_there.insert(lib_item);
2581                         }
2582                     }
2583                 }
2584                 if (already_there.size() == lib_contents[lib].size()) {
2585                     // this is a duplicate which is already included
2586                     continue;
2587                 }
2588                 // if this item adds only few new libraries, maybe we would better
2589                 // add them expicitely instead
2590                 if (//!do_replace &&
2591                     already_there.size() != 0 &&
2592                     already_there.size() >= (lib_contents[lib].size() * 3)/4) {
2593                     for( const string& lib_item : lib_contents[lib]) {
2594                         if (already_there.find(lib_item) == already_there.end()) {
2595                             list_in.push_back(lib_item);
2596                         }
2597                     }
2598                     continue;
2599                 }
2600 
2601 // if we insert it at iout, check that items that follow do not depend on it
2602                 do_append = false;
2603                 bool do_insert = true;
2604                 i = iout;
2605                 if (do_replace) {
2606                     ++i;
2607                 }
2608                 for (; i != list_out.end(); ++i) {
2609                     for( const string& lib_dep : lib_dependencies[*i]) {
2610                         if (lib_contents[lib].find(lib_dep) != lib_contents[lib].end()) {
2611 // maybe both include the same library.
2612 // if so, that is acceptable
2613                             if (lib_contents[*i].find(lib_dep) != lib_contents[*i].end()) {
2614                                 do_append = true;
2615                                 continue;
2616                             }
2617                             do_insert = false;
2618                             break;
2619                         }
2620                     }
2621                     if (!do_insert) {
2622                         break;
2623                     }
2624                 }
2625 
2626 // good to insert
2627                 if (do_insert) {
2628                     i = iout;
2629                     if (do_append && ++i == list_out.end()) {
2630                         list_out.push_back(lib);
2631                     } else {
2632                         if (do_replace) {
2633                             iout = list_out.erase(iout);
2634                         }
2635                         list_out.insert(iout, lib);
2636                     }
2637                     continue;
2638                 }
2639 
2640 // once again, try to append, allowing identical libraries in both
2641                 do_append = true;
2642 // check that this item dependencies do not contain items in 'out' list
2643                 for (i=iout; i != list_out.end(); ++i) {
2644                     for( const string& lib_dep : lib_dependencies[lib]) {
2645                         if (lib_contents[*i].find(lib_dep) != lib_contents[*i].end()) {
2646                             if (lib_contents[lib].find(lib_dep) != lib_contents[lib].end()) {
2647                                 continue;
2648                             }
2649                             do_append = false;
2650                             break;
2651                         }
2652                     }
2653                     if (!do_append) {
2654                         break;
2655                     }
2656                 }
2657 
2658                 // not sure about this one
2659                 if (do_replace) {
2660                     list_out.erase(iout);
2661                     for( const string& lib_item : already_there) {
2662                         list_out.remove(lib_item);
2663                     }
2664                 }
2665                 // good to append
2666                 if (do_append) {
2667                     list_out.push_back(lib);
2668                     continue;
2669                 }
2670 // Do not know what to do
2671 // keep it as is, in a hope that it will work
2672 //                failed = true;
2673                 list_out.push_back(lib);
2674             }
2675 
2676             if (list_in.size() == list_out.size() &&
2677                 equal(list_in.begin(), list_in.end(), list_out.begin())) {
2678                 break;
2679             }
2680         }
2681         if (pass != 0) {
2682             list<string> warnings;
2683             warnings.push_back("====== Library order warnings (toolkit libs) ======");
2684             warnings.push_back("present     library order: " + NStr::Join(lib_list_in0," "));
2685             if (lib_list_out[0].size() == lib_list_out[1].size() &&
2686                 equal(lib_list_out[0].begin(), lib_list_out[0].end(), lib_list_out[1].begin())) {
2687                 warnings.push_back("recommended library order: " + NStr::Join(lib_list_out[0]," "));
2688 
2689                 set<string> all_libs, all_deps;
2690                 for(const string& lib_item: lib_list_out[0]) {
2691                     all_libs.insert( lib_contents[lib_item].begin(),lib_contents[lib_item].end());
2692                     all_deps.insert( lib_dependencies[lib_item].begin(),lib_dependencies[lib_item].end());
2693                 }
2694                 set<string> all_missing;
2695                 for(const string& lib_item: all_deps) {
2696                     if (all_libs.find(lib_item) == all_libs.end()) {
2697                         all_missing.insert(lib_item);
2698                     }
2699                 }
2700                 if (!all_missing.empty()) {
2701                     warnings.push_back("missing libraries: " + NStr::Join(all_missing," "));
2702                 }
2703             } else {
2704                 warnings.push_back("Failed to identify recommended library order");
2705                 if (pass >= 2) {
2706                     warnings.push_back("candidate1: " + NStr::Join(lib_list_out[0]," "));
2707                     warnings.push_back("candidate2: " + NStr::Join(lib_list_out[1]," "));
2708                 }
2709             }
2710             PTB_WARNING_EX(project.m_DataSource.GetFileName(),ePTB_InvalidMakefile, NStr::Join(warnings,"\n"));
2711         }
2712     }
2713 }
2714 //-----------------------------------------------------------------------------
2715 
2716 
2717 void
BuildOneProjectTree(const IProjectFilter * filter,const string & root_src_path,CProjectItemsTree * tree)2718 CProjectTreeBuilder::BuildOneProjectTree(const IProjectFilter* filter,
2719                                          const string&         root_src_path,
2720                                          CProjectItemsTree*    tree)
2721 {
2722     SMakeFiles subtree_makefiles;
2723 
2724     ProcessDir(root_src_path,
2725                true,
2726                filter,
2727                &subtree_makefiles, eMakeType_Undefined, NULL);
2728 
2729     // Resolve macrodefines
2730     list<string> metadata_files;
2731     GetApp().GetMetaDataFiles(&metadata_files);
2732     CSymResolver resolver;
2733     if (CMsvc7RegSettings::GetMsvcPlatform() != CMsvc7RegSettings::eUnix) {
2734         resolver.Append( GetApp().GetSite().GetMacros());
2735     }
2736     ITERATE(list<string>, p, metadata_files) {
2737 	    string fileloc;
2738         if (!GetApp().m_BuildRoot.empty()) {
2739             fileloc = CDirEntry::ConcatPath(GetApp().m_BuildRoot,*p);
2740         }
2741         if (fileloc.empty() || !CFile(fileloc).Exists()) {
2742             fileloc = CDirEntry::ConcatPath(root_src_path, CDirEntry::ConvertToOSPath(*p));
2743         }
2744 	    if (!CDirEntry(fileloc).Exists() && !GetApp().m_ExtSrcRoot.empty()) {
2745 	        fileloc = CDirEntry::ConcatPath( CDirEntry::ConcatPath(
2746 	            GetApp().m_ExtSrcRoot,
2747 	                GetApp().GetConfig().Get("ProjectTree", "src")),
2748 	                    CDirEntry::ConvertToOSPath(*p));
2749 	    }
2750         if (!CDirEntry(fileloc).Exists()) {
2751             fileloc = CDirEntry::ConcatPath(CDirEntry(GetApp().m_Solution).GetDir(),*p);
2752         }
2753         if (CDirEntry(fileloc).Exists()) {
2754             CSymResolver sym(fileloc);
2755             bool is_good = true;
2756             string requires;
2757             if (sym.GetValue("REQUIRES", requires)) {
2758                 list<string> items;
2759                 NStr::Split(requires, LIST_SEPARATOR, items, NStr::fSplit_Tokenize);
2760                 for(const string& i : items) {
2761                     if (!GetApp().GetSite().IsProvided(i)) {
2762                         PTB_WARNING_EX(kEmptyStr, ePTB_FileExcluded, "Custom metadata " << fileloc << " rejected because of unmet requirement: " << i);
2763                         is_good = false;
2764                         break;
2765                     }
2766                 }
2767             }
2768             if (is_good) {
2769                 PTB_INFO("Resolve macros using rules from " << fileloc);
2770 	            resolver.Append( sym, true);;
2771             }
2772         }
2773 	}
2774     ResolveDefs(resolver, subtree_makefiles);
2775     GetApp().UpdateDepGraph( subtree_makefiles.m_Lib);
2776 
2777     // Build projects tree
2778     CProjectItemsTree::CreateFrom(root_src_path,
2779                                   subtree_makefiles.m_In,
2780                                   subtree_makefiles.m_Lib,
2781                                   subtree_makefiles.m_Dll,
2782                                   subtree_makefiles.m_App,
2783                                   subtree_makefiles.m_User, tree);
2784 
2785     if (!GetApp().IsScanningWholeTree()) {
2786         s_AnalyzeLibraryOrder(resolver, *tree);
2787     }
2788 }
2789 
2790 
2791 void
BuildProjectTree(const IProjectFilter * filter,const string & root_src_path,CProjectItemsTree * tree)2792 CProjectTreeBuilder::BuildProjectTree(const IProjectFilter* filter,
2793                                       const string&         root_src_path,
2794                                       CProjectItemsTree*    tree)
2795 {
2796     // Build subtree
2797     CProjectItemsTree target_tree;
2798 
2799     BuildOneProjectTree(filter, root_src_path, &target_tree);
2800 
2801     if (GetApp().IsScanningWholeTree()) {
2802         *tree = target_tree;
2803         NON_CONST_ITERATE( CProjectItemsTree::TProjects, t, tree->m_Projects) {
2804             t->second.m_MakeType = eMakeType_Excluded;
2805             t->second.m_External = true;
2806         }
2807         return;
2808     }
2809 
2810     GetApp().ExcludeProjectsByTag(target_tree);
2811     if ( GetApp().m_InteractiveCfg &&
2812         !GetApp().Gui_ConfirmProjects(target_tree))
2813     {
2814         GetApp().SetFail();
2815         return;
2816     }
2817     GetApp().ExcludeUnrequestedProjects(target_tree);
2818 
2819     for (;;) {
2820         size_t orig_size = target_tree.m_Projects.size();
2821         // Analyze subtree dependencies
2822         list<CProjKey> external_depends;
2823         target_tree.GetExternalDepends(&external_depends);
2824 
2825         // We have to add more projects to the target tree
2826         if ( !external_depends.empty()) {
2827             list<CProjKey> depends_to_resolve = external_depends;
2828             while ( !depends_to_resolve.empty() ) {
2829                 bool modified = false;
2830                 ITERATE(list<CProjKey>, p, depends_to_resolve) {
2831                     // id of the project we have to resolve
2832                     const CProjKey& prj_id = *p;
2833                     CProjectItemsTree::TProjects::const_iterator n =
2834                                    GetApp().GetWholeTree().m_Projects.find(prj_id);
2835 
2836                     if (n != GetApp().GetWholeTree().m_Projects.end()) {
2837                         //insert this project into the target_tree
2838                         target_tree.m_Projects[prj_id] = n->second;
2839                         modified = true;
2840                     } else {
2841                         /// FIXME: is this needed?
2842                         _TRACE("Project not found: " + prj_id.Id());
2843                     }
2844                 }
2845 
2846                 if (!modified) {
2847                     //done - no projects has been added to target_tree
2848                     AddDatatoolSourcesDepends(&target_tree);
2849                     *tree = target_tree;
2850                     return;
2851                 } else {
2852                     //continue resolving dependencies
2853                     target_tree.GetExternalDepends(&depends_to_resolve);
2854                 }
2855             }
2856         }
2857 
2858         AddDatatoolSourcesDepends(&target_tree);
2859         if (orig_size == target_tree.m_Projects.size()) {
2860             break;
2861         }
2862     }
2863     *tree = target_tree;
2864 }
2865 
2866 
ProcessDir(const string & dir_name,bool is_root,const IProjectFilter * filter,SMakeFiles * makefiles,EMakeFileType maketype,const CSimpleMakeFileContents * parent)2867 void CProjectTreeBuilder::ProcessDir(const string&         dir_name,
2868                                      bool                  is_root,
2869                                      const IProjectFilter* filter,
2870                                      SMakeFiles*           makefiles,
2871                                      EMakeFileType         maketype,
2872                                      const CSimpleMakeFileContents* parent)
2873 {
2874     // Node - Makefile.in should present
2875     // this is true if and only if there are also Makefile.*.lib or
2876     // Makefile.*.app project makefiles to process
2877     string node_path =
2878         CDirEntry::ConcatPath(dir_name,
2879                               GetApp().GetProjectTreeInfo().m_TreeNode);
2880     if ( !is_root  &&  !CDirEntry(node_path).Exists() ) {
2881         CDir::TGetEntriesFlags flags = CDir::fIgnoreRecursive;
2882         CDir::TEntries entries =
2883             CDir(dir_name).GetEntries("Makefile.*.lib", flags);
2884         if (entries.empty()) {
2885             entries = CDir(dir_name).GetEntries("Makefile.*.app", flags);
2886         }
2887         if ( !entries.empty() ) {
2888             PTB_WARNING_EX(node_path, ePTB_MissingMakefile,
2889                            "Makefile.in missing");
2890         }
2891 
2892         string bld_sys = CDirEntry::DeleteTrailingPathSeparator(
2893             CDirEntry(GetApp().GetConfigPath()).GetDir());
2894         if (NStr::CompareNocase(bld_sys,dir_name) == 0) {
2895             CDir dir(dir_name);
2896             CDir::TEntries contents;
2897             contents = dir.GetEntries(GetApp().GetProjectTreeInfo().m_CustomMetaData);
2898             ITERATE(CDir::TEntries, p, contents) {
2899                 GetApp().AddCustomMetaData( (*p)->GetPath());
2900             }
2901             contents = dir.GetEntries(GetApp().GetProjectTreeInfo().m_CustomConfH);
2902             ITERATE(CDir::TEntries, p, contents) {
2903                 GetApp().AddCustomConfH( (*p)->GetPath());
2904             }
2905         }
2906         return;
2907     }
2908     if (!is_root &&
2909         CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eUnix) {
2910         // on UNIX the build tree is already configured,
2911         // we check if this particular subtree is enabled (ie, exists) there
2912         string subtree =
2913             CDirEntry::CreateRelativePath(
2914                 GetApp().GetProjectTreeInfo().m_Src, dir_name);
2915         subtree = CDirEntry::ConcatPath(CDirEntry(GetApp().m_Solution).GetDir(), subtree);
2916         if (!CDirEntry(subtree).Exists()) {
2917             PTB_INFO_EX(subtree, ePTB_NoError,
2918                         "skipped missing subtree");
2919             return;
2920         }
2921     }
2922 
2923     bool weak=false;
2924     bool process_projects = !is_root && filter->CheckProject(dir_name,&weak);
2925     if (!process_projects && !weak && !is_root) {
2926         return;
2927     }
2928 
2929     // Process Makefile.in
2930     const CSimpleMakeFileContents* mkin = NULL;
2931     map<string, EMakeFileType> subprojects;
2932     map<string, EMakeFileType> appprojects;
2933     map<string, EMakeFileType> libprojects;
2934     map<string, EMakeFileType> dllprojects;
2935     map<string, EMakeFileType> userprojects;
2936     vector<string> ordered_subprojects;
2937     string topbuilddir;
2938     bool has_metal = false;
2939     bool get_order = GetApp().IsScanningWholeTree();
2940     if (is_root && get_order) {
2941         topbuilddir = GetApp().GetRegSettings().GetTopBuilddir();
2942     }
2943 
2944     if ( process_projects || weak || !topbuilddir.empty()) {
2945         string node(topbuilddir.empty() ? node_path : topbuilddir);
2946         ProcessMakeInFile(node, makefiles, maketype, parent);
2947         TFiles::const_iterator p = makefiles->m_In.find(node);
2948         if (p != makefiles->m_In.end()) {
2949         const CSimpleMakeFileContents& makefile = p->second;
2950         mkin = &makefile;
2951         CSimpleMakeFileContents::TContents::const_iterator k;
2952         int j;
2953         string subproj[] = {"SUB_PROJ","EXPENDABLE_SUB_PROJ","POTENTIAL_SUB_PROJ",""};
2954         EMakeFileType subtype[] = {eMakeType_Undefined,eMakeType_Expendable,eMakeType_Potential};
2955         if (filter->ExcludePotential()) {
2956             subtype[2] = eMakeType_Excluded;
2957         }
2958         for (j=0; !subproj[j].empty(); ++j) {
2959             k = makefile.m_Contents.find(subproj[j]);
2960             if (k != makefile.m_Contents.end()) {
2961                 const list<string>& values = k->second;
2962                 for (list<string>::const_iterator i=values.begin(); i!=values.end(); ++i) {
2963                     if (i->at(0) == '#') {
2964                         break;
2965                     }
2966                     subprojects[*i] = max(maketype, subtype[j]);
2967                     ordered_subprojects.push_back(*i);
2968                 }
2969             }
2970         }
2971         if ( process_projects ) {
2972         string userproj[] = {"UNIX_PROJ","EXPENDABLE_UNIX_PROJ", ""};
2973         if (CMsvc7RegSettings::GetMsvcPlatform() != CMsvc7RegSettings::eUnix) {
2974             bool is_xcode = CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eXCode;
2975             userproj[0] = is_xcode ? "XCODE_PROJ" : "MSVC_PROJ";
2976             userproj[1] = "";
2977         }
2978         EMakeFileType usertype[] = {eMakeType_Undefined,eMakeType_Expendable};
2979         for (j=0; !userproj[j].empty(); ++j) {
2980             k = makefile.m_Contents.find(userproj[j]);
2981             if (k != makefile.m_Contents.end()) {
2982                 const list<string>& values = k->second;
2983                 for (list<string>::const_iterator i=values.begin(); i!=values.end(); ++i) {
2984                     if (i->at(0) == '#') {
2985                         break;
2986                     }
2987                     if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eUnix) {
2988                         userprojects["Makefile." + *i] = max(maketype, usertype[j]);
2989                         userprojects["Makefile." + *i + ".in"] = max(maketype, usertype[j]);
2990                         if (get_order) {
2991                             s_WriteBuildOrder(dir_name,"Makefile." + *i);
2992                             s_WriteBuildOrder(dir_name,"Makefile." + *i + ".in");
2993                         }
2994                     } else {
2995                         string mkname("Makefile." + *i);
2996                         if (CMsvc7RegSettings::GetMsvcPlatform() != CMsvc7RegSettings::eXCode) {
2997                             mkname += ".msvcproj";
2998                         }
2999                         userprojects[mkname] = max(maketype, usertype[j]);
3000                         if (get_order) {
3001                             s_WriteBuildOrder(dir_name,mkname);
3002                         }
3003                     }
3004                 }
3005             }
3006         }
3007         string libproj[] = {"ASN_PROJ","DTD_PROJ","XSD_PROJ","WSDL_PROJ","JSD_PROJ", "PROTOBUF_PROJ",
3008             "LIB_PROJ","EXPENDABLE_LIB_PROJ","POTENTIAL_LIB_PROJ",""};
3009         EMakeFileType libtype[] = {
3010             eMakeType_Undefined, eMakeType_Undefined, eMakeType_Undefined, eMakeType_Undefined,
3011             eMakeType_Undefined, eMakeType_Undefined,
3012             eMakeType_Undefined,eMakeType_Expendable, filter->ExcludePotential() ? eMakeType_Excluded : eMakeType_Potential};
3013         for (j=0; !libproj[j].empty(); ++j) {
3014             k = makefile.m_Contents.find(libproj[j]);
3015             if (k != makefile.m_Contents.end()) {
3016                 const list<string>& values = k->second;
3017                 for (list<string>::const_iterator i=values.begin(); i!=values.end(); ++i) {
3018                     if (i->at(0) == '#') {
3019                         break;
3020                     }
3021                     string mkname("Makefile." + *i + ".lib");
3022                     libprojects[mkname] = max(maketype, libtype[j]);
3023                     if (get_order) {
3024                         s_WriteBuildOrder(dir_name,mkname);
3025                     }
3026                 }
3027             }
3028         }
3029         string dllproj[] = {"DLL_PROJ","EXPENDABLE_DLL_PROJ","POTENTIAL_DLL_PROJ",""};
3030         EMakeFileType dlltype[] = {eMakeType_Undefined,eMakeType_Expendable,
3031             filter->ExcludePotential() ? eMakeType_Excluded : eMakeType_Potential};
3032         for (j=0; !dllproj[j].empty(); ++j) {
3033             k = makefile.m_Contents.find(dllproj[j]);
3034             if (k != makefile.m_Contents.end()) {
3035                 const list<string>& values = k->second;
3036                 for (list<string>::const_iterator i=values.begin(); i!=values.end(); ++i) {
3037                     if (i->at(0) == '#') {
3038                         break;
3039                     }
3040                     string mkname("Makefile." + *i + ".dll");
3041                     dllprojects[mkname] = max(maketype, dlltype[j]);
3042                     if (get_order) {
3043                         s_WriteBuildOrder(dir_name,mkname);
3044                     }
3045                 }
3046             }
3047         }
3048         string metallib[] = {"METAL_PROJ", ""};
3049         EMakeFileType metaltype[] = { eMakeType_Undefined};
3050         for (j=0; !metallib[j].empty(); ++j) {
3051             k = makefile.m_Contents.find(metallib[j]);
3052             if (k != makefile.m_Contents.end()) {
3053                 const list<string>& values = k->second;
3054                 for (list<string>::const_iterator i=values.begin(); i!=values.end(); ++i) {
3055                     if (i->at(0) == '#') {
3056                         break;
3057                     }
3058                     string mkname("Makefile." + *i + ".metal");
3059                     libprojects[mkname] = max(maketype, metaltype[j]);
3060                     if (get_order) {
3061                         s_WriteBuildOrder(dir_name,mkname);
3062                     }
3063                     has_metal = true;
3064                 }
3065             }
3066         }
3067         string appproj[] = {"APP_PROJ","EXPENDABLE_APP_PROJ","POTENTIAL_APP_PROJ",""};
3068         EMakeFileType apptype[] = {eMakeType_Undefined,eMakeType_Expendable,eMakeType_Potential};
3069         if (filter->ExcludePotential()) {
3070             apptype[2] = eMakeType_Excluded;
3071         }
3072         for (j=0; !appproj[j].empty(); ++j) {
3073             k = makefile.m_Contents.find(appproj[j]);
3074             if (k != makefile.m_Contents.end()) {
3075                 const list<string>& values = k->second;
3076                 for (list<string>::const_iterator i=values.begin(); i!=values.end(); ++i) {
3077                     if (i->at(0) == '#') {
3078                         break;
3079                     }
3080                     string mkname("Makefile." + *i + ".app");
3081                     appprojects[mkname] = max(maketype, apptype[j]);
3082                     if (get_order) {
3083                         s_WriteBuildOrder(dir_name,mkname);
3084                     }
3085                 }
3086             }
3087         }
3088         }
3089         }
3090     }
3091 
3092     // Process Makefile.*.lib
3093     if ( process_projects && !libprojects.empty()) {
3094         CDir dir(dir_name);
3095         CDir::TEntries contents = dir.GetEntries("Makefile.*.lib");
3096         ITERATE(CDir::TEntries, p, contents) {
3097             const AutoPtr<CDirEntry>& dir_entry = *p;
3098             const string name = dir_entry->GetName();
3099             if (libprojects.find(name) != libprojects.end() &&
3100                 SMakeProjectT::IsMakeLibFile(name) )
3101 	            ProcessMakeLibFile(dir_entry->GetPath(), makefiles, libprojects[name], mkin);
3102 
3103         }
3104         if (has_metal) {
3105             contents = dir.GetEntries("Makefile.*.metal");
3106             ITERATE(CDir::TEntries, p, contents) {
3107                 const AutoPtr<CDirEntry>& dir_entry = *p;
3108                 const string name = dir_entry->GetName();
3109                 if (libprojects.find(name) != libprojects.end()) {
3110 	                ProcessMakeLibFile(dir_entry->GetPath(), makefiles, libprojects[name], mkin);
3111                 }
3112             }
3113         }
3114     }
3115     // Process Makefile.*.dll
3116     if ( process_projects && !dllprojects.empty()) {
3117         CDir dir(dir_name);
3118         CDir::TEntries contents = dir.GetEntries("Makefile.*.dll");
3119         ITERATE(CDir::TEntries, p, contents) {
3120             const AutoPtr<CDirEntry>& dir_entry = *p;
3121             const string name = dir_entry->GetName();
3122             if (dllprojects.find(name) != dllprojects.end() &&
3123                 SMakeProjectT::IsMakeDllFile(name) )
3124 	            ProcessMakeDllFile(dir_entry->GetPath(), makefiles, dllprojects[name], mkin);
3125 
3126         }
3127     }
3128     // Process Makefile.*.app
3129     if ( process_projects && !appprojects.empty() ) {
3130         CDir dir(dir_name);
3131         CDir::TEntries contents = dir.GetEntries("Makefile.*.app");
3132         ITERATE(CDir::TEntries, p, contents) {
3133             const AutoPtr<CDirEntry>& dir_entry = *p;
3134             const string name = dir_entry->GetName();
3135             if (appprojects.find(name) != appprojects.end() &&
3136                 SMakeProjectT::IsMakeAppFile(name) )
3137 	            ProcessMakeAppFile(dir_entry->GetPath(), makefiles, appprojects[name], mkin);
3138 
3139         }
3140     }
3141     // Process Makefile.*.msvcproj
3142     if ( process_projects && !userprojects.empty() ) {
3143         CDir dir(dir_name);
3144 //        CDir::TEntries contents = dir.GetEntries("Makefile.*.msvcproj");
3145         CDir::TEntries contents = dir.GetEntries("Makefile.*");
3146         ITERATE(CDir::TEntries, p, contents) {
3147             const AutoPtr<CDirEntry>& dir_entry = *p;
3148             const string name = dir_entry->GetName();
3149             if (userprojects.find(name) != userprojects.end() /*&&
3150                 SMakeProjectT::IsUserProjFile(name)*/ )
3151 	            ProcessUserProjFile(dir_entry->GetPath(), makefiles, userprojects[name], mkin);
3152 
3153         }
3154     }
3155 
3156     if ( process_projects) {
3157         /*if (!GetApp().IsScanningWholeTree())*/ {
3158             CDir dir(dir_name);
3159             CDir::TEntries contents = dir.GetEntries(GetApp().GetProjectTreeInfo().m_CustomMetaData);
3160             ITERATE(CDir::TEntries, p, contents) {
3161                 GetApp().AddCustomMetaData( (*p)->GetPath());
3162             }
3163             contents = dir.GetEntries(GetApp().GetProjectTreeInfo().m_CustomConfH);
3164             ITERATE(CDir::TEntries, p, contents) {
3165                 GetApp().AddCustomConfH( (*p)->GetPath());
3166             }
3167         }
3168     }
3169 
3170     // Convert subprojects to subdirs
3171     map<string, EMakeFileType> subprojects_dirs;
3172     vector<string> ordered_subprojects_dirs;
3173 
3174     // begin with explicitely requested subprojects
3175     ITERATE( vector<string>, p, ordered_subprojects) {
3176         string name(*p);
3177         CDirEntry dir_entry( CDirEntry::ConcatPath(dir_name, name));
3178         if ( dir_entry.IsDir() ) {
3179             if (subprojects.find(name) != subprojects.end()) {
3180                 subprojects_dirs[dir_entry.GetPath()] = subprojects[name];
3181             } else {
3182                 subprojects_dirs[dir_entry.GetPath()] =
3183                     is_root ? eMakeType_Undefined : eMakeType_Excluded;
3184             }
3185             if (find(ordered_subprojects_dirs.begin(), ordered_subprojects_dirs.end(), name) ==
3186                      ordered_subprojects_dirs.end()) {
3187                 ordered_subprojects_dirs.push_back(name);
3188             } else {
3189                 PTB_WARNING_EX(node_path, ePTB_InvalidMakefile,
3190                             "Duplicate entry: " << name);
3191             }
3192         }
3193     }
3194 
3195 //    if ( is_root || (!process_projects && weak) ) {
3196         CDir dir(dir_name);
3197         CDir::TEntries contents = dir.GetEntries("*");
3198         ITERATE(CDir::TEntries, p, contents) {
3199             const AutoPtr<CDirEntry>& dir_entry = *p;
3200             if ( !dir_entry->IsDir() ) {
3201                 continue;
3202             }
3203             string name  = dir_entry->GetName();
3204 //            if ( name == "."  ||  name == ".." ||  name == "CVS" ||  name == ".svn" ||
3205             if ( name[0] == '.'  ||  name == "CVS" ||
3206                  name == string(1,CDir::GetPathSeparator()) ) {
3207                 continue;
3208             }
3209             if (find(ordered_subprojects_dirs.begin(), ordered_subprojects_dirs.end(), name) !=
3210                      ordered_subprojects_dirs.end()) {
3211                 // already processed
3212                 continue;
3213             }
3214             if (subprojects.find(name) != subprojects.end()) {
3215                 subprojects_dirs[dir_entry->GetPath()] = subprojects[name];
3216             } else {
3217                 subprojects_dirs[dir_entry->GetPath()] =
3218                     is_root ? eMakeType_Undefined : eMakeType_Excluded;
3219             }
3220             if (find(ordered_subprojects_dirs.begin(), ordered_subprojects_dirs.end(), name) ==
3221                         ordered_subprojects_dirs.end()) {
3222                 ordered_subprojects_dirs.push_back(name);
3223             }
3224         }
3225         {
3226             map<string, EMakeFileType>::const_iterator s;
3227             for (s = subprojects.begin(); s != subprojects.end(); ++s) {
3228                 if (s->first.find('/') != string::npos) {
3229                     CDir dir_entry(CDirEntry::NormalizePath(
3230                         CDirEntry::ConcatPath(dir_name, s->first)));
3231                     if (dir_entry.IsDir()) {
3232                         subprojects_dirs[dir_entry.GetPath()] = subprojects[s->first];
3233                     }
3234                 }
3235             }
3236         }
3237 /*
3238     } else {
3239         // for non-root only subprojects
3240         map<string, EMakeFileType>::const_iterator p;
3241         for (p = subprojects.begin(); p != subprojects.end(); ++p) {
3242             const string& subproject = p->first;
3243             string subproject_dir =
3244                 CDirEntry::ConcatPath(dir_name, subproject);
3245             subprojects_dirs[subproject_dir] = p->second;
3246         }
3247     }
3248 */
3249 
3250     // Process subproj ( e.t. subdirs )
3251     ITERATE( vector<string>, ps, ordered_subprojects_dirs) {
3252         const string& subproject_dir = CDirEntry::ConcatPath(dir_name, *ps);
3253         ProcessDir(subproject_dir, false, filter, makefiles, subprojects_dirs[subproject_dir], mkin);
3254     }
3255 
3256 }
3257 
3258 
ProcessMakeInFile(const string & file_name,SMakeFiles * makefiles,EMakeFileType type,const CSimpleMakeFileContents * parent)3259 void CProjectTreeBuilder::ProcessMakeInFile(const string& file_name,
3260                                             SMakeFiles*   makefiles,
3261                                             EMakeFileType type,
3262                                             const CSimpleMakeFileContents* parent)
3263 {
3264     CSimpleMakeFileContents fc(file_name, type);
3265     fc.SetParent(parent);
3266     if ( !fc.m_Contents.empty() ) {
3267 	    makefiles->m_In[file_name] = fc;
3268         PTB_TRACE_EX(file_name, 0, MakeFileTypeAsString(type));
3269 	} else {
3270         PTB_WARNING(file_name, "ignored; empty");
3271 	}
3272 }
3273 
3274 
ProcessMakeLibFile(const string & file_name,SMakeFiles * makefiles,EMakeFileType type,const CSimpleMakeFileContents * parent)3275 void CProjectTreeBuilder::ProcessMakeLibFile(const string& file_name,
3276                                              SMakeFiles*   makefiles,
3277                                              EMakeFileType type,
3278                                              const CSimpleMakeFileContents* parent)
3279 {
3280     CSimpleMakeFileContents fc(file_name, type);
3281     fc.SetParent(parent);
3282     if ( !fc.m_Contents.empty()  ) {
3283         makefiles->m_Lib[file_name] = fc;
3284         PTB_TRACE_EX(file_name, 0, MakeFileTypeAsString(type));
3285 	} else {
3286         PTB_WARNING(file_name, "ignored; empty");
3287 	}
3288 }
3289 
ProcessMakeDllFile(const string & file_name,SMakeFiles * makefiles,EMakeFileType type,const CSimpleMakeFileContents * parent)3290 void CProjectTreeBuilder::ProcessMakeDllFile(const string& file_name,
3291                                              SMakeFiles*   makefiles,
3292                                              EMakeFileType type,
3293                                              const CSimpleMakeFileContents* parent)
3294 {
3295     string s = "MakeDll : " + file_name + "   ";
3296 
3297     CSimpleMakeFileContents fc(file_name, type);
3298     fc.SetParent(parent);
3299     if ( !fc.m_Contents.empty()  ) {
3300         makefiles->m_Dll[file_name] = fc;
3301 	} else {
3302         PTB_INFO(s << "rejected (is empty)");
3303 	}
3304 }
3305 
3306 
ProcessMakeAppFile(const string & file_name,SMakeFiles * makefiles,EMakeFileType type,const CSimpleMakeFileContents * parent)3307 void CProjectTreeBuilder::ProcessMakeAppFile(const string& file_name,
3308                                              SMakeFiles*   makefiles,
3309                                              EMakeFileType type,
3310                                              const CSimpleMakeFileContents* parent)
3311 {
3312     CSimpleMakeFileContents fc(file_name, type);
3313     fc.SetParent(parent);
3314     if ( !fc.m_Contents.empty() ) {
3315         makefiles->m_App[file_name] = fc;
3316         PTB_TRACE_EX(file_name, 0, MakeFileTypeAsString(type));
3317 	} else {
3318         PTB_WARNING(file_name, "ignored; empty");
3319 	}
3320 }
3321 
3322 
ProcessUserProjFile(const string & file_name,SMakeFiles * makefiles,EMakeFileType type,const CSimpleMakeFileContents * parent)3323 void CProjectTreeBuilder::ProcessUserProjFile(const string& file_name,
3324                                              SMakeFiles*   makefiles,
3325                                              EMakeFileType type,
3326                                              const CSimpleMakeFileContents* parent)
3327 {
3328     bool allow_empty = CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eUnix;
3329     CSimpleMakeFileContents fc(file_name, type);
3330     fc.SetParent(parent);
3331     if ( allow_empty || !fc.m_Contents.empty() ) {
3332 	    makefiles->m_User[file_name] = fc;
3333         PTB_TRACE_EX(file_name, 0, MakeFileTypeAsString(type));
3334 	} else {
3335         PTB_WARNING(file_name, "ignored; empty");
3336 	}
3337 }
3338 
3339 //recursive resolving
ResolveDefs(CSymResolver & resolver,SMakeFiles & makefiles)3340 void CProjectTreeBuilder::ResolveDefs(CSymResolver& resolver,
3341                                       SMakeFiles&   makefiles)
3342 {
3343     {{
3344         _TRACE("*** Resolving macrodefinitions in App projects ***");
3345         //App
3346         set<string> keys;
3347         keys.insert("LIB");
3348         keys.insert("LIBS");
3349         if (GetApp().GetBuildType().GetType() == CBuildType::eStatic) {
3350             keys.insert("STATIC_LIB");
3351             keys.insert("STATIC_LIBS");
3352         }
3353         keys.insert("NCBI_C_LIBS");
3354         SMakeProjectT::DoResolveDefs(resolver, makefiles.m_App, keys);
3355     }}
3356 
3357     {{
3358         _TRACE("*** Resolving macrodefinitions in Lib projects ***");
3359         //Lib
3360         set<string> keys;
3361         keys.insert("LIB");
3362         keys.insert("LIBS");
3363         if (GetApp().GetBuildType().GetType() == CBuildType::eStatic) {
3364             keys.insert("STATIC_LIB");
3365             keys.insert("STATIC_LIBS");
3366         }
3367         keys.insert("SRC");
3368         keys.insert("DLL_LIB");
3369         if (GetApp().GetBuildType().GetType() == CBuildType::eDll) {
3370             keys.insert("DLL_DLIB");
3371         }
3372         SMakeProjectT::DoResolveDefs(resolver, makefiles.m_Lib, keys);
3373     }}
3374 
3375     {{
3376         _TRACE("*** Resolving macrodefinitions in Msvc projects ***");
3377         set<string> keys;
3378         keys.insert("DLL_DEP");
3379         SMakeProjectT::DoResolveDefs(resolver, makefiles.m_User, keys);
3380     }}
3381     {{
3382         set<string> keys;
3383         SMakeProjectT::DoResolveDefs(resolver, makefiles.m_In, keys);
3384         SMakeProjectT::DoResolveDefs(resolver, makefiles.m_Dll, keys);
3385     }}
3386 }
3387 
3388 
3389 //analyze modules
s_CollectDatatoolIds(const CProjectItemsTree & tree,map<string,CProjKey> * datatool_ids)3390 void s_CollectDatatoolIds(const CProjectItemsTree& tree,
3391                           map<string, CProjKey>*   datatool_ids)
3392 {
3393     ITERATE(CProjectItemsTree::TProjects, p, tree.m_Projects) {
3394         const CProjKey&  project_id = p->first;
3395         if (project_id.Type() == CProjKey::eDataSpec) {
3396             continue;
3397         }
3398         const CProjItem& project    = p->second;
3399         ITERATE(list<CDataToolGeneratedSrc>, n, project.m_DatatoolSources) {
3400             const CDataToolGeneratedSrc& src = *n;
3401             string src_abs_path =
3402                 CDirEntry::ConcatPath(src.m_SourceBaseDir, src.m_SourceFile);
3403             string src_rel_path =
3404                 CDirEntry::CreateRelativePath
3405                                  (GetApp().GetProjectTreeInfo().m_Src,
3406                                   src_abs_path);
3407             (*datatool_ids)[src_rel_path] = project_id;
3408         }
3409     }
3410 }
3411 
3412 
AddDatatoolSourcesDepends(CProjectItemsTree * tree)3413 void CProjectTreeBuilder::AddDatatoolSourcesDepends(CProjectItemsTree* tree)
3414 {
3415     //datatool src rel path / project ID
3416 
3417     // 1. Collect all projects with datatool-generated-sources
3418     map<string, CProjKey> whole_datatool_ids;
3419     bool whole_collected = false;
3420     if (GetApp().IsScanningWholeTree()) {
3421         whole_collected = true;
3422         s_CollectDatatoolIds(GetApp().GetWholeTree(), &whole_datatool_ids);
3423     }
3424 
3425     // 2. Extent tree to accomodate more ASN projects if necessary
3426     bool tree_extented = false;
3427     map<string, CProjKey> datatool_ids;
3428 
3429     do {
3430 
3431         tree_extented = false;
3432         s_CollectDatatoolIds(*tree, &datatool_ids);
3433 
3434         CProjectItemsTree::TProjects added;
3435 
3436         NON_CONST_ITERATE(CProjectItemsTree::TProjects, p, tree->m_Projects) {
3437 //            const CProjKey&  project_id = p->first;
3438             CProjItem& project          = p->second;
3439             ITERATE(list<CDataToolGeneratedSrc>, n, project.m_DatatoolSources) {
3440                 const CDataToolGeneratedSrc& src = *n;
3441                 ITERATE(list<string>, i, src.m_ImportModules) {
3442                     const string& module = *i;
3443                     map<string, CProjKey>::const_iterator j =
3444                         datatool_ids.find(module);
3445                     if (j == datatool_ids.end()) {
3446                         if (!whole_collected) {
3447                             whole_collected = true;
3448                             s_CollectDatatoolIds(GetApp().GetWholeTree(), &whole_datatool_ids);
3449                         }
3450                         j = whole_datatool_ids.find(module);
3451                         if (j != whole_datatool_ids.end()) {
3452                             const CProjKey& depends_id = j->second;
3453 #if 1
3454 datatool_ids[module] = depends_id;
3455 added[depends_id] = GetApp().GetWholeTree().m_Projects.find(depends_id)->second;
3456 #else
3457                             tree->m_Projects[depends_id] =
3458                                 GetApp().GetWholeTree().m_Projects.find(depends_id)->second;
3459                             tree_extented = true;
3460 #endif
3461                         }
3462                     }
3463                 }
3464             }
3465         }
3466 #if 1
3467         tree_extented = !added.empty();
3468         ITERATE(CProjectItemsTree::TProjects, p, added) {
3469             tree->m_Projects[p->first] = p->second;
3470         }
3471 #endif
3472     } while( tree_extented );
3473 
3474 
3475     CProjKey proj_key(CProjKey::eDataSpec, GetApp().GetDataspecProjId());
3476     CProjectItemsTree::TProjects::iterator z = tree->m_Projects.find(proj_key);
3477 
3478     // 3. Finally - generate depends
3479     NON_CONST_ITERATE(CProjectItemsTree::TProjects, p, tree->m_Projects) {
3480         const CProjKey&  project_id = p->first;
3481         if (project_id.Type() == CProjKey::eDataSpec) {
3482             continue;
3483         }
3484         CProjItem& project          = p->second;
3485         ITERATE(list<CDataToolGeneratedSrc>, n, project.m_DatatoolSources) {
3486             const CDataToolGeneratedSrc& src = *n;
3487             if (z != tree->m_Projects.end()) {
3488                 z->second.m_DatatoolSources.push_back(src);
3489             }
3490             ITERATE(list<string>, i, src.m_ImportModules) {
3491                 const string& module = *i;
3492                 map<string, CProjKey>::const_iterator j =
3493                     datatool_ids.find(module);
3494                 if (j != datatool_ids.end()) {
3495                     const CProjKey& depends_id = j->second;
3496                     if (depends_id != project_id) {
3497                         project.m_Depends.push_back(depends_id);
3498                         project.m_Depends.sort();
3499                         project.m_Depends.unique();
3500                     }
3501                 }
3502             }
3503         }
3504     }
3505 
3506 }
3507 
3508 
3509 END_NCBI_SCOPE
3510