1 /* $Id: proj_builder_app.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_builder_app.hpp"
32 #include "proj_item.hpp"
33 #include "proj_tree_builder.hpp"
34 #include "msvc_prj_utils.hpp"
35 #include "msvc_prj_generator.hpp"
36 #include "mac_prj_generator.hpp"
37 #include "msvc_sln_generator.hpp"
38 #include "msvc_masterproject_generator.hpp"
39 #include "proj_utils.hpp"
40 #include "msvc_configure.hpp"
41 #include "msvc_prj_defines.hpp"
42 #include "msvc_configure_prj_generator.hpp"
43 #include "proj_projects.hpp"
44 #include "configurable_file.hpp"
45 #include "ptb_err_codes.hpp"
46 #include <corelib/ncbitime.hpp>
47 #include <corelib/expr.hpp>
48 
49 #include <common/test_assert.h>  /* This header must go last */
50 
51 
52 // special task
53 #define DO_PATCHTREEMAKEFILES  0
54 
55 BEGIN_NCBI_SCOPE
56 
57 
58 /////////////////////////////////////////////////////////////////////////////
59 ///
60 /// Windows-specific command-line logger
61 /// This is used to format error output in such a way that the Windows error
62 /// logger can pick this up
63 
64 class CWindowsCmdErrorHandler : public CDiagHandler
65 {
66 public:
67 
CWindowsCmdErrorHandler()68     CWindowsCmdErrorHandler()
69     {
70         m_OrigHandler.reset(GetDiagHandler(true));
71         CNcbiApplication* app = CNcbiApplication::Instance();
72         if (app) {
73             m_AppName = app->GetProgramDisplayName();
74         } else {
75             m_AppName = "unknown_app";
76         }
77     }
78 
~CWindowsCmdErrorHandler()79     ~CWindowsCmdErrorHandler()
80     {
81     }
82 
83     /// post a message
Post(const SDiagMessage & msg)84     void Post(const SDiagMessage& msg)
85     {
86         if (m_OrigHandler.get()) {
87             m_OrigHandler->Post(msg);
88         }
89 
90         CTempString str(msg.m_Buffer, msg.m_BufferLen);
91         if (!msg.m_Buffer) {
92             str.assign(kEmptyStr.c_str(),0);
93         }
94 
95         /// screen for error message level data only
96         /// MSVC doesn't handle the other parts
97         switch (msg.m_Severity) {
98         case eDiag_Error:
99         case eDiag_Critical:
100         case eDiag_Fatal:
101         case eDiag_Warning:
102             break;
103 
104         case eDiag_Info:
105         case eDiag_Trace:
106             if (msg.m_ErrCode == ePTB_NoError) {
107                 /// simple pass-through to stderr
108                 if (strlen(msg.m_File) != 0) {
109                     cerr << msg.m_File << ": ";
110                 }
111                 cerr << str << endl;
112                 return;
113             }
114             break;
115         }
116 
117         /// REQUIRED: origin
118         if (strlen(msg.m_File) == 0) {
119             cerr << m_AppName;
120         } else {
121             cerr << msg.m_File;
122         }
123         if (msg.m_Line) {
124             cerr << "(" << msg.m_Line << ")";
125         }
126         cerr << ": ";
127 
128         /// OPTIONAL: subcategory
129         //cerr << m_AppName << " ";
130 
131         /// REQUIRED: category
132         /// the MSVC system understands only 'error' and 'warning'
133         switch (msg.m_Severity) {
134         case eDiag_Error:
135         case eDiag_Critical:
136         case eDiag_Fatal:
137             cerr << "error ";
138             break;
139 
140         case eDiag_Warning:
141             cerr << "warning ";
142             break;
143 
144         case eDiag_Info:
145         case eDiag_Trace:
146             /// FIXME: find out how to get this in the messages tab
147             cerr << "info ";
148             break;
149         }
150 
151         /// REQUIRED: error code
152         cerr << msg.m_ErrCode << ": ";
153 
154         /// OPTIONAL: text
155         cerr << str << endl;
156     }
157 
158 private:
159     unique_ptr<CDiagHandler> m_OrigHandler;
160 
161     /// the original diagnostics handler
162     string        m_AppName;
163 
164 };
165 
166 /////////////////////////////////////////////////////////////////////////////
167 
168 
169 // When defined, this environment variable
170 // instructs PTB to exclude CONFIGURE, INDEX, and HIERARCHICAL VIEW
171 // projects
172 const char* s_ptb_skipconfig = "__PTB__SKIP__CONFIG__";
173 
174 #ifdef COMBINED_EXCLUDE
175 struct PIsExcludedByProjectMakefile
176 {
177     typedef CProjectItemsTree::TProjects::value_type TValueType;
operator ()PIsExcludedByProjectMakefile178     bool operator() (const TValueType& item) const
179     {
180         const CProjItem& project = item.second;
181         CMsvcPrjProjectContext prj_context(project);
182         const list<string> implicit_exclude_dirs =
183             GetApp().GetProjectTreeInfo().m_ImplicitExcludedAbsDirs;
184         ITERATE(list<string>, p, implicit_exclude_dirs) {
185             const string& dir = *p;
186             if ( IsSubdir(dir, project.m_SourcesBaseDir) ) {
187                 // implicitly excluded from build
188                 return prj_context.GetMsvcProjectMakefile().IsExcludeProject
189                                                                         (true);
190             }
191         }
192         // implicitly included to build
193         return prj_context.GetMsvcProjectMakefile().IsExcludeProject(false);
194     }
195 };
196 
197 
198 struct PIsExcludedMakefileIn
199 {
200     typedef CProjectItemsTree::TProjects::value_type TValueType;
201 
PIsExcludedMakefileInPIsExcludedMakefileIn202     PIsExcludedMakefileIn(const string& root_src_dir)
203         :m_RootSrcDir(CDirEntry::NormalizePath(root_src_dir))
204     {
205         ProcessDir(root_src_dir);
206     }
207 
operator ()PIsExcludedMakefileIn208     bool operator() (const TValueType& item) const
209     {
210         const CProjItem& project = item.second;
211 
212         const list<string> implicit_exclude_dirs =
213             GetApp().GetProjectTreeInfo().m_ImplicitExcludedAbsDirs;
214         ITERATE(list<string>, p, implicit_exclude_dirs) {
215             const string& dir = *p;
216             if ( IsSubdir(dir, project.m_SourcesBaseDir) ) {
217                 // implicitly excluded from build
218                 return !IsExcplicitlyIncluded(project.m_SourcesBaseDir);
219             }
220         }
221         return false;
222     }
223 
224 private:
225     string m_RootSrcDir;
226 
227     typedef map<string, AutoPtr<CPtbRegistry> > TMakefiles;
228     TMakefiles m_Makefiles;
229 
ProcessDirPIsExcludedMakefileIn230     void ProcessDir(const string& dir_name)
231     {
232         CDir dir(dir_name);
233         CDir::TEntries contents = dir.GetEntries("*");
234         ITERATE(CDir::TEntries, i, contents) {
235             string name  = (*i)->GetName();
236             if ( name == "."  ||  name == ".."  ||
237                  name == string(1,CDir::GetPathSeparator()) ) {
238                 continue;
239             }
240             string path = (*i)->GetPath();
241 
242             if ( (*i)->IsFile()        &&
243                 name          == "Makefile.in.msvc" ) {
244                 m_Makefiles[path] =
245                     AutoPtr<CPtbRegistry>
246                          (new CPtbRegistry(CNcbiIfstream(path.c_str(),
247                                             IOS_BASE::in | IOS_BASE::binary)));
248             }
249             else if ( (*i)->IsDir() ) {
250 
251                 ProcessDir(path);
252             }
253         }
254     }
255 
IsExcplicitlyIncludedPIsExcludedMakefileIn256     bool IsExcplicitlyIncluded(const string& project_base_dir) const
257     {
258         string dir = project_base_dir;
259         for(;;) {
260 
261             if (dir == m_RootSrcDir)
262                 return false;
263             string path = CDirEntry::ConcatPath(dir, "Makefile.in.msvc");
264             TMakefiles::const_iterator p =
265                 m_Makefiles.find(path);
266             if ( p != m_Makefiles.end() ) {
267                 string val =
268                     (p->second)->GetString("Common", "ExcludeProject");
269                 if (val == "FALSE")
270                     return true;
271             }
272 
273             dir = CDirEntry::ConcatPath(dir, "..");
274             dir = CDirEntry::NormalizePath(dir);
275         }
276 
277         return false;
278     }
279 };
280 
281 
282 template <class T1, class T2, class V> class CCombine
283 {
284 public:
CCombine(const T1 & t1,const T2 & t2)285     CCombine(const T1& t1, const T2& t2)
286         :m_T1(t1), m_T2(t2)
287     {
288     }
operator ()(const V & v) const289     bool operator() (const V& v) const
290     {
291         return m_T1(v)  &&  m_T2(v);
292     }
293 private:
294     const T1 m_T1;
295     const T2 m_T2;
296 };
297 #else
298 // not def COMBINED_EXCLUDE
299 struct PIsExcludedByProjectMakefile
300 {
301     typedef CProjectItemsTree::TProjects::value_type TValueType;
operator ()PIsExcludedByProjectMakefile302     bool operator() (const TValueType& item) const
303     {
304         const CProjItem& project = item.second;
305         CMsvcPrjProjectContext prj_context(project);
306         const list<string> implicit_exclude_dirs =
307             GetApp().GetProjectTreeInfo().m_ImplicitExcludedAbsDirs;
308         ITERATE(list<string>, p, implicit_exclude_dirs) {
309             const string& dir = *p;
310             if ( IsSubdir(dir, project.m_SourcesBaseDir) ) {
311                 // implicitly excluded from build
312                 if (prj_context.GetMsvcProjectMakefile().IsExcludeProject(true)) {
313                     PTB_WARNING_EX(kEmptyStr, ePTB_ProjectExcluded,
314                         "Excluded:  project " << project.m_Name
315                         << " by ProjectTree/ImplicitExclude");
316                     return true;
317                 }
318                 return false;
319             }
320         }
321         // implicitly included into build
322         if (prj_context.GetMsvcProjectMakefile().IsExcludeProject(false)) {
323             PTB_WARNING_EX(kEmptyStr, ePTB_ProjectExcluded,
324                 "Excluded:  project " << project.m_Name
325                 << " by Makefile." << project.m_Name << ".*."
326                 << GetApp().GetRegSettings().m_MakefilesExt);
327             return true;
328         }
329         return false;
330     }
331 };
332 
333 #endif
334 
335 struct PIsExcludedByTag
336 {
337     typedef CProjectItemsTree::TProjects::value_type TValueType;
operator ()PIsExcludedByTag338     bool operator() (const TValueType& item) const
339     {
340         const CProjItem& project = item.second;
341         string unmet;
342         if ( project.m_ProjType != CProjKey::eDataSpec &&
343             !GetApp().IsAllowedProjectTag(project) ) {
344             string unmet( NStr::Join(project.m_ProjTags,","));
345             PTB_WARNING_EX(project.GetPath(), ePTB_ProjectExcluded,
346                            "Excluded due to proj_tag; this project tags: " << unmet);
347             return true;
348         }
349         return false;
350     }
351 };
352 
353 struct PIsExcludedByUser
354 {
355     typedef CProjectItemsTree::TProjects::value_type TValueType;
operator ()PIsExcludedByUser356     bool operator() (const TValueType& item) const
357     {
358         const CProjItem& project = item.second;
359         if (project.m_ProjType != CProjKey::eDll &&
360             project.m_ProjType != CProjKey::eDataSpec &&
361             !GetApp().m_CustomConfiguration.DoesValueContain(
362             "__AllowedProjects",
363             CreateProjectName(CProjKey(project.m_ProjType, project.m_ID)), true)) {
364             PTB_WARNING_EX(project.GetPath(), ePTB_ProjectExcluded,
365                            "Excluded by user request");
366             return true;
367         }
368         return false;
369 
370     }
371 };
372 
373 struct PIsExcludedByRequires
374 {
375     typedef CProjectItemsTree::TProjects::value_type TValueType;
operator ()PIsExcludedByRequires376     bool operator() (const TValueType& item) const
377     {
378         string unmet;
379         const CProjItem& project = item.second;
380         if ( !CMsvcPrjProjectContext::IsRequiresOk(project, &unmet) ) {
381             PTB_WARNING_EX(project.GetPath(), ePTB_ProjectExcluded,
382                            "Excluded due to unmet requirement: "
383                            << unmet);
384             return true;
385         }
386         return false;
387 
388     }
389 };
390 
391 struct PIsExcludedByDisuse
392 {
393     typedef CProjectItemsTree::TProjects::value_type TValueType;
operator ()PIsExcludedByDisuse394     bool operator() (const TValueType& item) const
395     {
396         const CProjItem& project = item.second;
397         if (project.m_External) {
398             PTB_WARNING_EX(project.GetPath(), ePTB_ProjectExcluded,
399                            "Excluded unused external");
400             return true;
401         }
402         return false;
403     }
404 };
405 
406 
407 //-----------------------------------------------------------------------------
CProjBulderApp(void)408 CProjBulderApp::CProjBulderApp(void)
409 {
410     SetVersion( CVersionInfo(4,8,2) );
411     m_ScanningWholeTree = false;
412     m_Dll = false;
413     m_AddMissingLibs = false;
414     m_ScanWholeTree  = true;
415     m_TweakVTuneR = false;
416     m_TweakVTuneD = false;
417     m_AddUnicode = false;
418     m_CurrentBuildTree = 0;
419     m_IncompleteBuildTree = 0;
420     m_ProjTagCmnd = false;
421     m_ConfirmCfg = false;
422     m_AllDllBuild = false;
423     m_InteractiveCfg = false;
424     m_Dtdep = false;
425     m_AddMissingDep = false;
426     m_LibDep = false;
427     m_Ide = 0;
428     m_ExitCode = 0;
429 }
430 
431 
Init(void)432 void CProjBulderApp::Init(void)
433 {
434     string logfile = GetLogFile();
435     if (CDirEntry(logfile).Exists()) {
436         RegisterGeneratedFile(CDirEntry::NormalizePath(logfile));
437     }
438     if (CMsvc7RegSettings::GetMsvcPlatform() < CMsvc7RegSettings::eUnix) {
439         if (logfile != "STDERR") {
440             SetDiagHandler(new CWindowsCmdErrorHandler);
441         }
442     }
443     // Create command-line argument descriptions class
444     unique_ptr<CArgDescriptions> arg_desc(new CArgDescriptions);
445 
446     // Specify USAGE context
447     string context;
448     if (CMsvc7RegSettings::GetMsvcPlatform() < CMsvc7RegSettings::eUnix) {
449         context = "MSVC ";
450 /*
451         context += CMsvc7RegSettings::GetProjectFileFormatVersion() +
452             " (" + CMsvc7RegSettings::GetMsvcPlatformName() + ")";
453 */
454     } else if (CMsvc7RegSettings::GetMsvcPlatform() > CMsvc7RegSettings::eUnix) {
455         context = "XCODE ";
456 /*
457         context += CMsvc7RegSettings::GetMsvcVersionName() +
458             " (" + CMsvc7RegSettings::GetMsvcPlatformName() + ")";
459 */
460     } else {
461         context = CMsvc7RegSettings::GetMsvcPlatformName();
462     }
463     context += " projects tree builder application";
464     arg_desc->SetUsageContext(GetArguments().GetProgramBasename(),context);
465 
466     // Programm arguments:
467 
468     arg_desc->AddPositional("root",
469                             "Root directory of the build tree. "\
470                                 "This directory ends with \"c++\".",
471                             CArgDescriptions::eString);
472 
473     arg_desc->AddPositional("subtree",
474                             "Subtree, or a file with a list of subtrees to build."\
475                             " Examples: src/corelib/ scripts/projects/ncbi_cpp.lst",
476                             CArgDescriptions::eString);
477 
478     arg_desc->AddPositional("solution",
479                             "MSVC Solution to build.",
480                             CArgDescriptions::eString);
481 
482     arg_desc->AddFlag      ("dll",
483                             "Dll(s) will be built instead of static libraries.",
484                             true);
485 
486     arg_desc->AddFlag      ("nobuildptb",
487                             "Exclude \"build PTB\" step from CONFIGURE project.");
488 
489     arg_desc->AddFlag      ("ext",
490                             "Use external libraries instead of missing in-tree ones.");
491     arg_desc->AddFlag      ("nws",
492                             "Do not scan the whole source tree for missing projects.");
493     arg_desc->AddOptionalKey("extroot", "external_build_root",
494                              "Subtree in which to look for external libraries.",
495                              CArgDescriptions::eString);
496 
497     arg_desc->AddOptionalKey("projtag", "project_tag",
498                              "Expression. Include only projects that match."\
499                              " Example: \"core && (test || !demo)\"",
500                              CArgDescriptions::eString);
501 
502 #if defined(NCBI_XCODE_BUILD) || defined(PSEUDO_XCODE)
503     arg_desc->AddOptionalKey("ide", "xcode_version",
504                              "Target version of Xcode, for example: 30",
505                              CArgDescriptions::eInteger);
506     arg_desc->AddOptionalKey("arch", "architecture",
507                              "Target architecture, for example: ppc, i386",
508                              CArgDescriptions::eString);
509 #elif defined(NCBI_COMPILER_MSVC)
510     arg_desc->AddOptionalKey("ide", "msvc_version",
511                              "Target version of MS Visual Studio, for example: 1200, 1400, 1500",
512                              CArgDescriptions::eInteger);
513     arg_desc->AddOptionalKey("arch", "platform",
514                              "Target platform, for example: Win32, x64",
515                              CArgDescriptions::eString);
516 #endif
517 
518     arg_desc->AddFlag      ("cfg",
519                             "Show GUI to confirm configuration parameters (MS Windows only).");
520     arg_desc->AddFlag      ("i",
521                             "Run interactively. Can only be used by PTB GUI shell!");
522     arg_desc->AddFlag      ("dtdep",
523                             "Add dependency on datatool where needed.");
524     arg_desc->AddFlag      ("noadddep",
525                             "Do not add missing dependencies.");
526     arg_desc->AddDefaultKey("libdep", "LibraryDependencies",
527          "Analyze dependencies and generate library info for linker on Unix",
528          CArgDescriptions::eBoolean, "true");
529 
530     arg_desc->AddOptionalKey("args", "args_file",
531                              "Read arguments from a file",
532                              CArgDescriptions::eString);
533 
534     // Setup arg.descriptions for this application
535     SetupArgDescriptions(arg_desc.release());
536 }
537 
538 
539 static
s_ReportDependenciesStatus(const CCyclicDepends::TDependsCycles & cycles,CProjectItemsTree::TProjects & tree)540 void s_ReportDependenciesStatus(const CCyclicDepends::TDependsCycles& cycles,
541     CProjectItemsTree::TProjects& tree)
542 {
543     bool reported = false;
544     ITERATE(CCyclicDepends::TDependsCycles, p, cycles) {
545         const CCyclicDepends::TDependsChain& cycle = *p;
546         bool real_cycle = false;
547         string host0, host;
548         ITERATE(CCyclicDepends::TDependsChain, m, cycle) {
549             host = tree[*m].m_DllHost;
550             if (m == cycle.begin()) {
551                 host0 = host;
552             } else {
553                 real_cycle = (host0 != host) || (host0.empty() && host.empty());
554                 if (real_cycle) {
555                     break;
556                 }
557             }
558         }
559         if (!real_cycle) {
560             continue;
561         }
562         string str_chain("Dependency cycle found: ");
563         ITERATE(CCyclicDepends::TDependsChain, n, cycle) {
564             const CProjKey& proj_id = *n;
565             if (n != cycle.begin()) {
566                 str_chain += " - ";
567             }
568             str_chain += proj_id.Id();
569         }
570         PTB_WARNING_EX(kEmptyStr, ePTB_ConfigurationError, str_chain);
571         reported = true;
572         CCyclicDepends::TDependsChain::const_iterator i = cycle.end();
573         const CProjKey& last = *(--i);
574         const CProjKey& prev = *(--i);
575         if (last.Type() == CProjKey::eLib && prev.Type() == CProjKey::eLib) {
576             CProjectItemsTree::TProjects::const_iterator t = tree.find(prev);
577             if (t != tree.end()) {
578                 CProjItem item = t->second;
579                 item.m_Depends.remove(last);
580                 tree[prev] = item;
581                 PTB_WARNING_EX(kEmptyStr, ePTB_FileModified,
582                     "Removing LIB dependency: " << prev.Id() << " - " << last.Id());
583             }
584         }
585     }
586     if (!reported) {
587         PTB_INFO("No dependency cycles found.");
588     }
589 }
590 
Run(void)591 int CProjBulderApp::Run(void)
592 {
593     // Set error posting and tracing on maximum.
594 //    SetDiagTrace(eDT_Enable);
595     SetDiagPostAllFlags(eDPF_All & ~eDPF_DateTime);
596     SetDiagPostLevel(eDiag_Info);
597     PTB_INFO("Started at " + CTime(CTime::eCurrent).AsString());
598     PTB_INFO("Project tree builder version " + GetVersion().Print());
599 
600     CStopWatch sw;
601     sw.Start();
602 
603     // Get and check arguments
604     ParseArguments();
605     PTB_INFO("Project tags filter: " + m_ProjTags);
606     if (m_InteractiveCfg && !Gui_ConfirmConfiguration())
607     {
608         PTB_INFO("Cancelled by request.");
609         return 1;
610     }
611     else if (m_ConfirmCfg && !ConfirmConfiguration())
612     {
613         PTB_INFO("Cancelled by request.");
614         return 1;
615     }
616     VerifyArguments();
617     m_CustomConfiguration.Save(m_CustomConfFile);
618 
619     // Configure
620     CMsvcConfigure configure;
621     configure.Configure(const_cast<CMsvcSite&>(GetSite()),
622                         GetRegSettings().m_ConfigInfo,
623                         m_IncDir);
624     m_AllDllBuild = GetSite().IsProvided("DLL_BUILD");
625 
626 #if DO_PATCHTREEMAKEFILES
627     // this is just a task; it is to be run very rarely
628     {
629         bool b = m_ScanWholeTree;
630         m_ScanWholeTree = true;
631         CMakefilePatch::PatchTreeMakefiles(GetWholeTree());
632         m_ScanWholeTree = b;
633         return 0;
634     }
635 #endif
636     // Build projects tree
637 //#ifndef _DEBUG
638 // I need this to collect library relations data and metadata
639     {
640         bool b = m_ScanWholeTree;
641         m_ScanWholeTree = true;
642         GetWholeTree();
643         m_ScanWholeTree = b;
644     }
645 //#endif
646 
647     CProjectItemsTree projects_tree(GetProjectTreeInfo().m_Src);
648     CProjectTreeBuilder::BuildProjectTree(GetProjectTreeInfo().m_IProjectFilter.get(),
649                                           GetProjectTreeInfo().m_Src,
650                                           &projects_tree);
651     if (m_ExitCode != 0) {
652         PTB_INFO("Cancelled by request.");
653         return m_ExitCode;
654     }
655     configure.CreateConfH(const_cast<CMsvcSite&>(GetSite()),
656                         GetRegSettings().m_ConfigInfo,
657                         m_IncDir);
658 
659     // MSVC specific part:
660     PTB_INFO("Checking project requirements...");
661     // Exclude some projects from build:
662 #ifdef COMBINED_EXCLUDE
663     {{
664         // Implicit/Exclicit exclude by msvc Makefiles.in.msvc
665         // and project .msvc makefiles.
666         PIsExcludedMakefileIn          p_make_in(GetProjectTreeInfo().m_Src);
667         PIsExcludedByProjectMakefile   p_project_makefile;
668         CCombine<PIsExcludedMakefileIn,
669                  PIsExcludedByProjectMakefile,
670                  CProjectItemsTree::TProjects::value_type>
671                                   logical_combine(p_make_in, p_project_makefile);
672         EraseIf(projects_tree.m_Projects, logical_combine);
673     }}
674 #else
675     {{
676         // Implicit/Exclicit exclude by msvc Makefiles.in.msvc
677         PIsExcludedByProjectMakefile   p_project_makefile;
678         EraseIf(projects_tree.m_Projects, p_project_makefile);
679     }}
680 
681 #endif
682     {{
683         // Project requires are not provided
684         EraseIf(projects_tree.m_Projects, PIsExcludedByRequires());
685     }}
686 
687     CProjectItemsTree dll_projects_tree;
688     bool dll = (GetBuildType().GetType() == CBuildType::eDll);
689     if (dll) {
690         PTB_INFO("Assembling DLLs...");
691 //        AnalyzeDllData(projects_tree);
692         CreateDllBuildTree(projects_tree, &dll_projects_tree);
693     }
694     CProjectItemsTree& prj_tree = dll ? dll_projects_tree : projects_tree;
695     prj_tree.VerifyExternalDepends();
696     {{
697         // Erase obsolete external projects
698         EraseIf(prj_tree.m_Projects, PIsExcludedByDisuse());
699     }}
700     prj_tree.VerifyDataspecProj();
701 
702     PTB_INFO("Checking project inter-dependencies...");
703     CCyclicDepends::TDependsCycles cycles;
704     CCyclicDepends::FindCyclesNew(prj_tree.m_Projects, &cycles);
705     s_ReportDependenciesStatus(cycles,projects_tree.m_Projects);
706 
707     if (!m_SuspiciousProj.empty()) {
708         ITERATE( set<CProjKey>, key, m_SuspiciousProj) {
709             if (prj_tree.m_Projects.find(*key) != prj_tree.m_Projects.end()) {
710                 PTB_ERROR(prj_tree.m_Projects.find(*key)->second.GetPath(),
711                     "More than one target with this name");
712                 m_ExitCode = 1;
713             }
714         }
715     }
716     if (m_ExitCode != 0) {
717         string subtree = CDirEntry::ConcatPath(m_ProjectTreeInfo->m_Root, m_Subtree);
718         if (CDirEntry(subtree).IsFile()) {
719             return m_ExitCode;
720         }
721         m_ExitCode = 0;
722     }
723     PTB_INFO("Creating projects...");
724     if (CMsvc7RegSettings::GetMsvcPlatform() < CMsvc7RegSettings::eUnix) {
725         GenerateMsvcProjects(prj_tree);
726     }
727     else if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eUnix) {
728         GenerateUnixProjects(prj_tree);
729     }
730     else {
731         GenerateMacProjects(prj_tree);
732     }
733     ReportGeneratedFiles();
734     ReportProjectWatchers();
735     //
736     PTB_INFO("Done.  Elapsed time = " << sw.Elapsed() << " seconds");
737     return m_ExitCode;
738 }
739 
GenerateMsvcProjects(CProjectItemsTree & projects_tree)740 void CProjBulderApp::GenerateMsvcProjects(CProjectItemsTree& projects_tree)
741 {
742 #if NCBI_COMPILER_MSVC
743     PTB_INFO("Generating MSBuild projects...");
744 
745     bool dll = (GetBuildType().GetType() == CBuildType::eDll);
746     list<SConfigInfo> dll_configs;
747     const list<SConfigInfo>* configurations = 0;
748     bool skip_config = !GetEnvironment().Get(s_ptb_skipconfig).empty();
749     string str_config;
750 
751     if (dll) {
752         _TRACE("DLL build");
753         GetBuildConfigs(&dll_configs);
754         configurations = &dll_configs;
755     } else {
756         _TRACE("Static build");
757         configurations = &GetRegSettings().m_ConfigInfo;
758     }
759     {{
760         ITERATE(list<SConfigInfo>, p , *configurations) {
761             str_config += p->GetConfigFullName() + " ";
762         }
763         PTB_INFO("Building configurations: " << str_config);
764     }}
765 
766     m_CurrentBuildTree = &projects_tree;
767     if ( m_AddMissingLibs ) {
768         m_IncompleteBuildTree = &projects_tree;
769     }
770     // Projects
771     CMsvcProjectGenerator prj_gen(*configurations);
772     CMsvcProjectGenerator::GeneratePropertySheets();
773     NON_CONST_ITERATE(CProjectItemsTree::TProjects, p, projects_tree.m_Projects) {
774         prj_gen.Generate(p->second);
775     }
776 
777     //Utility projects dir
778     string utility_projects_dir = GetApp().GetUtilityProjectsDir();
779 
780     // MasterProject
781     CMsvcMasterProjectGenerator master_prj_gen(projects_tree,
782                                                *configurations,
783                                                utility_projects_dir);
784     if (!skip_config) {
785         master_prj_gen.SaveProject();
786     }
787 
788     // ConfigureProject
789     string output_dir = GetProjectTreeInfo().m_Compilers;
790     output_dir = CDirEntry::ConcatPath(output_dir,
791                                         GetRegSettings().m_CompilersSubdir);
792     output_dir = CDirEntry::ConcatPath(output_dir,
793         (m_BuildPtb && dll) ? "static" : GetBuildType().GetTypeStr());
794     output_dir = CDirEntry::ConcatPath(output_dir, "bin");
795     output_dir = CDirEntry::AddTrailingPathSeparator(output_dir);
796     CMsvcConfigureProjectGenerator configure_generator(
797                                             output_dir,
798                                             *configurations,
799                                             dll,
800                                             utility_projects_dir,
801                                             GetProjectTreeInfo().m_Root,
802                                             m_Subtree,
803                                             m_Solution,
804                                             m_BuildPtb);
805     if (!skip_config) {
806         configure_generator.SaveProject(false, &prj_gen);
807         configure_generator.SaveProject(true, &prj_gen);
808     }
809 
810     // INDEX dummy project
811     string index_prj_path = CDirEntry::ConcatPath(utility_projects_dir, "_INDEX_");
812     index_prj_path += CMsvc7RegSettings::GetVcprojExt();
813     string index_prj_guid, index_prj_name;
814     if (CMsvc7RegSettings::GetMsvcVersion() < CMsvc7RegSettings::eMsvc1000) {
815         CVisualStudioProject xmlprj;
816         CreateUtilityProject(" INDEX, see here: ", *configurations, &xmlprj);
817         if (!skip_config) {
818             SaveIfNewer(index_prj_path, xmlprj);
819             index_prj_guid = xmlprj.GetAttlist().GetProjectGUID();
820             index_prj_name = xmlprj.GetAttlist().GetName();
821         }
822     }
823 
824     string utils[] = {"_DATASPEC_ALL_", "-DATASPEC-ALL-",
825                       "_LIBS_ALL_", "-LIBS-ALL-",
826                       "_BUILD_ALL_","-BUILD-ALL-"};
827     vector<string> utils_id;
828     int i = 0, num_util = 3;
829 
830     for (i = 0; i < num_util; ++i) {
831         string prj_file(utils[i*2]);
832         string prj_name(utils[i*2+1]);
833         if (CMsvc7RegSettings::GetMsvcVersion() >= CMsvc7RegSettings::eMsvc1100) {
834             NStr::ReplaceInPlace(prj_name,"-", "_");
835         }
836         string prj_path = CDirEntry::ConcatPath(utility_projects_dir, prj_file);
837         prj_path += CMsvc7RegSettings::GetVcprojExt();
838         utils_id.push_back(prj_path);
839         if (CMsvc7RegSettings::GetMsvcVersion() < CMsvc7RegSettings::eMsvc1000) {
840             CVisualStudioProject xmlprj;
841             CreateUtilityProject(prj_name, *configurations, &xmlprj);
842             SaveIfNewer(prj_path, xmlprj);
843             utils_id.push_back(xmlprj.GetAttlist().GetProjectGUID());
844             utils_id.push_back(xmlprj.GetAttlist().GetName());
845         } else {
846             string prj_dir =  GetApp().GetUtilityProjectsSrcDir();
847             CProjItem prj_item( CreateUtilityProjectItem(prj_dir, prj_name));
848             prj_gen.Generate(prj_item);
849             utils_id.push_back(prj_item.m_GUID);
850             utils_id.push_back(prj_item.m_Name);
851         }
852     }
853     if (m_ProjTags == "*") {
854         for (map<string,string>::const_iterator composite = m_CompositeProjectTags.begin();
855             composite != m_CompositeProjectTags.end(); ++composite) {
856             string composite_name = "_TAG_" + composite->first;
857             string composite_filter = composite->second;
858 
859 
860             string prj_path = CDirEntry::ConcatPath(utility_projects_dir, composite_name);
861             prj_path += CMsvc7RegSettings::GetVcprojExt();
862             utils_id.push_back(prj_path);
863             if (CMsvc7RegSettings::GetMsvcVersion() < CMsvc7RegSettings::eMsvc1000) {
864                 CVisualStudioProject xmlprj;
865                 CreateUtilityProject(composite_name, *configurations, &xmlprj);
866                 SaveIfNewer(prj_path, xmlprj);
867                 utils_id.push_back(xmlprj.GetAttlist().GetProjectGUID());
868                 utils_id.push_back(xmlprj.GetAttlist().GetName());
869             } else {
870                 string prj_dir =  GetApp().GetUtilityProjectsSrcDir();
871                 CProjItem prj_item( CreateUtilityProjectItem(prj_dir, composite_name));
872                 prj_gen.Generate(prj_item);
873                 utils_id.push_back(prj_item.m_GUID);
874                 utils_id.push_back(prj_item.m_Name);
875             }
876             utils_id.push_back(composite_filter);
877             ++num_util;
878         }
879     }
880 
881     // Solution
882     CMsvcSolutionGenerator sln_gen(*configurations);
883     ITERATE(CProjectItemsTree::TProjects, p, projects_tree.m_Projects) {
884         sln_gen.AddProject(p->second);
885     }
886     if (!skip_config) {
887 
888         if (CMsvc7RegSettings::GetMsvcVersion() < CMsvc7RegSettings::eMsvc1000) {
889             sln_gen.AddUtilityProject( master_prj_gen.GetPath(),
890                 master_prj_gen.GetVisualStudioProject().GetAttlist().GetProjectGUID(),
891                 master_prj_gen.GetVisualStudioProject().GetAttlist().GetName());
892 
893             sln_gen.AddUtilityProject( index_prj_path, index_prj_guid, index_prj_name);
894         }
895 
896         string cfg_path, cfg_guid, cfg_name;
897         configure_generator.GetVisualStudioProject(cfg_path, cfg_guid, cfg_name, false);
898         sln_gen.AddConfigureProject( cfg_path, cfg_guid, cfg_name);
899 
900         configure_generator.GetVisualStudioProject(cfg_path, cfg_guid, cfg_name, true);
901         sln_gen.AddConfigureProject( cfg_path, cfg_guid, cfg_name);
902     }
903 
904     int u = 0;
905     for (i = 0; i < num_util; ++i) {
906         switch (i) {
907         case 0:
908             sln_gen.AddAsnAllProject(   utils_id[u],  utils_id[u+1],  utils_id[u+2]);
909             u += 3;
910             break;
911         case 1:
912             sln_gen.AddLibsAllProject(  utils_id[u],  utils_id[u+1],  utils_id[u+2]);
913             u += 3;
914             break;
915         case 2:
916             sln_gen.AddBuildAllProject( utils_id[u],  utils_id[u+1],  utils_id[u+2]);
917             u += 3;
918             break;
919         default:
920             sln_gen.AddTagProject( utils_id[u],  utils_id[u+1],  utils_id[u+2],  utils_id[u+3]);
921             u += 4;
922             break;
923         }
924     }
925 
926     sln_gen.SaveSolution(m_Solution);
927 
928     CreateCheckList(configurations, projects_tree);
929     list<string> enabled, disabled;
930     CreateFeaturesAndPackagesFiles(configurations, enabled, disabled);
931     GenerateSummary(*configurations, enabled, disabled);
932 #endif //NCBI_COMPILER_MSVC
933 }
934 
GenerateMacProjects(CProjectItemsTree & projects_tree)935 void CProjBulderApp::GenerateMacProjects(CProjectItemsTree& projects_tree)
936 {
937 #if defined(NCBI_XCODE_BUILD) || defined(PSEUDO_XCODE)
938     PTB_INFO("Generating XCode projects...");
939 
940     bool dll = (GetBuildType().GetType() == CBuildType::eDll);
941     list<SConfigInfo> dll_configs;
942     const list<SConfigInfo>* configurations = 0;
943 //    bool skip_config = !GetEnvironment().Get(s_ptb_skipconfig).empty();
944     string str_config;
945 
946     if (dll) {
947         _TRACE("DLL build");
948         GetBuildConfigs(&dll_configs);
949         configurations = &dll_configs;
950     } else {
951         _TRACE("Static build");
952         configurations = &GetRegSettings().m_ConfigInfo;
953     }
954     {{
955         ITERATE(list<SConfigInfo>, p , *configurations) {
956             str_config += p->GetConfigFullName() + " ";
957         }
958         PTB_INFO("Building configurations: " << str_config);
959     }}
960 
961     m_CurrentBuildTree = &projects_tree;
962     if ( m_AddMissingLibs ) {
963         m_IncompleteBuildTree = &projects_tree;
964     }
965     // Projects
966     CMacProjectGenerator prj_gen(*configurations, projects_tree);
967     prj_gen.Generate(m_Solution);
968 
969     CreateCheckList(configurations, projects_tree);
970     list<string> enabled, disabled;
971     CreateFeaturesAndPackagesFiles(configurations, enabled, disabled);
972     GenerateSummary(*configurations, enabled, disabled);
973 #endif
974 }
CollectLibToLibDependencies(CProjectItemsTree & projects_tree,set<string> & dep,set<string> & visited,CProjectItemsTree::TProjects::const_iterator & lib,CProjectItemsTree::TProjects::const_iterator & lib_dep)975 void CProjBulderApp::CollectLibToLibDependencies(
976     CProjectItemsTree& projects_tree,
977     set<string>& dep, set<string>& visited,
978     CProjectItemsTree::TProjects::const_iterator& lib,
979     CProjectItemsTree::TProjects::const_iterator& lib_dep)
980 {
981     string lib_name(CreateProjectName(lib->first));
982     string lib_dep_name(CreateProjectName(lib_dep->first));
983     if (m_AllDllBuild) {
984         dep.insert(lib_dep_name);
985 //        return;
986     }
987     if (visited.find(lib_dep_name) != visited.end() ||
988         lib_dep_name == lib_name) {
989         return;
990     }
991     visited.insert(lib_dep_name);
992     if (!lib_dep->second.m_DatatoolSources.empty() ||
993         !lib_dep->second.m_ExportHeaders.empty() ||
994         lib->second.m_UnconditionalDepends.find(lib_dep->first) !=
995             lib->second.m_UnconditionalDepends.end()) {
996         dep.insert(lib_dep_name);
997     }
998     ITERATE(list<CProjKey>, p, lib_dep->second.m_Depends) {
999         if (p->Type() == CProjKey::eLib) {
1000             CProjectItemsTree::TProjects::const_iterator n =
1001                 projects_tree.m_Projects.find(*p);
1002             if (n != projects_tree.m_Projects.end()) {
1003                 CollectLibToLibDependencies(projects_tree, dep, visited, lib, n);
1004             }
1005         }
1006     }
1007 }
1008 
GenerateUnixProjects(CProjectItemsTree & projects_tree)1009 void CProjBulderApp::GenerateUnixProjects(CProjectItemsTree& projects_tree)
1010 {
1011     map< string, list< string > > path_to_target;
1012     string solution_dir(CDirEntry(m_Solution).GetDir());
1013     CNcbiOfstream ofs(m_Solution.c_str(), IOS_BASE::out | IOS_BASE::trunc);
1014     if (!ofs.is_open()) {
1015         NCBI_THROW(CProjBulderAppException, eFileOpen, m_Solution);
1016         return;
1017     }
1018     GetApp().RegisterGeneratedFile( m_Solution );
1019     ofs << "# This file was generated by PROJECT_TREE_BUILDER v"
1020         <<  GetVersion().Print() << endl;
1021     ofs << "# on " << CTime(CTime::eCurrent).AsString() << endl << endl;
1022 
1023 // see CXX-950
1024 #if 0
1025     ofs << "# This is tricky part; it might work incorrectly on some platforms" << endl;
1026 //    ofs << "MARK=$(shell date +%Y%m%d%H%M%S)" << endl;
1027     ofs << "MARK=$(if $(MARK2),,$(eval MARK2=$(shell date +%Y%m%d%H%M%S)))$(MARK2)" << endl;
1028     ofs << "MARK:sh =date +%Y%m%d%H%M%S" << endl;
1029     ofs << endl;
1030     ofs << "prefix=.ncbi.signal." << endl;
1031     ofs << "s=$(prefix)$(MARK)" << endl;
1032     ofs << "sign=rm -f $(prefix)*.$@; touch $(s).$@" << endl;
1033     ofs << endl;
1034 #endif
1035 
1036     ofs << "MINPUT=" << CDirEntry(m_Solution).GetName() << endl << endl;
1037     ofs << "# Use empty MTARGET to build a project;" << endl;
1038     ofs << "# MTARGET=clean - to clean, or MTARGET=purge - to purge" << endl;
1039     ofs << "MTARGET =" << endl << endl;
1040 
1041     if (m_ExtSrcRoot.empty()) {
1042        ofs << "top_srcdir=" << m_Root << endl;
1043     } else {
1044         ofs << "top_srcdir=" << m_ExtSrcRoot << endl;
1045     }
1046     ofs << "# Non-redundant flags (will be overridden for GNU Make to avoid" << endl;
1047     ofs << "# --jobserver-fds=* proliferation)" << endl;
1048     ofs << "MFLAGS_NR = $(MFLAGS)" << endl;
1049     ofs << "SKIP_PRELIMINARIES= sources= configurables=configurables.null" << endl;
1050 
1051 // all dirs -----------------------------------------------------------------
1052     list<string> all_dirs;
1053     ITERATE(CProjectItemsTree::TProjects, p, projects_tree.m_Projects) {
1054         if (p->first.Type() == CProjKey::eDataSpec) {
1055             continue;
1056         }
1057         all_dirs.push_back(
1058             CDirEntry::DeleteTrailingPathSeparator( CDirEntry::CreateRelativePath(
1059                 GetProjectTreeInfo().m_Src,p->second.m_SourcesBaseDir)));
1060     }
1061     all_dirs.sort();
1062     all_dirs.unique();
1063     ofs << "all_dirs =";
1064     ITERATE(list<string>, p, all_dirs) {
1065         ofs << " \\" <<endl << "    " << *p;
1066     }
1067     ofs << endl << endl;
1068 
1069     ofs << "include $(top_srcdir)/src/build-system/Makefile.is_gmake" << endl;
1070     ofs << "include $(top_srcdir)/src/build-system/Makefile.meta.$(is_gmake)" << endl;
1071     ofs << endl;
1072 
1073     string dotreal(".real");
1074     string dotfiles(".files");
1075 
1076 // all projects -------------------------------------------------------------
1077     ofs << "all_projects =";
1078     ITERATE(CProjectItemsTree::TProjects, p, projects_tree.m_Projects) {
1079         if (p->second.m_MakeType == eMakeType_Excluded ||
1080             p->second.m_MakeType == eMakeType_ExcludedByReq) {
1081             PTB_INFO("For reference only: " << CreateProjectName(p->first));
1082             continue;
1083         }
1084         if (p->first.Type() == CProjKey::eDataSpec) {
1085             continue;
1086         }
1087         ofs << " \\" <<endl << "    " << CreateProjectName(p->first);
1088     }
1089     ofs << endl << endl;
1090 
1091     ofs << "ptb_all :" << endl
1092         << "\t$(MAKE) $(MFLAGS_NR) -f $(MINPUT) ptb_all" << dotreal
1093         << " MTARGET=$(MTARGET)";
1094     ofs << endl << endl;
1095     ofs << "ptb_all" << dotreal << " :" << " $(all_projects:%=%" << dotreal << ")";
1096     ofs << endl << endl;
1097 
1098 // all libs -----------------------------------------------------------------
1099     ofs << "all_libraries =";
1100     ITERATE(CProjectItemsTree::TProjects, p, projects_tree.m_Projects) {
1101         if (p->second.m_MakeType == eMakeType_Excluded ||
1102             p->second.m_MakeType == eMakeType_ExcludedByReq) {
1103             continue;
1104         }
1105         if (p->first.Type() == CProjKey::eLib ||
1106             p->first.Type() == CProjKey::eDll) {
1107             ofs << " \\" <<endl << "    " << CreateProjectName(p->first);
1108         }
1109     }
1110     ofs << endl << endl;
1111 
1112     ofs << "all_libs :" << endl
1113         << "\t$(MAKE) $(MFLAGS_NR) -f $(MINPUT) all_libs" << dotreal
1114         << " MTARGET=$(MTARGET)";
1115     ofs << endl << endl;
1116     ofs << "all_libs" << dotreal << " :" << " $(all_libraries:%=%" << dotreal << ")";
1117     ofs << endl << endl;
1118 
1119 // all sources --------------------------------------------------------------
1120     ofs << "all_dataspec =";
1121     ITERATE(CProjectItemsTree::TProjects, p, projects_tree.m_Projects) {
1122         if (p->second.m_MakeType == eMakeType_Excluded ||
1123             p->second.m_MakeType == eMakeType_ExcludedByReq) {
1124             continue;
1125         }
1126         if (p->first.Type() == CProjKey::eDataSpec) {
1127             continue;
1128         }
1129         if (p->second.m_DatatoolSources.empty()) {
1130             continue;
1131         }
1132         ofs << " \\" <<endl << "    " << CreateProjectName(p->first) << dotfiles;
1133     }
1134     ofs << endl << endl;
1135 
1136     ofs << "all_files :" << endl
1137         << "\t$(MAKE) $(MFLAGS_NR) -f $(MINPUT) all_files" << dotreal;
1138     ofs << endl << endl;
1139     ofs << "all_files" << dotreal << " :" << " $(all_dataspec:%=%" << dotreal << ")";
1140     ofs << endl << endl;
1141 
1142 // all apps -----------------------------------------------------------------
1143     ofs << "all_apps =";
1144     ITERATE(CProjectItemsTree::TProjects, p, projects_tree.m_Projects) {
1145         if (p->second.m_MakeType == eMakeType_Excluded ||
1146             p->second.m_MakeType == eMakeType_ExcludedByReq) {
1147             continue;
1148         }
1149         if (p->first.Type() == CProjKey::eApp) {
1150             ofs << " \\" <<endl << "    " << CreateProjectName(p->first);
1151         }
1152     }
1153     ofs << endl << endl;
1154 
1155 // all Unix -------------------------------------------------------------
1156     ofs << "all_unix =";
1157     ITERATE(CProjectItemsTree::TProjects, p, projects_tree.m_Projects) {
1158         if (p->second.m_MakeType == eMakeType_Excluded ||
1159             p->second.m_MakeType == eMakeType_ExcludedByReq) {
1160             continue;
1161         }
1162         if (p->first.Type() == CProjKey::eMsvc) {
1163             ofs << " \\" <<endl << "    " << CreateProjectName(p->first);
1164         }
1165     }
1166     ofs << endl << endl;
1167 
1168 // all excluded -------------------------------------------------------------
1169     ofs << "all_excluded =";
1170     ITERATE(CProjectItemsTree::TProjects, p, projects_tree.m_Projects) {
1171         if (p->first.Type() == CProjKey::eDataSpec) {
1172             continue;
1173         }
1174         if (p->second.m_MakeType == eMakeType_Excluded ||
1175             p->second.m_MakeType == eMakeType_ExcludedByReq) {
1176             ofs << " \\" <<endl << "    " << CreateProjectName(p->first);
1177         }
1178     }
1179     ofs << endl << endl;
1180 
1181 // CompositeProjectTags -----------------------------------------------------
1182 // (add always)
1183     vector<string> existing_composite_names;
1184     ITERATE(set<string>, r, m_RegisteredProjectTags) {
1185         m_CompositeProjectTags[*r] = *r;
1186     }
1187     /*if (m_ProjTags == "*")*/ {
1188         for (map<string,string>::const_iterator composite = m_CompositeProjectTags.begin();
1189             composite != m_CompositeProjectTags.end(); ++composite) {
1190             string composite_name = "TAG_" + composite->first;
1191             string composite_filter = composite->second;
1192             vector<string> matching;
1193 
1194             ITERATE(CProjectItemsTree::TProjects, p, projects_tree.m_Projects) {
1195                 if (p->second.m_MakeType == eMakeType_Excluded ||
1196                     p->second.m_MakeType == eMakeType_ExcludedByReq) {
1197                     continue;
1198                 }
1199                 if (p->first.Type() == CProjKey::eDataSpec) {
1200                     continue;
1201                 }
1202                 if (IsAllowedProjectTag(p->second, &composite_filter)) {
1203                     matching.push_back( CreateProjectName(p->first));
1204                 }
1205             }
1206             if (!matching.empty()) {
1207                 existing_composite_names.push_back(composite_name);
1208                 ofs << composite_name << "_projects =";
1209                 ITERATE(vector<string>, c, matching) {
1210                     ofs << " \\" <<endl << "    " << *c;
1211                 }
1212                 ofs << endl << endl;
1213 
1214                 ofs << composite_name << " :" << endl
1215                     << "\t$(MAKE) $(MFLAGS_NR) -f $(MINPUT) " << composite_name << dotreal
1216                     << " MTARGET=$(MTARGET)";
1217                 ofs << endl << endl;
1218                 ofs << composite_name << dotreal << " :" << " $("
1219                     << composite_name << "_projects" << ":%=%" << dotreal << ")";
1220                 ofs << endl << endl;
1221 
1222             }
1223         }
1224     }
1225 
1226 
1227 // help and list targets ----------------------------------------------------
1228     ofs << "help :"
1229         << endl << "\t@echo Build all projects"
1230         << endl << "\t@echo \"    make -f $(MINPUT) -j 12 ptb_all\""
1231         << endl << "\t@echo Build a project, for example, xncbi.lib"
1232         << endl << "\t@echo \"    make -f $(MINPUT) -j 12 xncbi.lib\""
1233         << endl << "\t@echo Clean project intermediate files"
1234         << endl << "\t@echo \"    make -f $(MINPUT) -j 12 xncbi.lib MTARGET=clean\""
1235         << endl << "\t@echo Clean project intermediate and output files"
1236         << endl << "\t@echo \"    make -f $(MINPUT) -j 12 xncbi.lib MTARGET=purge\""
1237         << endl << "\t@echo Target lists: "
1238         << endl << "\t@echo \"    list-all         - list all targets\""
1239         << endl << "\t@echo \"    list-apps        - list all applications\""
1240         << endl << "\t@echo \"    list-libs        - list all libraries\""
1241         << endl << "\t@echo \"    list-unix        - list all native Unix projects\""
1242         << endl << "\t@echo \"    list-excluded    - list 'excluded' targets\""
1243         << endl << "\t@echo \"    list-tags        - list composite targets\""
1244         << endl << "\t@echo \"    list-tag-TagName - list all targets in a composite target TagName\"";
1245     ofs << endl << endl;
1246 
1247     ofs << "list-all :"
1248         << endl << "\t@echo"
1249         << endl << "\t@echo"
1250         << endl << "\t@echo --------------------------------------"
1251         << endl << "\t@echo APPLICATIONS"
1252         << endl << "\t@echo"
1253         << endl << "\t@for i in $(all_apps); do echo $$i; done"
1254         << endl << "\t@echo"
1255         << endl << "\t@echo"
1256         << endl << "\t@echo --------------------------------------"
1257         << endl << "\t@echo LIBRARIES"
1258         << endl << "\t@echo"
1259         << endl << "\t@for i in $(all_libraries); do echo $$i; done"
1260         << endl << "\t@echo"
1261         << endl << "\t@echo"
1262         << endl << "\t@echo --------------------------------------"
1263         << endl << "\t@echo UNIX PROJECTS"
1264         << endl << "\t@echo"
1265         << endl << "\t@for i in $(all_unix); do echo $$i; done";
1266 
1267     if (!existing_composite_names.empty()) {
1268        ofs
1269             << endl << "\t@echo"
1270             << endl << "\t@echo"
1271             << endl << "\t@echo --------------------------------------"
1272             << endl << "\t@echo COMPOSITE TARGETS"
1273             << endl << "\t@echo";
1274         ITERATE(vector<string>, c, existing_composite_names) {
1275             ofs  << endl << "\t@echo " << *c;
1276         }
1277     }
1278     ofs
1279         << endl << "\t@echo"
1280         << endl << "\t@echo"
1281         << endl << "\t@echo --------------------------------------"
1282         << endl << "\t@echo DIRECTORIES"
1283         << endl << "\t@echo"
1284         << endl << "\t@for i in $(all_dirs); do echo $$i/; done";
1285     ofs << endl << endl;
1286     ofs << "list-apps :"
1287         << endl << "\t@for i in $(all_apps); do echo $$i; done";
1288     ofs << endl << endl;
1289     ofs << "list-libs :"
1290         << endl << "\t@for i in $(all_libraries); do echo $$i; done";
1291     ofs << endl << endl;
1292     ofs << "list-unix :"
1293         << endl << "\t@for i in $(all_unix); do echo $$i; done";
1294     ofs << endl << endl;
1295     ofs << "list-excluded :"
1296         << endl << "\t@for i in $(all_excluded); do echo $$i; done";
1297     ofs << endl << endl;
1298 
1299     ofs << "list-tags :";
1300     if (!existing_composite_names.empty()) {
1301         ITERATE(vector<string>, c, existing_composite_names) {
1302             ofs  << endl << "\t@echo " << *c;
1303         }
1304     }
1305     ofs << endl << endl;
1306     ITERATE(vector<string>, c, existing_composite_names) {
1307         ofs << "list-tag-" << *c << " :"
1308             << endl << "\t@for i in $(" << *c << "_projects); do echo $$i; done";
1309         ofs << endl << endl;
1310     }
1311 
1312 // --------------------------------------------------------------------------
1313     string datatool_key;
1314     string datatool( GetDatatoolId() );
1315     set<string> dataspec_dirs;
1316     if (!datatool.empty()) {
1317         CProjKey t(CProjKey::eApp, datatool);
1318         if (projects_tree.m_Projects.find(t) != projects_tree.m_Projects.end()) {
1319             datatool_key = CreateProjectName(t);
1320         }
1321     }
1322 
1323     ITERATE(CProjectItemsTree::TProjects, p, projects_tree.m_Projects) {
1324 
1325         if (p->first.Type() == CProjKey::eDataSpec) {
1326             continue;
1327         }
1328 
1329         bool isLibrary = p->first.Type() == CProjKey::eLib;
1330         bool hasDataspec = !p->second.m_DatatoolSources.empty();
1331         string target, target_app, target_lib, target_user;
1332         list<string> dependencies;
1333         CProjectItemsTree::TProjects::const_iterator n;
1334 
1335         target = CreateProjectName(p->first);
1336         target_app = target_lib = target_user = "\"\"";
1337         if (p->first.Type() == CProjKey::eApp) {
1338             target_app = p->second.m_Name;
1339         } else if (p->first.Type() == CProjKey::eMsvc) {
1340             target_user = p->second.m_Name;
1341         } else if (p->first.Type() == CProjKey::eLib) {
1342             target_lib = p->second.m_Name;
1343         } else {
1344             target_lib = p->second.m_Name;
1345         }
1346         string rel_path = CDirEntry::CreateRelativePath(
1347             GetProjectTreeInfo().m_Src,p->second.m_SourcesBaseDir);
1348 
1349 // check for missing dependencies -------------------------------------------
1350         string error;
1351         if (p->second.m_MakeType != eMakeType_Expendable && m_BuildRoot.empty()) {
1352             ITERATE(set<CProjKey>, u, p->second.m_UnconditionalDepends) {
1353                 CProjKey proj_key = *u;
1354                 if (projects_tree.m_Projects.find(proj_key) ==
1355                     projects_tree.m_Projects.end()) {
1356                     bool depfound = false;
1357                     string dll(GetDllHost(projects_tree, proj_key.Id()));
1358                     if (!dll.empty()) {
1359                         CProjKey id_alt(CProjKey::eDll,dll);
1360                         depfound = (projects_tree.m_Projects.find(id_alt) !=
1361                             projects_tree.m_Projects.end());
1362                     }
1363                     if (!depfound &&
1364                         !SMakeProjectT::IsConfigurableDefine(proj_key.Id())) {
1365                         error = "@echo ERROR: this project depends on missing " +
1366                             CreateProjectName(proj_key);
1367                     }
1368                 }
1369             }
1370         }
1371 
1372 // collect dependencies -----------------------------------------------------
1373         set<string> lib_guid, visited;
1374         ITERATE(list<CProjKey>, i, p->second.m_Depends) {
1375 
1376             const CProjKey& id = *i;
1377             // exclude 3rd party libs
1378             if ( GetSite().IsLibWithChoice(id.Id()) ) {
1379                 if ( GetSite().GetChoiceForLib(id.Id()) == CMsvcSite::e3PartyLib ) {
1380                     continue;
1381                 }
1382             }
1383             // exclude missing projects
1384             n = projects_tree.m_Projects.find(id);
1385             if (n == projects_tree.m_Projects.end()) {
1386 /*
1387                 CProjKey id_alt(CProjKey::eDll,GetDllsInfo().GetDllHost(id.Id()));
1388                 n = projects_tree.m_Projects.find(id_alt);
1389                 if (n == projects_tree.m_Projects.end())
1390 */
1391                 {
1392                     if (!SMakeProjectT::IsConfigurableDefine(id.Id())) {
1393                         PTB_WARNING_EX(kEmptyStr, ePTB_ProjectNotFound,
1394                             "Project " + p->first.Id() + " depends on missing project " + id.Id());
1395                     }
1396                     continue;
1397                 }
1398             }
1399             if (isLibrary) {
1400                 CollectLibToLibDependencies(projects_tree, lib_guid, visited, p, n);
1401                 continue;
1402             }
1403             dependencies.push_back(CreateProjectName(n->first));
1404         }
1405         copy(lib_guid.begin(), lib_guid.end(), back_inserter(dependencies));
1406         dependencies.sort();
1407         dependencies.unique();
1408         CProjectTreeBuilder::VerifyBuildOrder( p->second, dependencies, projects_tree);
1409 
1410         if (isLibrary && !m_AllDllBuild) {
1411             list<string> new_dependencies;
1412 //            new_dependencies.push_back( target + dotfiles);
1413             ITERATE(list<string>, d, dependencies) {
1414                 if (*d == datatool_key) {
1415                     continue;
1416                 }
1417                 n = projects_tree.m_Projects.find(CreateProjKey(*d));
1418                 if (n != projects_tree.m_Projects.end() &&
1419                     !n->second.m_DatatoolSources.empty()) {
1420                     new_dependencies.push_back(*d + dotfiles);
1421                     continue;
1422                 }
1423                 new_dependencies.push_back(*d);
1424             }
1425             dependencies = new_dependencies;
1426         }
1427 
1428 // collect paths ------------------------------------------------------------
1429         if (p->first.Type() != CProjKey::eDataSpec) {
1430 
1431             path_to_target[rel_path].push_back(target);
1432             if (p->second.m_MakeType != eMakeType_Excluded &&
1433                 p->second.m_MakeType != eMakeType_ExcludedByReq) {
1434                 string stop_path(CDirEntry::AddTrailingPathSeparator("."));
1435                 string parent_path, prev_parent(rel_path);
1436                 for (;;) {
1437                     parent_path = ParentDir(prev_parent);
1438 // see CXX-950
1439 #if 0
1440                     path_to_target[parent_path].push_back(prev_parent + ".real");
1441 #else
1442                     path_to_target[parent_path].push_back(prev_parent);
1443 #endif
1444                     if (parent_path == stop_path) {
1445                         break;
1446                     }
1447                     prev_parent = parent_path;
1448                 }
1449             }
1450         }
1451 
1452 #if NCBI_COMPILER_MSVC
1453         rel_path = NStr::Replace(rel_path,"\\","/");
1454 #endif //NCBI_COMPILER_MSVC
1455 
1456 // see CXX-950
1457 #if 0
1458             ofs << target << " : " << rel_path << "$(s)." << target << ".real";
1459         ofs << endl << endl;
1460         ofs << rel_path << "$(s)." << target << ".real" << " :" << endl
1461             << "\t$(MAKE) $(MFLAGS_NR) -f $(MINPUT) " << target << ".real"
1462             << " MTARGET=$(MTARGET) MARK=$(MARK)";
1463         ofs << endl << endl;
1464         ofs << target << ".real" << " :";
1465         ITERATE(list<string>, d, dependencies) {
1466             ofs << " " << *d;
1467         }
1468         ofs << endl << "\t";
1469         if (!error.empty()) {
1470             ofs << error << endl << "\t@exit 1" << endl << "\t";
1471         }
1472         ofs << "+";
1473         if (p->second.m_MakeType == eMakeType_Expendable) {
1474             ofs << "-";
1475             }
1476         ofs << "cd " << rel_path << "; $(MAKE) $(MFLAGS_NR)"
1477             << " APP_PROJ=" << target_app
1478         << " LIB_PROJ=" << target_lib
1479         << " $(MTARGET)" << endl
1480         << "\t@" << "cd " << rel_path << "; $(sign)";
1481         ofs << endl << endl;
1482 #else
1483         ofs << target << " :" << endl
1484             << "\t$(MAKE) $(MFLAGS) -f $(MINPUT) " << target << dotreal
1485             << " MTARGET=$(MTARGET)";
1486         ofs << endl << endl;
1487         ofs << target << dotreal << " :";
1488 
1489         if (hasDataspec) {
1490             dataspec_dirs.insert(rel_path);
1491         }
1492         ITERATE(list<string>, d, dependencies) {
1493             if (*d == datatool_key) {
1494                 dataspec_dirs.insert(rel_path);
1495             } else {
1496                 ofs << " " << *d << dotreal;
1497             }
1498         }
1499         ofs << " " << rel_path << dotfiles << dotreal;
1500 
1501 
1502         ofs << endl << "\t";
1503         if (!error.empty()) {
1504             ofs << error << endl << "\t@exit 1" << endl << "\t";
1505         }
1506         ofs << "+";
1507         if (p->second.m_MakeType >= eMakeType_Expendable) {
1508             ofs << "-";
1509         }
1510         ofs << "cd " << rel_path << " && ";
1511         if (p->second.m_MakeType == eMakeType_Expendable) {
1512             ofs << " NCBI_BUT_EXPENDABLE=' (but expendable)'";
1513         }
1514         ofs << " $(MAKE) $(MFLAGS)"
1515             << " APP_PROJ=" << target_app
1516             << (p->second.m_IsMetallib ? " LIB_PROJ=\"\" METAL_PROJ=" : " LIB_PROJ=") << target_lib
1517             << " UNIX_PROJ=" << target_user
1518             << " $(MTARGET)";
1519         if (p->first.Type() != CProjKey::eMsvc) {
1520             ofs << " $(SKIP_PRELIMINARIES)";
1521         }
1522         ofs << endl << endl;
1523  #endif
1524         if (hasDataspec) {
1525             ofs << target << dotfiles << " :" << endl
1526                 << "\t$(MAKE) $(MFLAGS) -f $(MINPUT) $(SKIP_PRELIMINARIES) "
1527                 << target << dotfiles << dotreal;
1528             ofs << endl << endl;
1529             ofs << target << dotfiles << dotreal << " :";
1530             ofs << " " << rel_path << dotfiles << dotreal;
1531             ofs << endl << endl;
1532         }
1533 
1534 // recommended library order
1535         if (p->first.Type() == CProjKey::eApp || p->first.Type() == CProjKey::eDll) {
1536             const list<string>& liborder  = m_LibraryOrder[       p->second.m_MkName];
1537             const list<string>& lib3order = m_3PartyLibraryOrder[ p->second.m_MkName];
1538             string filename(
1539                 CDirEntry::ConcatPath(solution_dir,
1540                     CDirEntry::CreateRelativePath( GetProjectTreeInfo().m_Src, p->second.GetPath() + ".libdep")));
1541             if (m_LibDep  && (!liborder.empty() ||  !lib3order.empty())) {
1542                 CNcbiOfstream ofs(filename.c_str(), IOS_BASE::out | IOS_BASE::trunc);
1543                 if (ofs.is_open()) {
1544                     if (!liborder.empty()) {
1545                         ofs << "GENERATED_LIB_ORDER = -l" << NStr::Join(liborder," -l") << endl;
1546                     }
1547                     if (!lib3order.empty()) {
1548                         ofs << "GENERATED_LIB3PARTY_ORDER =";
1549                         ITERATE( list<string>, l3, lib3order) {
1550                             if (l3->empty()) {
1551                                 continue;
1552                             }
1553                             ofs << " ";
1554                             if (m_Frameworks.find(*l3) != m_Frameworks.end()) {
1555                                 ofs << "-framework ";
1556                             } else if (m_3PartyLibs.find(*l3) != m_3PartyLibs.end()) {
1557                                 ofs << "-l";
1558                             } else if (l3->at(0) != '-' &&
1559                                        l3->find_first_of("$/.") == string::npos) {
1560                                 ofs << "-l";
1561                             }
1562                             ofs << *l3;
1563                         }
1564                         ofs << endl;
1565                     }
1566                 }
1567             }
1568             else {
1569                 CFile(filename).Remove();
1570             }
1571         }
1572     }
1573 
1574 // folder targets -----------------------------------------------------------
1575     map< string, list< string > >::const_iterator pt;
1576     for ( pt = path_to_target.begin(); pt != path_to_target.end(); ++pt) {
1577         string target(pt->first);
1578         ofs << ".PHONY : " << target << endl << endl;
1579         ofs << target << " :" << endl
1580             << "\t$(MAKE) $(MFLAGS_NR) -f $(MINPUT) " << target << dotreal
1581             << " MTARGET=$(MTARGET)";
1582         ofs << endl << endl;
1583         ofs << target << dotreal << " :";
1584         if (!pt->second.empty()) {
1585             list< string > tt(pt->second);
1586             tt.sort();
1587             tt.unique();
1588 // see CXX-950
1589 #if 0
1590             ofs << " " << NStr::Join( tt, " ");
1591 #else
1592             ofs << " " << NStr::Join( tt, dotreal + " ") << dotreal;
1593 #endif
1594             ofs << endl << endl;
1595         }
1596 
1597         ofs << target << dotfiles << " :" << endl
1598             << "\t$(MAKE) $(MFLAGS_NR) -f $(MINPUT) " << target << dotfiles << dotreal
1599             << " MTARGET=$(MTARGET)";
1600         ofs << endl << endl;
1601         ofs << target << dotfiles << dotreal << " :";
1602         if (m_Dtdep && !datatool_key.empty() &&
1603             dataspec_dirs.find(target) != dataspec_dirs.end()) {
1604             ofs << " " << datatool_key << dotreal;
1605         }
1606         ofs << endl << "\t";
1607         ofs << "-";
1608         ofs << "cd " << target << " && $(MAKE) $(MFLAGS) sources";
1609         ofs << endl << endl;
1610     }
1611 }
1612 
1613 
CreateFeaturesAndPackagesFiles(const list<SConfigInfo> * configs,list<string> & list_enabled,list<string> & list_disabled)1614 void CProjBulderApp::CreateFeaturesAndPackagesFiles(
1615     const list<SConfigInfo>* configs,
1616     list<string>& list_enabled, list<string>& list_disabled)
1617 {
1618     PTB_INFO("Generating Features_And_Packages files...");
1619     // Create makefile path
1620     string base_path = GetProjectTreeInfo().m_Compilers;
1621     base_path = CDirEntry::ConcatPath(base_path,
1622         GetRegSettings().m_CompilersSubdir);
1623 
1624     base_path = CDirEntry::ConcatPath(base_path, GetBuildType().GetTypeStr());
1625     ITERATE(list<SConfigInfo>, c , *configs) {
1626         string file_path = CDirEntry::ConcatPath(base_path, c->GetConfigFullName());
1627         CDir(file_path).CreatePath();
1628         string enabled = CDirEntry::ConcatPath(file_path,
1629             "features_and_packages.txt");
1630         string disabled = CDirEntry::ConcatPath(file_path,
1631             "features_and_packages_disabled.txt");
1632         file_path = CDirEntry::ConcatPath(file_path,
1633                                           "features_and_packages.txt");
1634         CNcbiOfstream ofs(enabled.c_str(), IOS_BASE::out | IOS_BASE::trunc );
1635         if ( !ofs )
1636             NCBI_THROW(CProjBulderAppException, eFileCreation, enabled);
1637         GetApp().RegisterGeneratedFile( enabled );
1638 
1639         CNcbiOfstream ofsd(disabled.c_str(), IOS_BASE::out | IOS_BASE::trunc );
1640         if ( !ofsd )
1641             NCBI_THROW(CProjBulderAppException, eFileCreation, disabled);
1642         GetApp().RegisterGeneratedFile( disabled );
1643 
1644         if (c->m_rtType == SConfigInfo::rtMultiThreaded) {
1645             ofs << "MT" << endl;
1646         } else if (c->m_rtType == SConfigInfo::rtMultiThreadedDebug) {
1647             ofs << "MT" << endl << "Debug" << endl;
1648         } else if (c->m_rtType == SConfigInfo::rtMultiThreadedDLL) {
1649             ofs << "MT" << endl;
1650         } else if (c->m_rtType == SConfigInfo::rtMultiThreadedDebugDLL) {
1651             ofs << "MT" << endl << "Debug" << endl;
1652         } else if (c->m_rtType == SConfigInfo::rtSingleThreaded) {
1653         } else if (c->m_rtType == SConfigInfo::rtSingleThreadedDebug) {
1654             ofs << "Debug" << endl;
1655         }
1656         if (GetBuildType().GetType() == CBuildType::eDll) {
1657             ofs << "DLL" << endl;
1658         }
1659         const set<string>& epackages =
1660             CMsvcPrjProjectContext::GetEnabledPackages(c->GetConfigFullName());
1661         ITERATE(set<string>, e, epackages) {
1662             ofs << *e << endl;
1663             list_enabled.push_back(*e);
1664         }
1665 
1666         list<string> std_features;
1667         GetSite().GetStandardFeatures(std_features);
1668         ITERATE(list<string>, s, std_features) {
1669             ofs << *s << endl;
1670             list_enabled.push_back(*s);
1671         }
1672 
1673         const set<string>& dpackages =
1674             CMsvcPrjProjectContext::GetDisabledPackages(c->GetConfigFullName());
1675         ITERATE(set<string>, d, dpackages) {
1676             ofsd << *d << endl;
1677             list_disabled.push_back(*d);
1678         }
1679     }
1680     list_enabled.sort();
1681     list_enabled.unique();
1682     list_disabled.sort();
1683     list_disabled.unique();
1684 }
1685 
GenerateSummary(const list<SConfigInfo> configs,const list<string> & enabled,const list<string> & disabled)1686 void CProjBulderApp::GenerateSummary(const list<SConfigInfo> configs,
1687     const list<string>& enabled, const list<string>& disabled)
1688 {
1689     if (!m_ConfSrc.empty() && !m_ConfDest.empty()) {
1690         string orig_ext = CDirEntry( CDirEntry(m_ConfSrc).GetBase() ).GetExt();
1691         ITERATE(list<SConfigInfo>, p , configs) {
1692             const SConfigInfo& cfg_info = *p;
1693             string file_dst_path;
1694             file_dst_path = m_ConfDest + "." +
1695                             ConfigurableFileSuffix(cfg_info.GetConfigFullName())+
1696                             orig_ext;
1697             CreateConfigurableFile(m_ConfSrc, file_dst_path,
1698                                    cfg_info.GetConfigFullName());
1699         }
1700     }
1701 
1702     string str_config;
1703     // summary
1704     SetDiagPostAllFlags(eDPF_Log);
1705     PTB_INFO("===========================================================");
1706     PTB_INFO("SOLUTION: " << m_Solution);
1707     PTB_INFO("PROJECTS: " << CDirEntry::ConcatPath(m_ProjectTreeInfo->m_Root, m_Subtree));
1708     PTB_INFO("CONFIGURATIONS: " << str_config);
1709     PTB_INFO("FEATURES AND PACKAGES: ");
1710     string str_pkg = "     enabled: ";
1711     ITERATE( list<string>, p, enabled) {
1712         if (str_pkg.length() > 70) {
1713             PTB_INFO(str_pkg);
1714             str_pkg = "              ";
1715         }
1716         str_pkg += " ";
1717         str_pkg += *p;
1718     }
1719     if (!str_pkg.empty()) {
1720         PTB_INFO(str_pkg);
1721     }
1722     str_pkg = "    disabled: ";
1723     ITERATE( list<string>, p, disabled) {
1724         if (str_pkg.length() > 70) {
1725             PTB_INFO(str_pkg);
1726             str_pkg = "              ";
1727         }
1728         str_pkg += " ";
1729         str_pkg += *p;
1730     }
1731     if (!str_pkg.empty()) {
1732         PTB_INFO(str_pkg);
1733     }
1734     string str_path = GetProjectTreeInfo().m_Compilers;
1735     str_path = CDirEntry::ConcatPath(str_path,
1736         GetRegSettings().m_CompilersSubdir);
1737     str_path = CDirEntry::ConcatPath(str_path, GetBuildType().GetTypeStr());
1738 
1739     PTB_INFO(" ");
1740     PTB_INFO("    If a package is present in both lists,");
1741     PTB_INFO("    it is disabled in SOME configurations only");
1742     PTB_INFO("    For details see 'features_and_packages' files in");
1743     PTB_INFO("    " << str_path << "/%ConfigurationName%");
1744     PTB_INFO("===========================================================");
1745 }
1746 
CreateCheckList(const list<SConfigInfo> * configs,CProjectItemsTree & projects_tree)1747 void CProjBulderApp::CreateCheckList(const list<SConfigInfo>* configs,
1748     CProjectItemsTree& projects_tree)
1749 {
1750     PTB_INFO("Generating check.sh.list files...");
1751     string output_dir(m_Solution);
1752     if (CMsvc7RegSettings::GetMsvcPlatform() < CMsvc7RegSettings::eUnix) {
1753         string::size_type n = output_dir.find_last_of('.');
1754         if (n != string::npos) {
1755             output_dir = output_dir.substr(0,n);
1756         }
1757     }
1758     output_dir += ".check";
1759     ITERATE(list<SConfigInfo>, c , *configs) {
1760         string cfg(c->GetConfigFullName());
1761         string file_path = CDirEntry::ConcatPath(output_dir, cfg);
1762         CDir dir(file_path);
1763         if (!dir.Exists()) {
1764             dir.CreatePath();
1765         }
1766         file_path = CDirEntry::ConcatPath(file_path, "check.sh.list");
1767         CNcbiOfstream ofs(file_path.c_str(), IOS_BASE::out | IOS_BASE::trunc );
1768         if ( !ofs )
1769             NCBI_THROW(CProjBulderAppException, eFileCreation, file_path);
1770         GetApp().RegisterGeneratedFile( file_path );
1771         list<string> all_cmd;
1772         ITERATE(CProjectItemsTree::TProjects, p, projects_tree.m_Projects) {
1773             const CProjItem& project = p->second;
1774             if (project.m_MakeType == eMakeType_Excluded ||
1775                 project.m_MakeType == eMakeType_ExcludedByReq) {
1776                 continue;
1777             }
1778             if (project.m_CheckConfigs.find(cfg) != project.m_CheckConfigs.end()) {
1779                 ITERATE( list<string>, cmd, project.m_CheckInfo) {
1780                     all_cmd.push_back(*cmd);
1781                 }
1782             } else if (!project.m_CheckInfo.empty()) {
1783                 PTB_INFO("Project: " << p->first.Id() << ": CHECK_CMD disabled in " << cfg);
1784             }
1785         }
1786         all_cmd.sort();
1787         all_cmd.unique();
1788         ITERATE(list<string>, cmd, all_cmd) {
1789             ofs << *cmd << endl;
1790         }
1791     }
1792 }
1793 
ReportGeneratedFiles(void)1794 void CProjBulderApp::ReportGeneratedFiles(void)
1795 {
1796     m_GeneratedFiles.sort();
1797     string file_path( m_Solution + "_generated_files.txt");
1798     string sep;
1799     sep += CDirEntry::GetPathSeparator();
1800     string root(m_Root);
1801     if (!CDirEntry::IsAbsolutePath(root)) {
1802         root = CDirEntry::ConcatPath(CDir::GetCwd(), root);
1803     }
1804     CNcbiOfstream ofs(file_path.c_str(), IOS_BASE::out | IOS_BASE::trunc );
1805     if (ofs.is_open()) {
1806         ITERATE( list<string>, f, m_GeneratedFiles) {
1807             string path(*f);
1808             if (!CDirEntry::IsAbsolutePath(path)) {
1809                 path = CDirEntry::ConcatPath(CDir::GetCwd(), path);
1810             }
1811             path = CDirEntry::CreateRelativePath(root, path);
1812             ofs << NStr::ReplaceInPlace( path, sep, "/") << endl;
1813         }
1814     }
1815 }
1816 
ReportProjectWatchers(void)1817 void CProjBulderApp::ReportProjectWatchers(void)
1818 {
1819     m_ProjWatchers.sort();
1820     string file_path( m_Solution + "_watchers.txt");
1821     CNcbiOfstream ofs(file_path.c_str(), IOS_BASE::out | IOS_BASE::trunc );
1822     if (ofs.is_open()) {
1823         ITERATE( list<string>, f, m_ProjWatchers) {
1824             ofs << *f << endl;
1825         }
1826     }
1827 }
1828 
Exit(void)1829 void CProjBulderApp::Exit(void)
1830 {
1831 }
1832 
1833 
ParseArguments(void)1834 void CProjBulderApp::ParseArguments(void)
1835 {
1836     const CArgs& args = GetArgs();
1837     string root;
1838     bool extroot = false;
1839     bool argfile = false;
1840     string argsfile;
1841 
1842     if ( args["args"] ) {
1843         argsfile = args["args"].AsString();
1844         if (CDirEntry(argsfile).Exists()) {
1845             argfile = true;
1846             m_CustomConfiguration.LoadFrom(argsfile,&m_CustomConfiguration);
1847         } else {
1848             NCBI_THROW(CProjBulderAppException, eFileOpen,
1849                                     argsfile + " not found");
1850         }
1851     }
1852 
1853     root = args["root"].AsString();
1854     if (root == "\"\"") {
1855         root = "";
1856     }
1857     if (argfile && root.empty()) {
1858         m_CustomConfiguration.GetPathValue("__arg_root", root);
1859     }
1860     m_Root = CDirEntry::IsAbsolutePath(root) ?
1861         root : CDirEntry::ConcatPath( CDir::GetCwd(), root);
1862     m_Root = CDirEntry::AddTrailingPathSeparator(m_Root);
1863     m_Root = CDirEntry::NormalizePath(m_Root);
1864     m_Root = CDirEntry::AddTrailingPathSeparator(m_Root);
1865 
1866     m_Subtree        = args["subtree"].AsString();
1867     if (m_Subtree == "\"\"") {
1868         m_Subtree = "";
1869     }
1870     if (CDirEntry::IsAbsolutePath(m_Subtree)) {
1871         m_Subtree = CDirEntry::NormalizePath(
1872                         CDirEntry::CreateRelativePath(m_Root, m_Subtree));
1873     }
1874     m_Solution       = CDirEntry::NormalizePath(args["solution"].AsString());
1875     if (m_Solution == "\"\"") {
1876         m_Solution = "";
1877     }
1878     if (!m_Solution.empty() && !CDirEntry::IsAbsolutePath(m_Solution)) {
1879         m_Solution = CDirEntry::ConcatPath( CDir::GetCwd(), m_Solution);
1880     }
1881 
1882     if (argfile) {
1883         string v;
1884         if (GetConfigPath().empty() &&
1885             m_CustomConfiguration.GetPathValue("__arg_conffile", v)) {
1886             if (!CDirEntry::IsAbsolutePath(v)) {
1887                 v = CDirEntry::ConcatPath(m_Root,v);
1888             }
1889             LoadConfig(GetRWConfig(),&v);
1890         }
1891         string subtree;
1892         m_CustomConfiguration.GetPathValue("__arg_subtree", subtree);
1893         if (m_Subtree.empty()) {
1894             m_Subtree = subtree;
1895         } else if (m_Subtree != subtree) {
1896             m_CustomConfiguration.RemoveDefinition("__AllowedProjects");
1897         }
1898         if (m_Solution.empty()) {
1899             m_CustomConfiguration.GetPathValue("__arg_solution", m_Solution);
1900             if (!CDirEntry::IsAbsolutePath(m_Solution)) {
1901                 m_Solution = CDirEntry::ConcatPath(m_Root,m_Solution);
1902             }
1903         }
1904 
1905         if (m_CustomConfiguration.GetValue("__arg_dll", v)) {
1906             m_Dll = NStr::StringToBool(v);
1907         }
1908         if (m_CustomConfiguration.GetValue("__arg_nobuildptb", v)) {
1909             m_BuildPtb = !NStr::StringToBool(v);
1910         }
1911 
1912         if (m_CustomConfiguration.GetValue("__arg_ext", v)) {
1913             m_AddMissingLibs = NStr::StringToBool(v);
1914         }
1915         if (m_CustomConfiguration.GetValue("__arg_nws", v)) {
1916             m_ScanWholeTree = !NStr::StringToBool(v);
1917         }
1918         extroot = m_CustomConfiguration.GetPathValue("__arg_extroot", m_BuildRoot);
1919         m_CustomConfiguration.GetValue("__arg_projtag", m_ProjTags);
1920 
1921 #if defined(NCBI_COMPILER_MSVC) || defined(NCBI_XCODE_BUILD) || defined(PSEUDO_XCODE)
1922         if (m_CustomConfiguration.GetValue("__arg_ide", v)) {
1923             m_Ide = NStr::StringToInt(v);
1924         }
1925         m_CustomConfiguration.GetValue("__arg_arch", m_Arch);
1926 #endif
1927 
1928         if (m_CustomConfiguration.GetValue("__arg_dtdep", v)) {
1929             m_Dtdep = NStr::StringToBool(v);
1930         }
1931         if (m_CustomConfiguration.GetValue("__arg_noadddep", v)) {
1932             m_AddMissingDep = !NStr::StringToBool(v);
1933         }
1934         if (m_CustomConfiguration.GetValue("__arg_libdep", v)) {
1935             m_LibDep = NStr::StringToBool(v);
1936         }
1937     } else {
1938         m_Dll            =   (bool)args["dll"];
1939         m_BuildPtb       = !((bool)args["nobuildptb"]);
1940         m_AddMissingLibs =   (bool)args["ext"];
1941         m_ScanWholeTree  = !((bool)args["nws"]);
1942         extroot     = (bool)args["extroot"];
1943         if (extroot) {
1944             m_BuildRoot      = args["extroot"].AsString();
1945         }
1946         if ( const CArgValue& t = args["projtag"] ) {
1947             m_ProjTags = t.AsString();
1948             m_ProjTagCmnd = true;
1949         } else {
1950             m_ProjTags = CProjectsLstFileFilter::GetAllowedTagsInfo(
1951                 CDirEntry::ConcatPath(m_Root, m_Subtree));
1952             m_ProjTagCmnd = false;
1953         }
1954 #if defined(NCBI_COMPILER_MSVC) || defined(NCBI_XCODE_BUILD) || defined(PSEUDO_XCODE)
1955         const CArgValue& ide = args["ide"];
1956         if ((bool)ide) {
1957             m_Ide = ide.AsInteger();
1958         }
1959         const CArgValue& arch = args["arch"];
1960         if ((bool)arch) {
1961             m_Arch = arch.AsString();
1962         }
1963 #endif
1964     }
1965 
1966     CMsvc7RegSettings::IdentifyPlatform();
1967 
1968     string entry[] = {"","",""};
1969     if (CMsvc7RegSettings::GetMsvcPlatform() < CMsvc7RegSettings::eUnix) {
1970         entry[0] = "ThirdPartyBasePath";
1971         entry[1] = "ThirdParty_C_ncbi";
1972     }
1973     else if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eXCode) {
1974         entry[0] = "XCode_ThirdPartyBasePath";
1975         entry[1] = "XCode_ThirdParty_C_ncbi";
1976     }
1977     if (argfile) {
1978         // this replaces path separators in entry[j] with a native one
1979         string v;
1980         for (int j=0; !entry[j].empty(); ++j) {
1981             if (m_CustomConfiguration.GetPathValue(entry[j], v)) {
1982                 m_CustomConfiguration.AddDefinition(entry[j], v);
1983             }
1984         }
1985     }
1986 
1987     m_ConfirmCfg = false;
1988 #if defined(NCBI_COMPILER_MSVC)
1989     m_ConfirmCfg =   (bool)args["cfg"];
1990 #endif
1991     m_InteractiveCfg = (bool)args["i"];
1992     m_Dtdep = (bool)args["dtdep"];
1993     m_AddMissingDep = !((bool)args["noadddep"]);
1994     m_LibDep = args["libdep"].AsBoolean();
1995 
1996     // Solution
1997     PTB_INFO("Solution: " << m_Solution);
1998     m_StatusDir =
1999         CDirEntry::NormalizePath( CDirEntry::ConcatPath( CDirEntry::ConcatPath(
2000             CDirEntry(m_Solution).GetDir(),".."),"status"));
2001 //    m_BuildPtb = m_BuildPtb &&
2002 //        CMsvc7RegSettings::GetMsvcVersion() == CMsvc7RegSettings::eMsvc710;
2003 
2004     if ( extroot ) {
2005         if (CDirEntry(m_BuildRoot).Exists()) {
2006 // verify status dir
2007             if (!CDirEntry(m_StatusDir).Exists() && !m_BuildRoot.empty()) {
2008                 m_StatusDir = CDirEntry::NormalizePath(
2009                     CDirEntry::ConcatPath( CDirEntry::ConcatPath(
2010                         m_BuildRoot,".."),"status"));
2011             }
2012 
2013             string t, try_dir;
2014             string src = GetConfig().Get("ProjectTree", "src");
2015             for ( t = try_dir = m_BuildRoot; ; try_dir = t) {
2016                 if (CDirEntry(
2017                     CDirEntry::ConcatPath(try_dir, src)).Exists()) {
2018                     m_ExtSrcRoot = try_dir;
2019                     break;
2020                 }
2021                 t = CDirEntry(try_dir).GetDir();
2022                 if (t == try_dir) {
2023                     break;
2024                 }
2025             }
2026         }
2027     }
2028     if (m_ProjTags.empty() || m_ProjTags == "\"\"" || m_ProjTags == "#") {
2029         m_ProjTags = "*";
2030     }
2031 
2032     string tmp(GetConfig().Get("ProjectTree", "CustomConfiguration"));
2033     if (!tmp.empty()) {
2034         m_CustomConfFile = CDirEntry::ConcatPath( CDirEntry(m_Solution).GetDir(), tmp);
2035     }
2036     CDir sln_dir(CDirEntry(m_Solution).GetDir());
2037     if ( !sln_dir.Exists() ) {
2038         sln_dir.CreatePath();
2039     }
2040     if (!argfile) {
2041         if (CFile(m_CustomConfFile).Exists()) {
2042             m_CustomConfiguration.LoadFrom(m_CustomConfFile,&m_CustomConfiguration);
2043 
2044             string subtree;
2045             m_CustomConfiguration.GetPathValue("__arg_subtree", subtree);
2046             if (m_Subtree.empty()) {
2047                 m_Subtree = subtree;
2048             } else if (m_Subtree != subtree) {
2049                 m_CustomConfiguration.RemoveDefinition("__AllowedProjects");
2050             }
2051         } else {
2052             if (CMsvc7RegSettings::GetMsvcPlatform() != CMsvc7RegSettings::eUnix) {
2053                 for (int j=0; !entry[j].empty(); ++j) {
2054                     m_CustomConfiguration.AddDefinition(entry[j], GetSite().GetConfigureEntry(entry[j]));
2055                 }
2056             }
2057             if (CMsvc7RegSettings::GetMsvcPlatform() < CMsvc7RegSettings::eUnix) {
2058                 string vt = GetSite().IsProvided("TweakVTune", false) ? "yes" : "no";
2059                 m_CustomConfiguration.AddDefinition("__TweakVTuneR", vt);
2060                 m_CustomConfiguration.AddDefinition("__TweakVTuneD", vt);
2061             }
2062         }
2063 
2064         string v;
2065         v = GetConfigPath();
2066         if (CDirEntry::IsAbsolutePath(v)) {
2067             try {
2068                 v = CDirEntry::CreateRelativePath(m_Root, v);
2069             } catch (CFileException&) {
2070             }
2071         }
2072         m_CustomConfiguration.AddDefinition("__arg_conffile", v);
2073 
2074         m_CustomConfiguration.AddDefinition("__arg_root", root);
2075         m_CustomConfiguration.AddDefinition("__arg_subtree", m_Subtree);
2076         v = m_Solution;
2077         if (CDirEntry::IsAbsolutePath(v)) {
2078             try {
2079                 v = CDirEntry::CreateRelativePath(m_Root, v);
2080             } catch (CFileException&) {
2081             }
2082         }
2083         m_CustomConfiguration.AddDefinition("__arg_solution", v);
2084 
2085         m_CustomConfiguration.AddDefinition("__arg_dll", m_Dll ? "yes" : "no");
2086         m_CustomConfiguration.AddDefinition("__arg_nobuildptb", m_BuildPtb ? "no" : "yes");
2087         m_CustomConfiguration.AddDefinition("__arg_ext", m_AddMissingLibs ? "yes" : "no");
2088         m_CustomConfiguration.AddDefinition("__arg_nws", m_ScanWholeTree ? "no" : "yes");
2089         m_CustomConfiguration.AddDefinition("__arg_extroot", m_BuildRoot);
2090         m_CustomConfiguration.AddDefinition("__arg_projtag", m_ProjTags);
2091 
2092 #if defined(NCBI_COMPILER_MSVC) || defined(NCBI_XCODE_BUILD) || defined(PSEUDO_XCODE)
2093         m_CustomConfiguration.AddDefinition("__arg_ide", NStr::IntToString(m_Ide));
2094         m_CustomConfiguration.AddDefinition("__arg_arch", m_Arch);
2095 #endif
2096 
2097         m_CustomConfiguration.AddDefinition("__arg_dtdep", m_Dtdep ? "yes" : "no");
2098         m_CustomConfiguration.AddDefinition("__arg_noadddep", m_AddMissingDep ? "no" : "yes");
2099         m_CustomConfiguration.AddDefinition("__arg_libdep", m_LibDep ? "yes" : "no");
2100 
2101         // this replaces path separators in entry[j] with a native one
2102         for (int j=0; !entry[j].empty(); ++j) {
2103             if (m_CustomConfiguration.GetPathValue(entry[j], v)) {
2104                 m_CustomConfiguration.AddDefinition(entry[j], v);
2105             }
2106         }
2107     }
2108     if (CMsvc7RegSettings::GetMsvcPlatform() < CMsvc7RegSettings::eUnix) {
2109         string v;
2110         if (m_CustomConfiguration.GetValue("__TweakVTuneR", v)) {
2111             m_TweakVTuneR = NStr::StringToBool(v);
2112         }
2113         if (m_CustomConfiguration.GetValue("__TweakVTuneD", v)) {
2114             m_TweakVTuneD = NStr::StringToBool(v);
2115         }
2116         m_AddUnicode = GetSite().IsProvided("Ncbi_Unicode", false) ||
2117                        GetSite().IsProvided("Ncbi-Unicode", false);
2118         if (m_AddUnicode && !(
2119             GetSite().IsProvided("Ncbi_Unicode", false) &&
2120             GetSite().IsProvided("Ncbi-Unicode", false))) {
2121             //workaround to handle both
2122             string add;
2123             if (GetSite().IsProvided("Ncbi_Unicode", false)) {
2124                 add = "Ncbi-Unicode";
2125             } else {
2126                 add = "Ncbi_Unicode";
2127             }
2128             string section("__EnabledUserRequests");
2129             string value;
2130             m_CustomConfiguration.GetValue(section, value);
2131             if (!value.empty()) {
2132                 value += " ";
2133             }
2134             value += add;
2135             GetApp().m_CustomConfiguration.AddDefinition(section, value);
2136         }
2137     }
2138     tmp = GetConfig().Get("Configure", "UserRequests");
2139     if (!tmp.empty()) {
2140         m_CustomConfiguration.AddDefinition("__UserRequests", tmp);
2141     } else {
2142         m_CustomConfiguration.RemoveDefinition("__UserRequests");
2143     }
2144     if ( m_MsvcRegSettings.get() ) {
2145         GetBuildConfigs(&m_MsvcRegSettings->m_ConfigInfo);
2146     }
2147     m_AbsDirs.clear();
2148     for (int j=0; !entry[j].empty(); ++j) {
2149         string v;
2150         if (m_CustomConfiguration.GetPathValue(entry[j], v)) {
2151             m_AbsDirs.push_back(v);
2152         }
2153     }
2154 }
2155 
VerifyArguments(void)2156 void CProjBulderApp::VerifyArguments(void)
2157 {
2158     m_Root = CDirEntry::AddTrailingPathSeparator(m_Root);
2159     if (CMsvc7RegSettings::GetMsvcPlatform() < CMsvc7RegSettings::eUnix) {
2160         NStr::ToLower(m_Root);
2161     }
2162 
2163     m_IncDir = GetProjectTreeInfo().m_Compilers;
2164     if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eUnix) {
2165         m_IncDir = CDirEntry(m_Solution).GetDir();
2166         m_IncDir = CDirEntry::ConcatPath(m_IncDir,"..");
2167     } else {
2168         m_IncDir = CDirEntry::ConcatPath(m_IncDir,GetRegSettings().m_CompilersSubdir);
2169         m_IncDir = CDirEntry::ConcatPath(m_IncDir, GetBuildType().GetTypeStr());
2170     }
2171     m_IncDir = CDirEntry::ConcatPath(m_IncDir, "inc");
2172     m_IncDir = CDirEntry::ConcatPath(m_IncDir, CMsvc7RegSettings::GetConfigNameKeyword());
2173 }
2174 
2175 
EnumOpt(const string & enum_name,const string & enum_val) const2176 int CProjBulderApp::EnumOpt(const string& enum_name,
2177                             const string& enum_val) const
2178 {
2179     int opt = GetConfig().GetInt(enum_name, enum_val, -1);
2180     if (opt == -1) {
2181         NCBI_THROW(CProjBulderAppException, eEnumValue,
2182                                 enum_name + "::" + enum_val);
2183     }
2184     return opt;
2185 }
2186 
2187 
DumpFiles(const TFiles & files,const string & filename) const2188 void CProjBulderApp::DumpFiles(const TFiles& files,
2189                                const string& filename) const
2190 {
2191     CNcbiOfstream  ofs(filename.c_str(), IOS_BASE::out | IOS_BASE::trunc);
2192     if ( !ofs ) {
2193         NCBI_THROW(CProjBulderAppException, eFileCreation, filename);
2194     }
2195 
2196     ITERATE(TFiles, p, files) {
2197         ofs << "+++++++++++++++++++++++++\n";
2198         ofs << p->first << endl;
2199         p->second.Dump(ofs);
2200         ofs << "-------------------------\n";
2201     }
2202 }
2203 
UseAbsolutePath(const string & path) const2204 bool CProjBulderApp::UseAbsolutePath(const string& path) const
2205 {
2206     ITERATE(list<string>, p, m_AbsDirs) {
2207         if (NStr::strncasecmp(path.c_str(), p->c_str(), p->length()) == 0) {
2208             return true;
2209         }
2210     }
2211     return false;
2212 }
2213 
AddCustomMetaData(const string & file)2214 void CProjBulderApp::AddCustomMetaData(const string& file)
2215 {
2216     string s( CDirEntry::CreateRelativePath(GetProjectTreeInfo().m_Src, file));
2217     if ( find(m_CustomMetaData.begin(), m_CustomMetaData.end(), s) ==
2218               m_CustomMetaData.end()) {
2219         m_CustomMetaData.push_back( s );
2220     }
2221 }
2222 
GetMetaDataFiles(list<string> * files) const2223 void CProjBulderApp::GetMetaDataFiles(list<string>* files) const
2224 {
2225     *files = m_CustomMetaData;
2226     if (CMsvc7RegSettings::GetMsvcPlatform() != CMsvc7RegSettings::eUnix) {
2227         NStr::Split(GetConfig().Get("ProjectTree", "MetaData"), LIST_SEPARATOR,
2228                     *files, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
2229     } else {
2230         string name(GetApp().GetSite().GetConfigureEntry("MetaData"));
2231         if (!name.empty()) {
2232             files->push_back( name);
2233         }
2234     }
2235 }
2236 
AddCustomConfH(const string & file)2237 void CProjBulderApp::AddCustomConfH(const string& file)
2238 {
2239     m_CustomConfH.push_back(file);
2240 }
2241 
GetCustomConfH(list<string> * files) const2242 void CProjBulderApp::GetCustomConfH(list<string>* files) const
2243 {
2244     *files = m_CustomConfH;
2245 }
2246 
2247 
GetBuildConfigs(list<SConfigInfo> * configs)2248 void CProjBulderApp::GetBuildConfigs(list<SConfigInfo>* configs)
2249 {
2250     configs->clear();
2251     string name = m_Dll ? "DllConfigurations" : "Configurations";
2252     const string& config_str
2253       = GetConfig().Get(CMsvc7RegSettings::GetMsvcSection(), name);
2254     list<string> configs_list;
2255     NStr::Split(config_str, LIST_SEPARATOR, configs_list, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
2256     LoadConfigInfoByNames(GetConfig(), configs_list, configs);
2257 }
2258 
2259 
GetRegSettings(void)2260 const CMsvc7RegSettings& CProjBulderApp::GetRegSettings(void)
2261 {
2262     if ( !m_MsvcRegSettings.get() ) {
2263         m_MsvcRegSettings.reset(new CMsvc7RegSettings());
2264 
2265         string section(CMsvc7RegSettings::GetMsvcRegSection());
2266 
2267         m_MsvcRegSettings->m_MakefilesExt =
2268             GetConfig().GetString(section, "MakefilesExt", "msvc");
2269 
2270         m_MsvcRegSettings->m_ProjectsSubdir  =
2271             GetConfig().GetString(section, "Projects", "build");
2272 
2273         m_MsvcRegSettings->m_MetaMakefile = CDirEntry::ConvertToOSPath(
2274             GetConfig().Get(section, "MetaMakefile"));
2275 
2276         m_MsvcRegSettings->m_DllInfo =
2277             GetConfig().Get(section, "DllInfo");
2278 
2279         m_MsvcRegSettings->m_Version = NStr::Replace(
2280             GetConfig().Get(CMsvc7RegSettings::GetMsvcSection(), "Version"),
2281             "\\n", "\n");
2282 
2283         m_MsvcRegSettings->m_CompilersSubdir  =
2284             GetConfig().Get(CMsvc7RegSettings::GetMsvcSection(), "msvc_prj");
2285 
2286         GetBuildConfigs(&m_MsvcRegSettings->m_ConfigInfo);
2287     }
2288     return *m_MsvcRegSettings;
2289 }
2290 
2291 
GetSite(void)2292 const CMsvcSite& CProjBulderApp::GetSite(void)
2293 {
2294     if ( !m_MsvcSite.get() ) {
2295         m_MsvcSite.reset(new CMsvcSite(GetConfigPath()));
2296     }
2297 
2298     return *m_MsvcSite;
2299 }
2300 
2301 
GetMetaMakefile(void)2302 const CMsvcMetaMakefile& CProjBulderApp::GetMetaMakefile(void)
2303 {
2304     if ( !m_MsvcMetaMakefile.get() ) {
2305         //Metamakefile must be in RootSrc directory
2306         m_MsvcMetaMakefile.reset(new CMsvcMetaMakefile
2307                     (CDirEntry::ConcatPath(GetProjectTreeInfo().m_Src,
2308                                            GetRegSettings().m_MetaMakefile)));
2309 
2310         //Metamakefile must present and must not be empty
2311         if ( m_MsvcMetaMakefile->IsEmpty() )
2312             NCBI_THROW(CProjBulderAppException,
2313                        eMetaMakefile, GetRegSettings().m_MetaMakefile);
2314     }
2315 
2316     return *m_MsvcMetaMakefile;
2317 }
2318 
2319 
GetProjectTreeInfo(void)2320 const SProjectTreeInfo& CProjBulderApp::GetProjectTreeInfo(void)
2321 {
2322     if ( m_ProjectTreeInfo.get() )
2323         return *m_ProjectTreeInfo;
2324 
2325     m_ProjectTreeInfo.reset(new SProjectTreeInfo);
2326 
2327     // Root, etc.
2328     m_ProjectTreeInfo->m_Root = m_Root;
2329     PTB_INFO("Project tree root: " << m_Root);
2330 
2331     // all possible project tags
2332     string tagsfile = CDirEntry::ConvertToOSPath(
2333         GetConfig().Get("ProjectTree", "ProjectTags"));
2334     if (!tagsfile.empty()) {
2335         string fileloc(CDirEntry::ConcatPath(m_ProjectTreeInfo->m_Root, tagsfile));
2336         if (!CDirEntry(fileloc).Exists() && !m_ExtSrcRoot.empty()) {
2337             fileloc = CDirEntry::ConcatPath(m_ExtSrcRoot,tagsfile);
2338         }
2339         LoadProjectTags(fileloc);
2340     }
2341 
2342     //dependencies
2343     list<string> depsfile;
2344     if (!FindDepGraph(m_ProjectTreeInfo->m_Root, depsfile) && !m_ExtSrcRoot.empty()) {
2345         FindDepGraph(m_ExtSrcRoot, depsfile);
2346     }
2347     if (!depsfile.empty()) {
2348         ITERATE(list<string>, d, depsfile) {
2349             PTB_INFO("Library dependencies graph: " << *d);
2350             LoadDepGraph(*d);
2351         }
2352     }
2353 
2354     /// <include> branch of tree
2355     string include = GetConfig().Get("ProjectTree", "include");
2356     m_ProjectTreeInfo->m_Include =
2357             CDirEntry::ConcatPath(m_ProjectTreeInfo->m_Root,
2358                                   include);
2359     m_ProjectTreeInfo->m_Include =
2360         CDirEntry::AddTrailingPathSeparator(m_ProjectTreeInfo->m_Include);
2361 
2362 
2363     /// <src> branch of tree
2364     string src = GetConfig().Get("ProjectTree", "src");
2365     m_ProjectTreeInfo->m_Src =
2366             CDirEntry::ConcatPath(m_ProjectTreeInfo->m_Root,
2367                                   src);
2368     m_ProjectTreeInfo->m_Src =
2369         CDirEntry::AddTrailingPathSeparator(m_ProjectTreeInfo->m_Src);
2370 
2371     // Subtree to build - projects filter
2372     string subtree = CDirEntry::ConcatPath(m_ProjectTreeInfo->m_Root, m_Subtree);
2373     PTB_INFO("Project list or subtree: " << subtree);
2374     if (!CDirEntry(subtree).Exists()) {
2375         PTB_WARNING_EX(kEmptyStr, ePTB_PathNotFound, "subtree does not exist: "<< subtree);
2376     }
2377     m_ProjectTreeInfo->m_IProjectFilter.reset(
2378         new CProjectsLstFileFilter(m_ProjectTreeInfo->m_Src, subtree));
2379 
2380     /// <compilers> branch of tree
2381     string compilers = GetConfig().Get("ProjectTree", "compilers");
2382     m_ProjectTreeInfo->m_Compilers =
2383             CDirEntry::ConcatPath(m_ProjectTreeInfo->m_Root,
2384                                   compilers);
2385     m_ProjectTreeInfo->m_Compilers =
2386         CDirEntry::AddTrailingPathSeparator
2387                    (m_ProjectTreeInfo->m_Compilers);
2388 
2389     /// ImplicitExcludedBranches - all subdirs will be excluded by default
2390     string implicit_exclude_str
2391         = GetConfig().Get("ProjectTree", "ImplicitExclude");
2392     list<string> implicit_exclude_list;
2393     NStr::Split(implicit_exclude_str,
2394                 LIST_SEPARATOR,
2395                 implicit_exclude_list, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
2396     ITERATE(list<string>, p, implicit_exclude_list) {
2397         const string& subdir = *p;
2398         string dir = CDirEntry::ConcatPath(m_ProjectTreeInfo->m_Src,
2399                                            subdir);
2400         dir = CDirEntry::AddTrailingPathSeparator(dir);
2401         m_ProjectTreeInfo->m_ImplicitExcludedAbsDirs.push_back(dir);
2402     }
2403 
2404     /// <projects> branch of tree (scripts\projects)
2405     string projects = CDirEntry::ConvertToOSPath(
2406         GetConfig().Get("ProjectTree", "projects"));
2407     m_ProjectTreeInfo->m_Projects =
2408             CDirEntry::ConcatPath(m_ProjectTreeInfo->m_Root,
2409                                   projects);
2410     m_ProjectTreeInfo->m_Projects =
2411         CDirEntry::AddTrailingPathSeparator
2412                    (m_ProjectTreeInfo->m_Compilers);
2413 
2414     /// impl part if include project node
2415     m_ProjectTreeInfo->m_Impl =
2416         GetConfig().Get("ProjectTree", "impl");
2417 
2418     /// Makefile in tree node
2419     m_ProjectTreeInfo->m_TreeNode =
2420         GetConfig().Get("ProjectTree", "TreeNode");
2421 
2422     m_ProjectTreeInfo->m_CustomMetaData =
2423         GetConfig().Get("ProjectTree", "CustomMetaData");
2424     m_ProjectTreeInfo->m_CustomConfH =
2425         GetConfig().Get("ProjectTree", "CustomConfH");
2426 
2427     return *m_ProjectTreeInfo;
2428 }
2429 
2430 
GetBuildType(void)2431 const CBuildType& CProjBulderApp::GetBuildType(void)
2432 {
2433     if ( !m_BuildType.get() ) {
2434         m_BuildType.reset(new CBuildType(m_Dll));
2435     }
2436     return *m_BuildType;
2437 }
2438 
GetWholeTree(void)2439 const CProjectItemsTree& CProjBulderApp::GetWholeTree(void)
2440 {
2441     if ( !m_WholeTree.get() ) {
2442         m_WholeTree.reset(new CProjectItemsTree);
2443         if (m_ScanWholeTree) {
2444             m_ScanningWholeTree = true;
2445             CProjectsLstFileFilter pass_all_filter(m_ProjectTreeInfo->m_Src, m_ProjectTreeInfo->m_Src);
2446 //            pass_all_filter.SetExcludePotential(false);
2447             CProjectTreeBuilder::BuildProjectTree(&pass_all_filter,
2448                                                 GetProjectTreeInfo().m_Src,
2449                                                 m_WholeTree.get());
2450             m_ScanningWholeTree = false;
2451         }
2452     }
2453     return *m_WholeTree;
2454 }
2455 
2456 
GetDllFilesDistr(void)2457 CDllSrcFilesDistr& CProjBulderApp::GetDllFilesDistr(void)
2458 {
2459     if (m_DllSrcFilesDistr.get())
2460         return *m_DllSrcFilesDistr;
2461 
2462     m_DllSrcFilesDistr.reset ( new CDllSrcFilesDistr() );
2463     return *m_DllSrcFilesDistr;
2464 }
2465 
GetDataspecProjId(void) const2466 string CProjBulderApp::GetDataspecProjId(void) const
2467 {
2468     return "_generate_all_objects";
2469 }
2470 
GetDatatoolId(void) const2471 string CProjBulderApp::GetDatatoolId(void) const
2472 {
2473     return GetConfig().GetString("Datatool", "datatool",
2474         CMsvc7RegSettings::GetMsvcPlatform() >= CMsvc7RegSettings::eUnix ? "datatool" : "");
2475 }
2476 
2477 
GetDatatoolPathForApp(void) const2478 string CProjBulderApp::GetDatatoolPathForApp(void) const
2479 {
2480     if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eXCode) {
2481         return GetConfig().GetString("Datatool", "Location.xcode", "datatool");
2482     }
2483     return GetConfig().GetString("Datatool", "Location.App", "datatool.exe");
2484 }
2485 
2486 
GetDatatoolPathForLib(void) const2487 string CProjBulderApp::GetDatatoolPathForLib(void) const
2488 {
2489     if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eXCode) {
2490         return GetConfig().GetString("Datatool", "Location.xcode", "datatool");
2491     }
2492     return GetConfig().GetString("Datatool", "Location.Lib", "datatool.exe");
2493 }
2494 
2495 
GetDatatoolCommandLine(void) const2496 string CProjBulderApp::GetDatatoolCommandLine(void) const
2497 {
2498     if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eXCode) {
2499         return GetConfig().GetString("Datatool", "CommandLine.xcode", "");
2500     }
2501     return GetConfig().Get("Datatool", "CommandLine");
2502 }
2503 
GetProjectTreeRoot(void) const2504 string CProjBulderApp::GetProjectTreeRoot(void) const
2505 {
2506     string path = CDirEntry::ConcatPath(
2507         m_ProjectTreeInfo->m_Compilers,
2508         m_MsvcRegSettings->m_CompilersSubdir);
2509     return CDirEntry::AddTrailingPathSeparator(path);
2510 }
2511 
IsAllowedProjectTag(const CProjItem & project,const string * filter) const2512 bool CProjBulderApp::IsAllowedProjectTag(
2513     const CProjItem& project, const string* filter /*= NULL*/) const
2514 {
2515     // verify that all project tags are registered
2516     list<string>::const_iterator i;
2517     for (i = project.m_ProjTags.begin(); i != project.m_ProjTags.end(); ++i) {
2518         if (m_RegisteredProjectTags.find(*i) == m_RegisteredProjectTags.end()) {
2519             NCBI_THROW(CProjBulderAppException, eUnknownProjectTag,
2520                 project.GetPath() + ": Unregistered project tag: " + *i);
2521             return false;
2522         }
2523     }
2524 
2525     if (filter == NULL) {
2526         filter = &m_ProjTags;
2527     }
2528     // no filter - everything is allowed
2529     if (filter->empty() || *filter == "*") {
2530         return true;
2531     }
2532 
2533     CExprParser parser;
2534     ITERATE( set<string>, p, m_RegisteredProjectTags) {
2535         parser.AddSymbol(p->c_str(),
2536             find( project.m_ProjTags.begin(), project.m_ProjTags.end(), *p) != project.m_ProjTags.end());
2537     }
2538     parser.Parse(filter->c_str());
2539     return parser.GetResult().GetBool();
2540 }
2541 
LoadProjectTags(const string & filename)2542 void CProjBulderApp::LoadProjectTags(const string& filename)
2543 {
2544     CNcbiIfstream ifs(filename.c_str(), IOS_BASE::in | IOS_BASE::binary);
2545     if ( ifs.is_open() ) {
2546         string line;
2547         while ( NcbiGetlineEOL(ifs, line) ) {
2548             if (line.empty() || line[0] == '#') {
2549                 continue;
2550             }
2551             list<string> values;
2552             if (line.find('=') != string::npos) {
2553                 NStr::Split(line, "=", values, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
2554                 if (values.size() > 1) {
2555                     string first = NStr::TruncateSpaces(values.front());
2556                     string second = NStr::TruncateSpaces(values.back());
2557                     m_CompositeProjectTags[first] = second;
2558 
2559                 }
2560                 continue;
2561             }
2562             NStr::Split(line, LIST_SEPARATOR, values, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
2563             ITERATE(list<string>,v,values) {
2564                 m_RegisteredProjectTags.insert(*v);
2565             }
2566         }
2567     }
2568     m_RegisteredProjectTags.insert("exe");
2569     m_RegisteredProjectTags.insert("lib");
2570     m_RegisteredProjectTags.insert("dll");
2571     m_RegisteredProjectTags.insert("public");
2572     m_RegisteredProjectTags.insert("internal");
2573 }
2574 
FindDepGraph(const string & root,list<string> & found) const2575 bool  CProjBulderApp::FindDepGraph(const string& root, list<string>& found) const
2576 {
2577     found.clear();
2578     list<string> locations;
2579     string locstr(GetConfig().Get("ProjectTree", "DepGraph"));
2580     NStr::Split(locstr, LIST_SEPARATOR, locations, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
2581     for (list<string>::const_iterator l = locations.begin(); l != locations.end(); ++l) {
2582         CDirEntry fileloc(CDirEntry::ConcatPath(root,CDirEntry::ConvertToOSPath(*l)));
2583         if (fileloc.Exists() && fileloc.IsFile()) {
2584             found.push_back(fileloc.GetPath());
2585         }
2586     }
2587     return !found.empty();
2588 }
2589 
LoadDepGraph(const string & filename)2590 void   CProjBulderApp::LoadDepGraph(const string& filename)
2591 {
2592     const CMsvcSite& site = GetSite();
2593     CNcbiIfstream ifs(filename.c_str(), IOS_BASE::in);
2594     if ( ifs.is_open() ) {
2595         string line;
2596         while ( NcbiGetlineEOL(ifs, line) ) {
2597             if (line.empty() || line[0] == '#') {
2598                 continue;
2599             }
2600             list<string> values;
2601             NStr::Split(line, " ", values, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
2602             if (values.size() < 2) {
2603                 continue;
2604             }
2605             list<string>::const_iterator l= values.begin();
2606             string first  = *l++;
2607             string second = *l++;
2608             string third  = values.size() > 2 ? (*l++) : string();
2609 
2610             list<string> first_list;
2611             if (CSymResolver::IsDefine(first)) {
2612                 string resolved;
2613                 site.ResolveDefine(CSymResolver::StripDefine(first), resolved);
2614                 first = resolved;
2615             }
2616             NStr::Split(first, LIST_SEPARATOR_LIBS, first_list, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
2617 
2618             list<string> third_list;
2619 #if DO_PATCHTREEMAKEFILES
2620             if (!third.empty()) {
2621                 third_list.push_back(third);
2622             }
2623 #else
2624             if (CSymResolver::IsDefine(third)) {
2625                 string resolved;
2626                 if (CMsvc7RegSettings::GetMsvcPlatform() != CMsvc7RegSettings::eUnix) {
2627                     string stripped(CSymResolver::StripDefine(third));
2628                     if (stripped != "NCBI_C_ncbi") {
2629                         site.ResolveDefine(stripped, resolved);
2630                     }
2631                     if (resolved.empty()) {
2632                         resolved = "@" + stripped + "@";
2633                     }
2634                 } else {
2635                     site.ResolveDefine(CSymResolver::StripDefine(third), resolved);
2636                 }
2637                 third = resolved;
2638             }
2639             NStr::Split(third, LIST_SEPARATOR_LIBS, third_list, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
2640 #endif
2641             ITERATE(list<string>, f, first_list) {
2642                 string f_name(*f);
2643                 if (NStr::StartsWith(*f, "-l")) {
2644                     f_name = f->substr(2);
2645                 } else if (NStr::FindCase(*f,"-framework") != NPOS) {
2646                     list<string> f_list;
2647                     NStr::Split(f_name, ",", f_list, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
2648                     f_name = f_list.back();
2649                 } else if (f->at(0) == '-') {
2650                     continue;
2651                 }
2652                 map<string, set<string> >  lib3Precedes;
2653                 CSymResolver::StripSuffix(f_name);
2654                 if (third_list.empty() && m_GraphDepPrecedes.find(f_name) == m_GraphDepPrecedes.end()) {
2655                     m_GraphDepPrecedes[f_name] = set<string>();
2656                 }
2657                 ITERATE(list<string>, t, third_list) {
2658                     string t_name(*t);
2659                     CSymResolver::StripSuffix(t_name);
2660                     bool is_lib = false;
2661                     bool is_framework = false;
2662                     if (NStr::StartsWith(*t, "-l")) {
2663                         is_lib = true;
2664                         t_name = t_name.substr(2);
2665                     } else if (NStr::CompareNocase(*t,"-framework") == 0) {
2666                         if (t != third_list.end()) {
2667                             is_framework = true;
2668                             t_name = *(++t);
2669                         } else {
2670                             continue;
2671                         }
2672                     } else {
2673                         is_lib = t->at(0) != '-';
2674                     }
2675                     if (*f == t_name) {
2676                         continue;
2677                     }
2678                     if (!is_lib && !is_framework) {
2679                         if (second == "needs3party") {
2680                             m_GraphDepFlags[*f].insert(t_name);
2681                         }
2682                         continue;
2683                     }
2684                     if (second == "includes") {
2685                         m_GraphDepIncludes[*f].insert(t_name);
2686                     } else if (second == "includes3party") {
2687                         m_GraphDepIncludes[*f].insert(t_name);
2688                         m_3PartyLibs.insert(t_name);
2689                         if (is_framework) {
2690                             m_Frameworks.insert(t_name);
2691                         }
2692                     } else if (second == "needs") {
2693                         m_GraphDepPrecedes[*f].insert(t_name);
2694                     } else if (second == "needs3party") {
2695                         m_GraphDepPrecedes[*f].insert(t_name);
2696                         m_3PartyLibs.insert(t_name);
2697                         if (is_framework) {
2698                             m_Frameworks.insert(t_name);
2699                         }
2700                     }
2701                 }
2702             }
2703         }
2704     }
2705     for ( map<string, set<string> >::const_iterator i = m_GraphDepIncludes.begin();
2706         i != m_GraphDepIncludes.end(); ++i) {
2707         const set<string>& inc = i->second;
2708         for (set<string>::const_iterator m = inc.begin(); m != inc.end(); ++m) {
2709             CollectDep(i->first, *m);
2710         }
2711     }
2712 //    RankDepGraph();
2713 }
2714 
CollectDep(const string & libname,const string & incname)2715 void CProjBulderApp::CollectDep(const string& libname, const string& incname)
2716 {
2717     if (incname[0] == '@') {
2718         return;
2719     }
2720     const set<string>& deps = m_GraphDepPrecedes[incname];
2721     for (set<string>::const_iterator d = deps.begin(); d != deps.end(); ++d) {
2722         m_GraphDepPrecedes[libname].insert(*d);
2723     }
2724     if (m_GraphDepFlags.find(incname) != m_GraphDepFlags.end()) {
2725         const set<string>& flags = m_GraphDepFlags[incname];
2726         for (set<string>::const_iterator d = flags.begin(); d != flags.end(); ++d) {
2727             m_GraphDepFlags[libname].insert(*d);
2728         }
2729     }
2730     if (m_GraphDepIncludes.find(incname) != m_GraphDepIncludes.end()) {
2731         const set<string>& inc = m_GraphDepIncludes.find(incname)->second;
2732         for (set<string>::const_iterator m = inc.begin(); m != inc.end(); ++m) {
2733             CollectDep(libname, *m);
2734         }
2735     }
2736 }
2737 
UpdateDepGraph(CProjectTreeBuilder::TFiles & files)2738 void CProjBulderApp::UpdateDepGraph( CProjectTreeBuilder::TFiles& files)
2739 {
2740 #if DO_PATCHTREEMAKEFILES
2741     return;
2742 #endif
2743     if (!IsScanningWholeTree()) {
2744         return;
2745     }
2746     const CMsvcSite& site = GetSite();
2747     ITERATE( CProjectTreeBuilder::TFiles, f, files) {
2748         const CSimpleMakeFileContents& fc( f->second);
2749         string libname;
2750         fc.GetValue("LIB", libname);
2751         list<string> libdep;
2752         fc.GetValue("USES_LIBRARIES", libdep);
2753         if (!libdep.empty()) {
2754             if (m_GraphDepPrecedes.find(libname) == m_GraphDepPrecedes.end()) {
2755                 set<string> t;
2756                 m_GraphDepPrecedes[libname] = t;
2757             }
2758             ITERATE(list<string>, l, libdep) {
2759                 list<string> dep_list;
2760                 string dep(*l);
2761                 if (dep.at(0) == '#') {
2762                     break;
2763                 }
2764                 if (CSymResolver::IsDefine(dep)) {
2765                     string resolved;
2766                     if (CMsvc7RegSettings::GetMsvcPlatform() != CMsvc7RegSettings::eUnix) {
2767                         string stripped(CSymResolver::StripDefine(dep));
2768                         if (stripped != "NCBI_C_ncbi") {
2769                             site.ResolveDefine(stripped, resolved);
2770                         }
2771                         if (resolved.empty()) {
2772                             resolved = "@" + stripped + "@";
2773                         }
2774                     } else {
2775                         site.ResolveDefine(CSymResolver::StripDefine(dep), resolved);
2776                     }
2777                     dep = resolved;
2778                 }
2779                 NStr::Split(dep, LIST_SEPARATOR_LIBS, dep_list, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
2780                 ITERATE(list<string>, d, dep_list) {
2781                     string dep_name = NStr::StartsWith(*d, "-l") ? d->substr(2) : *d;
2782                     CSymResolver::StripSuffix(dep_name);
2783                     if (dep_name.at(0) == '-' || libname == dep_name) {
2784                         continue;
2785                     }
2786                     m_GraphDepPrecedes[libname].insert(dep_name);
2787                 }
2788             }
2789         }
2790     }
2791     RankDepGraph();
2792 }
2793 
RankDepGraph(void)2794 void  CProjBulderApp::RankDepGraph(void)
2795 {
2796 #if DO_PATCHTREEMAKEFILES
2797     return;
2798 #endif
2799     if (CMsvc7RegSettings::GetMsvcPlatform() != CMsvc7RegSettings::eUnix || !m_LibDep) {
2800         return;
2801     }
2802     vector< set<string> > graph;
2803     for (map<string, set<string> >::const_iterator d= m_GraphDepPrecedes.begin();
2804             d!= m_GraphDepPrecedes.end(); ++d) {
2805         list<string> done;
2806         done.push_back(d->first);
2807         InsertDep(graph, d->first, done);
2808     }
2809     for (size_t s= 0; s<graph.size(); ++s) {
2810         for (set<string>::const_iterator l = graph[s].begin(); l != graph[s].end(); ++l) {
2811             m_GraphDepRank[*l] = s;
2812         }
2813     }
2814 }
2815 
InsertDep(vector<set<string>> & graph,const string & dep,list<string> & done)2816 bool  CProjBulderApp::InsertDep(vector< set<string> >& graph, const string& dep, list<string>& done)
2817 {
2818     const set<string>& dependents = m_GraphDepPrecedes[dep];
2819     size_t graphset=0;
2820     for (set<string>::const_iterator d = dependents.begin(); d != dependents.end(); ++d) {
2821         if (m_GraphDepPrecedes.find(*d) == m_GraphDepPrecedes.end()) {
2822             continue;
2823         }
2824         if (find(done.begin(), done.end(), *d) != done.end()) {
2825             done.push_back(*d);
2826             PTB_ERROR_EX(m_Root, ePTB_ConfigurationError,
2827                     "Library dependency cycle found: " << NStr::Join(done, " - "));
2828             done.pop_back();
2829             //m_GraphDepPrecedes.erase(*d);
2830             return false;
2831         }
2832         done.push_back(*d);
2833         for (bool found=false; !found; ) {
2834             for (size_t s= 0; !found && s<graph.size(); ++s) {
2835                 if (graph[s].find(*d) != graph[s].end()) {
2836                     graphset = max(graphset,s);
2837                     found = true;
2838                 }
2839             }
2840             if (!found) {
2841                 found  = !InsertDep(graph, *d, done);
2842             }
2843         }
2844         done.pop_back();
2845     }
2846     if (!dependents.empty()) {
2847         ++graphset;
2848     }
2849     if (graphset < graph.size()) {
2850         graph[graphset].insert(dep);
2851     } else {
2852         set<string> t;
2853         t.insert(dep);
2854         graph.push_back(t);
2855     }
2856     return true;
2857 }
2858 
ProcessLocationMacros(string raw_data)2859 string CProjBulderApp::ProcessLocationMacros(string raw_data)
2860 {
2861     string data(raw_data), raw_macro, macro, definition;
2862     string::size_type start, end, done = 0;
2863     while ((start = data.find("$(", done)) != string::npos) {
2864         end = data.find(")", start);
2865         if (end == string::npos) {
2866             PTB_WARNING_EX(kEmptyStr, ePTB_MacroInvalid, "Possibly incorrect MACRO definition in: " + raw_data);
2867             return data;
2868         }
2869         raw_macro = data.substr(start,end-start+1);
2870         if (CSymResolver::IsDefine(raw_macro)) {
2871             macro = CSymResolver::StripDefine(raw_macro);
2872             definition.erase();
2873             definition = GetConfig().GetString(CMsvc7RegSettings::GetMsvcSection(), macro, "");
2874             if (!definition.empty()) {
2875                 definition = CDirEntry::ConcatPath(
2876                     m_ProjectTreeInfo->m_Compilers, definition);
2877                 data = NStr::Replace(data, raw_macro, definition);
2878             } else {
2879                 done = end;
2880             }
2881         }
2882     }
2883     return data;
2884 }
2885 
GetConfigureMacro(string data)2886 string CProjBulderApp::GetConfigureMacro(string data)
2887 {
2888     string definition = GetConfig().GetString(CMsvc7RegSettings::GetMsvcSection(), data, "");
2889     if (!definition.empty()) {
2890         definition = CDirEntry::ConcatPath( m_ProjectTreeInfo->m_Compilers, definition);
2891     }
2892     return definition;
2893 }
2894 
RegisterSuspiciousProject(const CProjKey & proj)2895 void CProjBulderApp::RegisterSuspiciousProject(const CProjKey& proj)
2896 {
2897     m_SuspiciousProj.insert(proj);
2898 }
2899 
RegisterGeneratedFile(const string & file)2900 void CProjBulderApp::RegisterGeneratedFile( const string& file)
2901 {
2902     m_GeneratedFiles.push_back(file);
2903 }
2904 
RegisterProjectWatcher(const string & project,const string & dir,const string & watcher)2905 void CProjBulderApp::RegisterProjectWatcher(
2906     const string& project, const string& dir,  const string& watcher)
2907 {
2908     if (watcher.empty()) {
2909         return;
2910     }
2911     string sep;
2912     sep += CDirEntry::GetPathSeparator();
2913     string root(GetProjectTreeInfo().m_Src);
2914     if (!CDirEntry::IsAbsolutePath(root)) {
2915         root = CDirEntry::ConcatPath(CDir::GetCwd(), root);
2916     }
2917     string path(dir);
2918     if (!CDirEntry::IsAbsolutePath(path)) {
2919         path = CDirEntry::ConcatPath(CDir::GetCwd(), path);
2920     }
2921     path = CDirEntry::DeleteTrailingPathSeparator(
2922         CDirEntry::CreateRelativePath(root, path));
2923     NStr::ReplaceInPlace( path, sep, "/");
2924     m_ProjWatchers.push_back( project + ", " + path + ", " + watcher );
2925 }
2926 
ExcludeProjectsByTag(CProjectItemsTree & tree) const2927 void CProjBulderApp::ExcludeProjectsByTag(CProjectItemsTree& tree) const
2928 {
2929     EraseIf(tree.m_Projects, PIsExcludedByTag());
2930     if (!m_ProjTags.empty() && m_ProjTags != "*") {
2931         NON_CONST_ITERATE(CProjectItemsTree::TProjects, p, tree.m_Projects) {
2932             if (p->second.m_ProjType == CProjKey::eDll) {
2933                 p->second.m_External = false;
2934             }
2935         }
2936     }
2937 }
2938 
ExcludeUnrequestedProjects(CProjectItemsTree & tree) const2939 void CProjBulderApp::ExcludeUnrequestedProjects(CProjectItemsTree& tree) const
2940 {
2941     EraseIf(tree.m_Projects, PIsExcludedByUser());
2942 }
2943 
GetUtilityProjectsDir(void) const2944 string CProjBulderApp::GetUtilityProjectsDir(void) const
2945 {
2946     string utility_projects_dir = CDirEntry(m_Solution).GetDir();
2947     utility_projects_dir =
2948         CDirEntry::ConcatPath(utility_projects_dir, "UtilityProjects");
2949     utility_projects_dir =
2950         CDirEntry::AddTrailingPathSeparator(utility_projects_dir);
2951     return utility_projects_dir;
2952 }
2953 
GetUtilityProjectsSrcDir(void)2954 string CProjBulderApp::GetUtilityProjectsSrcDir(void)
2955 {
2956     string prj = GetProjectTreeInfo().m_Compilers;
2957     prj = CDirEntry::ConcatPath(prj, GetRegSettings().m_CompilersSubdir);
2958     prj = CDirEntry::ConcatPath(prj, GetBuildType().GetTypeStr());
2959     prj = CDirEntry::ConcatPath(prj, GetRegSettings().m_ProjectsSubdir);
2960 
2961     string sln = CDirEntry(m_Solution).GetDir();
2962     prj = CDirEntry::CreateRelativePath( prj, sln);
2963     prj = CDirEntry::ConcatPath(GetProjectTreeInfo().m_Src, prj);
2964     prj = CDirEntry::ConcatPath(prj, "UtilityProjects");
2965     prj = CDirEntry::AddTrailingPathSeparator(prj);
2966     return prj;
2967 }
2968 
SetConfFileData(const string & src,const string & dest)2969 void CProjBulderApp::SetConfFileData(const string& src, const string& dest)
2970 {
2971     m_ConfSrc = src;
2972     m_ConfDest= dest;
2973 }
2974 
GetBuildDir(void)2975 string CProjBulderApp::GetBuildDir(void)
2976 {
2977     return  CDirEntry::AddTrailingPathSeparator(
2978         CDirEntry::ConcatPath( CDirEntry::ConcatPath( CDirEntry::ConcatPath(
2979             GetProjectTreeInfo().m_Compilers, GetRegSettings().m_CompilersSubdir),
2980             GetBuildType().GetTypeStr()), GetRegSettings().m_ProjectsSubdir));
2981 }
2982 
GetApp(void)2983 CProjBulderApp& GetApp(void)
2984 {
2985     static CProjBulderApp theApp;
2986     return theApp;
2987 }
2988 
2989 END_NCBI_SCOPE
2990 
2991 
2992 USING_NCBI_SCOPE;
2993 
NcbiSys_main(int argc,TXChar * argv[])2994 int NcbiSys_main(int argc, TXChar* argv[])
2995 {
2996     // Execute main application function
2997     CDiagContext::SetLogTruncate(true);
2998     GetDiagContext().SetLogRate_Limit(CDiagContext::eLogRate_Err, (unsigned int)-1);
2999     return GetApp().AppMain(argc, argv);
3000 }
3001