1 /* $Id: msvc_makefile.cpp 576401 2018-12-14 15:04:17Z 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 "stl_msvc_usage.hpp"
32 #include "msvc_makefile.hpp"
33 #include "proj_builder_app.hpp"
34 #include "msvc_prj_defines.hpp"
35 
36 #include <algorithm>
37 
38 #include <corelib/ncbistr.hpp>
39 
40 BEGIN_NCBI_SCOPE
41 
42 //-----------------------------------------------------------------------------
CMsvcMetaMakefile(const string & file_path)43 CMsvcMetaMakefile::CMsvcMetaMakefile(const string& file_path)
44 {
45 #if defined(NCBI_COMPILER_MSVC) || defined(NCBI_XCODE_BUILD) || defined(PSEUDO_XCODE)
46     if (CFile(file_path).Exists()) {
47         CNcbiIfstream ifs(file_path.c_str(), IOS_BASE::in | IOS_BASE::binary);
48         //read registry
49         m_MakeFile.Read(ifs);
50         //and remember dir from where it has been loaded
51         CDirEntry::SplitPath(file_path, &m_MakeFileBaseDir);
52 //        LOG_POST(Info << "Using rules from " << file_path);
53     }
54 #endif //NCBI_COMPILER_MSVC
55 }
56 
57 
IsEmpty(void) const58 bool CMsvcMetaMakefile::IsEmpty(void) const
59 {
60     return m_MakeFile.Empty();
61 }
62 
TranslateOpt(const string & value,const string & section,const string & opt)63 string CMsvcMetaMakefile::TranslateOpt(
64     const string& value, const string& section, const string& opt)
65 {
66     if (value.empty() ||
67         (CMsvc7RegSettings::GetMsvcVersion() < CMsvc7RegSettings::eMsvc1000 ||
68         CMsvc7RegSettings::GetMsvcVersion() >= CMsvc7RegSettings::eXCode30) ) {
69         return value;
70     }
71     string name(section+"_"+opt+"_"+value);
72     return GetApp().GetMetaMakefile().m_MakeFile.GetString(
73         "Translate", name, value);
74 }
75 
TranslateCommand(const string & value)76 string CMsvcMetaMakefile::TranslateCommand(const string& value)
77 {
78     if (value.empty() ||
79         (CMsvc7RegSettings::GetMsvcVersion() < CMsvc7RegSettings::eMsvc1000 ||
80         CMsvc7RegSettings::GetMsvcVersion() >= CMsvc7RegSettings::eXCode30) ) {
81         return value;
82     }
83     const CMsvcMetaMakefile& meta = GetApp().GetMetaMakefile();
84 
85     string data(value), raw_macro, macro, definition;
86     string::size_type start, end, done = 0;
87     for (;;) {
88         if ((start = data.find("$(", done)) == string::npos) {
89             break;
90         }
91         end = data.find(")", start);
92         if (end == string::npos) {
93             break;
94         }
95         raw_macro = data.substr(start,end-start+1);
96         if (CSymResolver::IsDefine(raw_macro)) {
97             macro = CSymResolver::StripDefine(raw_macro);
98             definition = meta.m_MakeFile.Get("Translate", string("Macro_") + macro);
99             if (definition.empty()) {
100                 done = end;
101             } else {
102                 data = NStr::Replace(data, raw_macro, definition);
103                 done = 0;
104             }
105         }
106     }
107     data = NStr::Replace(data, "@echo", "%40echo");
108     return data;
109 }
110 
GetConfigurationOpt(const string & opt,const SConfigInfo & config) const111 string CMsvcMetaMakefile::GetConfigurationOpt(const string& opt,
112                                          const SConfigInfo& config) const
113 {
114     string sec("Configuration");
115     return TranslateOpt( GetOpt(m_MakeFile, sec, opt, config), sec, opt);
116 }
117 
GetCompilerOpt(const string & opt,const SConfigInfo & config) const118 string CMsvcMetaMakefile::GetCompilerOpt(const string& opt,
119                                          const SConfigInfo& config) const
120 {
121     string sec("Compiler");
122     return TranslateOpt( GetOpt(m_MakeFile, sec, opt, config), sec, opt);
123 }
124 
125 
GetLinkerOpt(const string & opt,const SConfigInfo & config) const126 string CMsvcMetaMakefile::GetLinkerOpt(const string& opt,
127                                        const SConfigInfo& config) const
128 {
129     string sec("Linker");
130     return TranslateOpt( GetOpt(m_MakeFile, sec, opt, config), sec, opt);
131 }
132 
133 
GetLibrarianOpt(const string & opt,const SConfigInfo & config) const134 string CMsvcMetaMakefile::GetLibrarianOpt(const string& opt,
135                                           const SConfigInfo& config) const
136 {
137     string sec("Librarian");
138     return TranslateOpt( GetOpt(m_MakeFile, sec, opt, config), sec, opt);
139 }
140 
141 
GetResourceCompilerOpt(const string & opt,const SConfigInfo & config) const142 string CMsvcMetaMakefile::GetResourceCompilerOpt
143                           (const string& opt, const SConfigInfo& config) const
144 {
145     string sec("ResourceCompiler");
146     return TranslateOpt( GetOpt(m_MakeFile, sec, opt, config), sec, opt);
147 }
148 
GetConfigOpt(const string & section,const string & opt,const SConfigInfo & config) const149 string CMsvcMetaMakefile::GetConfigOpt(
150     const string& section, const string& opt, const SConfigInfo& config) const
151 {
152     return GetOpt(m_MakeFile, section, opt, config);
153 }
154 
155 
IsPchEnabled(void) const156 bool CMsvcMetaMakefile::IsPchEnabled(void) const
157 {
158     return GetPchInfo().m_UsePch;
159 }
160 
161 
GetUsePchThroughHeader(const string & project_id,const string & source_file_full_path,const string & tree_src_dir) const162 string CMsvcMetaMakefile::GetUsePchThroughHeader
163                           (const string& project_id,
164                            const string& source_file_full_path,
165                            const string& tree_src_dir) const
166 {
167     const SPchInfo& pch_info = GetPchInfo();
168 
169     if (find(pch_info.m_DontUsePchList.begin(),
170              pch_info.m_DontUsePchList.end(),
171              project_id) != pch_info.m_DontUsePchList.end()) {
172         return kEmptyStr;
173     }
174 
175     string source_file_dir;
176     CDirEntry::SplitPath(source_file_full_path, &source_file_dir);
177     source_file_dir = CDirEntry::AddTrailingPathSeparator(source_file_dir);
178 
179     size_t max_match = 0;
180     string pch_file;
181     bool found = false;
182     ITERATE(SPchInfo::TSubdirPchfile, p, pch_info.m_PchUsageMap) {
183         const string& branch_subdir = p->first;
184         string abs_branch_subdir =
185             CDirEntry::ConcatPath(tree_src_dir, branch_subdir);
186         abs_branch_subdir =
187             CDirEntry::AddTrailingPathSeparator(abs_branch_subdir);
188         if ( IsSubdir(abs_branch_subdir, source_file_dir) ) {
189             if ( branch_subdir.length() > max_match ) {
190                 max_match = branch_subdir.length();
191                 pch_file  = p->second;
192                 found = true;
193             }
194         }
195     }
196     if (found) {
197         return pch_file;
198     }
199     return m_PchInfo->m_DefaultPch;
200 }
201 
202 
GetPchInfo(void) const203 const CMsvcMetaMakefile::SPchInfo& CMsvcMetaMakefile::GetPchInfo(void) const
204 {
205     if ( m_PchInfo.get() )
206         return *m_PchInfo;
207 
208     (const_cast<CMsvcMetaMakefile&>(*this)).m_PchInfo.reset(new SPchInfo);
209 
210     string use_pch_str          = m_MakeFile.GetString("UsePch", "UsePch", "TRUE");
211     m_PchInfo->m_UsePch = NStr::StringToBool(use_pch_str);
212     m_PchInfo->m_PchUsageDefine = m_MakeFile.GetString("UsePch", "PchUsageDefine");
213     m_PchInfo->m_DefaultPch     = m_MakeFile.GetString("UsePch", "DefaultPch");
214     string do_not_use_pch_str   = m_MakeFile.GetString("UsePch", "DoNotUsePch");
215     NStr::Split(do_not_use_pch_str, LIST_SEPARATOR, m_PchInfo->m_DontUsePchList, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
216     string irrelevant[] = {"UsePch","PchUsageDefine","DefaultPch","DoNotUsePch",""};
217 
218     list<string> projects_with_pch_dirs;
219     m_MakeFile.EnumerateEntries("UsePch", &projects_with_pch_dirs);
220     ITERATE(list<string>, p, projects_with_pch_dirs) {
221         const string& key = *p;
222         bool ok = true;
223         for (int i=0; ok && !irrelevant[i].empty(); ++i) {
224             ok = key != irrelevant[i];
225         }
226         if (!ok)
227             continue;
228 
229         string val = m_MakeFile.GetString("UsePch", key, "-");
230         if ( val == "-" ) {
231             val = "";
232         }
233         string tmp = CDirEntry::ConvertToOSPath(key);
234         m_PchInfo->m_PchUsageMap[tmp] = val;
235     }
236     return *m_PchInfo;
237 }
238 
GetPchUsageDefine(void) const239 string CMsvcMetaMakefile::GetPchUsageDefine(void) const
240 {
241     return GetPchInfo().m_PchUsageDefine;
242 }
243 //-----------------------------------------------------------------------------
CreateMsvcProjectMakefileName(const string & project_name,CProjItem::TProjType type)244 string CreateMsvcProjectMakefileName(const string&        project_name,
245                                      CProjItem::TProjType type)
246 {
247     string name("Makefile.");
248 
249     name += project_name + '.';
250 
251     switch (type) {
252     case CProjKey::eApp:
253         name += "app.";
254         break;
255     case CProjKey::eLib:
256         name += "lib.";
257         break;
258     case CProjKey::eDll:
259         name += "dll.";
260         break;
261     case CProjKey::eMsvc:
262         if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eMsvcWin32 ||
263             CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eMsvcX64) {
264             name += "msvcproj.";
265         }
266         break;
267     case CProjKey::eDataSpec:
268         name += "dataspec.";
269         break;
270     case CProjKey::eUtility:
271         name += "utility.";
272         break;
273     default:
274         NCBI_THROW(CProjBulderAppException,
275                    eProjectType,
276                    NStr::IntToString(type));
277         break;
278     }
279     name += GetApp().GetRegSettings().m_MakefilesExt;
280     return name;
281 }
282 
283 
CreateMsvcProjectMakefileName(const CProjItem & project)284 string CreateMsvcProjectMakefileName(const CProjItem& project)
285 {
286     return CreateMsvcProjectMakefileName(project.m_Name,
287                                          project.m_ProjType);
288 }
289 
290 
291 //-----------------------------------------------------------------------------
CMsvcProjectMakefile(const string & file_path,bool compound)292 CMsvcProjectMakefile::CMsvcProjectMakefile(const string& file_path, bool compound)
293     :CMsvcMetaMakefile(file_path)
294 {
295     CDirEntry::SplitPath(file_path, &m_ProjectBaseDir);
296     m_FilePath = file_path;
297     m_Compound = compound;
298 }
299 
300 
GetGUID(void) const301 string CMsvcProjectMakefile::GetGUID(void) const
302 {
303     return m_MakeFile.GetString("Common", "ProjectGUID");
304 }
305 
Redefine(const string & value,list<string> & redef) const306 bool CMsvcProjectMakefile::Redefine(const string& value, list<string>& redef) const
307 {
308     redef.clear();
309     if (IsEmpty()) {
310         return false;
311     }
312     string::size_type start, end;
313     if ((start = value.find("$(")) != string::npos &&
314         (end   = value.find(")"))  != string::npos  && (end > start)) {
315         string raw_define = value.substr(start+2,end-start-2);
316         string new_val = m_MakeFile.GetString("Redefine", raw_define);
317         if (!new_val.empty()) {
318             redef.push_back("$(" + new_val + ")");
319             _TRACE(m_FilePath << " redefines:  " << raw_define << " = " << new_val);
320             return true;
321         }
322     } else if (NStr::StartsWith(value, "@") && NStr::EndsWith(value, "@")) {
323         string raw_define = value.substr(1,value.length()-2);
324         string new_val = m_MakeFile.GetString("Redefine", raw_define);
325         if (!new_val.empty()) {
326             redef.push_back("@" + new_val + "@");
327             _TRACE(m_FilePath << " redefines:  " << raw_define << " = " << new_val);
328             return true;
329         }
330     } else {
331         string new_val = m_MakeFile.GetString("Redefine", value);
332         if (!new_val.empty()) {
333             redef.clear();
334             NStr::Split(new_val, LIST_SEPARATOR, redef, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
335             _TRACE(m_FilePath << " redefines:  " << value << " = " << new_val);
336             return true;
337         }
338     }
339     return false;
340 }
341 
Redefine(const list<string> & value,list<string> & redef) const342 bool CMsvcProjectMakefile::Redefine(const list<string>& value, list<string>& redef) const
343 {
344     bool res=false;
345     redef.clear();
346     if (IsEmpty()) {
347         redef.insert(redef.end(),value.begin(), value.end());
348     } else {
349         list<string> newval;
350         ITERATE(list<string>, k, value) {
351             if (Redefine(*k,newval)) {
352                 redef.insert(redef.end(),newval.begin(), newval.end());
353                 res=true;
354             } else {
355                 redef.push_back(*k);
356             }
357         }
358     }
359     return res;
360 }
361 
Append(list<string> & values,const string & def) const362 void CMsvcProjectMakefile::Append( list<string>& values, const string& def) const
363 {
364     if (IsEmpty()) {
365         values.push_back(def);
366     } else {
367         list<string> redef;
368         if (Redefine(def,redef)) {
369             values.insert(values.end(), redef.begin(), redef.end());
370         } else {
371             values.push_back(def);
372         }
373     }
374 }
375 
Append(list<string> & values,const list<string> & def) const376 void CMsvcProjectMakefile::Append( list<string>& values, const list<string>& def) const
377 {
378     if (IsEmpty()) {
379         values.insert(values.end(), def.begin(), def.end());
380     } else {
381         ITERATE(list<string>, k, def) {
382             Append(values,*k);
383         }
384     }
385 }
386 
IsExcludeProject(bool default_val) const387 bool CMsvcProjectMakefile::IsExcludeProject(bool default_val) const
388 {
389     string val = m_MakeFile.GetString("Common", "ExcludeProject");
390 
391     if ( val.empty() )
392         return default_val;
393 
394     return val != "FALSE";
395 }
396 
397 
GetAdditionalSourceFiles(const SConfigInfo & config,list<string> * files) const398 void CMsvcProjectMakefile::GetAdditionalSourceFiles(const SConfigInfo& config,
399                                                     list<string>* files) const
400 {
401     string files_string =
402         GetOpt(m_MakeFile, "AddToProject", "SourceFiles", config);
403 
404     NStr::Split(files_string, LIST_SEPARATOR, *files, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
405 }
406 
407 
GetAdditionalLIB(const SConfigInfo & config,list<string> * lib_ids) const408 void CMsvcProjectMakefile::GetAdditionalLIB(const SConfigInfo& config,
409                                             list<string>*      lib_ids) const
410 {
411     string lib_string =
412         GetOpt(m_MakeFile, "AddToProject", "LIB", config);
413 
414     NStr::Split(lib_string, LIST_SEPARATOR, *lib_ids, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
415 }
416 
417 
GetExcludedSourceFiles(const SConfigInfo & config,list<string> * files) const418 void CMsvcProjectMakefile::GetExcludedSourceFiles(const SConfigInfo& config,
419                                                   list<string>* files) const
420 {
421     string files_string =
422         GetOpt(m_MakeFile,
423                "ExcludedFromProject", "SourceFiles", config);
424 
425     NStr::Split(files_string, LIST_SEPARATOR, *files, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
426 }
427 
428 
GetExcludedLIB(const SConfigInfo & config,list<string> * lib_ids) const429 void CMsvcProjectMakefile::GetExcludedLIB(const SConfigInfo& config,
430                                           list<string>*      lib_ids) const
431 {
432     string lib_string =
433         GetOpt(m_MakeFile,
434                "ExcludedFromProject", "LIB", config);
435 
436     NStr::Split(lib_string, LIST_SEPARATOR, *lib_ids, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
437 }
438 
439 
GetAdditionalIncludeDirs(const SConfigInfo & config,list<string> * dirs) const440 void CMsvcProjectMakefile::GetAdditionalIncludeDirs(const SConfigInfo& config,
441                                                     list<string>* dirs) const
442 {
443     string dirs_string =
444         GetOpt(m_MakeFile, "AddToProject", "IncludeDirs", config);
445 
446     NStr::Split(dirs_string, LIST_SEPARATOR, *dirs, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate | NStr::fSplit_CanQuote);
447 }
448 
GetHeadersInInclude(const SConfigInfo & config,list<string> * files) const449 void CMsvcProjectMakefile::GetHeadersInInclude(const SConfigInfo& config,
450                                                list<string>*  files) const
451 {
452     x_GetHeaders(config, "HeadersInInclude", files);
453 }
454 
GetHeadersInSrc(const SConfigInfo & config,list<string> * files) const455 void CMsvcProjectMakefile::GetHeadersInSrc(const SConfigInfo& config,
456                                            list<string>*  files) const
457 {
458     x_GetHeaders(config, "HeadersInSrc", files);
459 }
460 
x_GetHeaders(const SConfigInfo & config,const string & entry,list<string> * files) const461 void CMsvcProjectMakefile::x_GetHeaders(
462     const SConfigInfo& config, const string& entry, list<string>* files) const
463 {
464     string dirs_string =  GetOpt(m_MakeFile, "AddToProject", entry, config);
465     string separator;
466     separator += CDirEntry::GetPathSeparator();
467     dirs_string = NStr::Replace(dirs_string,"/",separator);
468     dirs_string = NStr::Replace(dirs_string,"\\",separator);
469 
470     files->clear();
471     NStr::Split(dirs_string, LIST_SEPARATOR, *files, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
472     if (files->empty() && !m_Compound) {
473         files->push_back("*.h");
474         files->push_back("*.hpp");
475     }
476 }
477 
GetInlinesInInclude(const SConfigInfo &,list<string> * files) const478 void CMsvcProjectMakefile::GetInlinesInInclude(const SConfigInfo& ,
479                                                list<string>*  files) const
480 {
481     files->clear();
482     files->push_back("*.inl");
483 }
484 
GetInlinesInSrc(const SConfigInfo &,list<string> * files) const485 void CMsvcProjectMakefile::GetInlinesInSrc(const SConfigInfo& ,
486                                            list<string>*  files) const
487 {
488     files->clear();
489     files->push_back("*.inl");
490 }
491 
492 void
GetCustomBuildInfo(list<SCustomBuildInfo> * info) const493 CMsvcProjectMakefile::GetCustomBuildInfo(list<SCustomBuildInfo>* info) const
494 {
495     info->clear();
496 
497     string source_files_str =
498         m_MakeFile.GetString("CustomBuild", "SourceFiles");
499     if (source_files_str.empty()) {
500         return;
501     }
502 
503     list<string> source_files;
504     NStr::Split(source_files_str, LIST_SEPARATOR, source_files, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
505 
506     ITERATE(list<string>, p, source_files){
507         const string& source_file = *p;
508 
509         SCustomBuildInfo build_info;
510         string source_file_path_abs =
511             CDirEntry::ConcatPath(m_MakeFileBaseDir, source_file);
512         build_info.m_SourceFile =
513             CDirEntry::NormalizePath(source_file_path_abs);
514         build_info.m_CommandLine =
515             GetApp().GetSite().ProcessMacros(
516                 m_MakeFile.GetString(source_file, "CommandLine"));
517         build_info.m_Description =
518             m_MakeFile.GetString(source_file, "Description");
519         build_info.m_Outputs =
520             m_MakeFile.GetString(source_file, "Outputs");
521         build_info.m_AdditionalDependencies =
522             GetApp().GetSite().ProcessMacros(
523                 m_MakeFile.GetString(source_file, "AdditionalDependencies"));
524 
525         if ( !build_info.IsEmpty() )
526             info->push_back(build_info);
527     }
528 }
529 
530 void
GetCustomScriptInfo(SCustomScriptInfo & info,const string & sec) const531 CMsvcProjectMakefile::GetCustomScriptInfo(SCustomScriptInfo& info, const string& sec) const
532 {
533     info.m_Input  = m_MakeFile.GetString(sec, "Input");
534     info.m_Output = m_MakeFile.GetString(sec, "Output");
535     info.m_Shell  = m_MakeFile.GetString(sec, "Shell");
536     info.m_Script = m_MakeFile.GetString(sec, "Script");
537 }
538 
539 
GetResourceFiles(const SConfigInfo & config,list<string> * files) const540 void CMsvcProjectMakefile::GetResourceFiles(const SConfigInfo& config,
541                                             list<string>*      files) const
542 {
543     string files_string =
544         GetOpt(m_MakeFile, "AddToProject", "ResourceFiles", config);
545 
546     NStr::Split(files_string, LIST_SEPARATOR, *files, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
547 }
548 
GetExtraFiles(map<string,list<string>> * files_map) const549 void CMsvcProjectMakefile::GetExtraFiles(map<string, list<string> >*  files_map) const
550 {
551     string prefix("ExtraFileGroup.");
552     list<string> sections;
553     m_MakeFile.EnumerateSections(&sections);
554     ITERATE(list<string>, s, sections) {
555         if (NStr::StartsWith(*s,prefix)) {
556             string section(*s);
557             string group_name = NStr::Replace(s->substr(prefix.size()),"_"," ");
558             string files_string = m_MakeFile.Get(section, "Files");
559             list<string> raw_files, files;
560             NStr::Split(files_string, LIST_SEPARATOR, raw_files, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
561             string fname;
562             bool started = false;
563             ITERATE(list<string>, f, raw_files) {
564                 string part(*f);
565                 if (part[0] == '\"' && !started) {
566                     fname = part.substr(1);
567                     started = true;
568                     continue;
569                 }
570                 else if (part[part.size()-1] == '\"') {
571                     fname += ' ';
572                     fname += part.substr(0,part.size()-1);
573                 }
574                 else if (started) {
575                     fname += ' ';
576                     fname += part;
577                     continue;
578                 }
579                 else {
580                     fname = part;
581                 }
582                 files.push_back(fname);
583                 fname.clear();
584                 started = false;
585             }
586             if (!group_name.empty() && !files.empty()) {
587                 (*files_map)[group_name] = files;
588             }
589         }
590     }
591 }
592 
593 //-----------------------------------------------------------------------------
CMsvcProjectRuleMakefile(const string & file_path,bool compound)594 CMsvcProjectRuleMakefile::CMsvcProjectRuleMakefile(const string& file_path, bool compound)
595     :CMsvcProjectMakefile(file_path, compound)
596 {
597 }
598 
599 
GetRulePriority(const SConfigInfo & config) const600 int CMsvcProjectRuleMakefile::GetRulePriority(const SConfigInfo& config) const
601 {
602     string priority_string =
603         GetOpt(m_MakeFile, "Rule", "Priority", config);
604 
605     if ( priority_string.empty() )
606         return 0;
607 
608     return NStr::StringToInt(priority_string);
609 }
610 
611 
612 //-----------------------------------------------------------------------------
s_CreateRuleMakefileFilename(CProjItem::TProjType project_type,const string & requires)613 static string s_CreateRuleMakefileFilename(CProjItem::TProjType project_type,
614                                            const string& requires)
615 {
616     string name = "Makefile." + requires;
617     switch (project_type) {
618     case CProjKey::eApp:
619         name += ".app";
620         break;
621     case CProjKey::eLib:
622         name += ".lib";
623         break;
624     case CProjKey::eDll:
625         name += ".dll";
626         break;
627     default:
628         break;
629     }
630     return name + "." + GetApp().GetRegSettings().m_MakefilesExt;
631 }
632 
CMsvcCombinedProjectMakefile(CProjItem::TProjType project_type,const CMsvcProjectMakefile * project_makefile,const string & rules_basedir,const list<string> requires_list)633 CMsvcCombinedProjectMakefile::CMsvcCombinedProjectMakefile
634                               (CProjItem::TProjType        project_type,
635                                const CMsvcProjectMakefile* project_makefile,
636                                const string&               rules_basedir,
637                                const list<string>          requires_list)
638     :m_ProjectMakefile(project_makefile)
639 {
640     ITERATE(list<string>, p, requires_list) {
641         const string& requires = *p;
642         string rule_path = rules_basedir;
643         rule_path =
644             CDirEntry::ConcatPath(rule_path,
645                                   s_CreateRuleMakefileFilename(project_type,
646                                                                requires));
647 
648         TRule rule(new CMsvcProjectRuleMakefile(rule_path, project_type== CProjKey::eDll));
649         if ( !rule->IsEmpty() )
650             m_Rules.push_back(rule);
651     }
652 }
653 
654 
~CMsvcCombinedProjectMakefile(void)655 CMsvcCombinedProjectMakefile::~CMsvcCombinedProjectMakefile(void)
656 {
657 }
658 
659 #define IMPLEMENT_COMBINED_MAKEFILE_OPT(X)  \
660 string CMsvcCombinedProjectMakefile::X(const string&       opt,               \
661                                          const SConfigInfo&  config) const    \
662 {                                                                             \
663     string prj_val = m_ProjectMakefile->X(opt, config);                       \
664     if ( !prj_val.empty() )                                                   \
665         return prj_val;                                                       \
666     string val;                                                               \
667     int priority = 0;                                                         \
668     ITERATE(TRules, p, m_Rules) {                                             \
669         const TRule& rule = *p;                                               \
670         string rule_val = rule->X(opt, config);                               \
671         if ( !rule_val.empty() && priority < rule->GetRulePriority(config)) { \
672             val      = rule_val;                                              \
673             priority = rule->GetRulePriority(config);                         \
674         }                                                                     \
675     }                                                                         \
676     return val;                                                               \
677 }
678 
679 
680 IMPLEMENT_COMBINED_MAKEFILE_OPT(GetConfigurationOpt)
IMPLEMENT_COMBINED_MAKEFILE_OPT(GetCompilerOpt)681 IMPLEMENT_COMBINED_MAKEFILE_OPT(GetCompilerOpt)
682 IMPLEMENT_COMBINED_MAKEFILE_OPT(GetLinkerOpt)
683 IMPLEMENT_COMBINED_MAKEFILE_OPT(GetLibrarianOpt)
684 IMPLEMENT_COMBINED_MAKEFILE_OPT(GetResourceCompilerOpt)
685 
686 bool CMsvcCombinedProjectMakefile::IsExcludeProject(bool default_val) const
687 {
688     return m_ProjectMakefile->IsExcludeProject(default_val);
689 }
690 
691 
s_ConvertRelativePaths(const string & rule_base_dir,const list<string> & rules_paths_list,const string & project_base_dir,list<string> * project_paths_list)692 static void s_ConvertRelativePaths(const string&       rule_base_dir,
693                                    const list<string>& rules_paths_list,
694                                    const string&       project_base_dir,
695                                    list<string>*       project_paths_list)
696 {
697     project_paths_list->clear();
698     ITERATE(list<string>, p, rules_paths_list) {
699         const string& rules_path = *p;
700         string rules_abs_path =
701             CDirEntry::ConcatPath(rule_base_dir, rules_path);
702         string project_path =
703             CDirEntry::CreateRelativePath(project_base_dir, rules_abs_path);
704         project_paths_list->push_back(project_path);
705     }
706 }
707 
708 
709 #define IMPLEMENT_COMBINED_MAKEFILE_VALUES(X)  \
710 void CMsvcCombinedProjectMakefile::X(const SConfigInfo& config,               \
711                                        list<string>*      values_list) const  \
712 {                                                                             \
713     list<string> prj_val;                                                     \
714     m_ProjectMakefile->X(config, &prj_val);                                   \
715     if ( !prj_val.empty() ) {                                                 \
716         *values_list = prj_val;                                               \
717         return;                                                               \
718     }                                                                         \
719     list<string> val;                                                         \
720     int priority = 0;                                                         \
721     ITERATE(TRules, p, m_Rules) {                                             \
722         const TRule& rule = *p;                                               \
723         list<string> rule_val;                                                \
724         rule->X(config, &rule_val);                                           \
725         if ( !rule_val.empty() && priority < rule->GetRulePriority(config)) { \
726             val      = rule_val;                                              \
727             priority = rule->GetRulePriority(config);                         \
728         }                                                                     \
729     }                                                                         \
730     *values_list = val;                                                       \
731 }
732 
733 
734 #define IMPLEMENT_COMBINED_MAKEFILE_FILESLIST(X)  \
735 void CMsvcCombinedProjectMakefile::X(const SConfigInfo& config,               \
736                                        list<string>*      values_list) const  \
737 {                                                                             \
738     list<string> prj_val;                                                     \
739     m_ProjectMakefile->X(config, &prj_val);                                   \
740     if ( !prj_val.empty() ) {                                                 \
741         *values_list = prj_val;                                               \
742         return;                                                               \
743     }                                                                         \
744     list<string> val;                                                         \
745     int priority = 0;                                                         \
746     string rule_base_dir;                                                     \
747     ITERATE(TRules, p, m_Rules) {                                             \
748         const TRule& rule = *p;                                               \
749         list<string> rule_val;                                                \
750         rule->X(config, &rule_val);                                           \
751         if ( !rule_val.empty() && priority < rule->GetRulePriority(config)) { \
752             val      = rule_val;                                              \
753             priority = rule->GetRulePriority(config);                         \
754             rule_base_dir = rule->m_ProjectBaseDir;                           \
755         }                                                                     \
756     }                                                                         \
757     s_ConvertRelativePaths(rule_base_dir,                                     \
758                            val,                                               \
759                            m_ProjectMakefile->m_ProjectBaseDir,               \
760                            values_list);                                      \
761 }
762 
763 
764 IMPLEMENT_COMBINED_MAKEFILE_FILESLIST(GetAdditionalSourceFiles)
IMPLEMENT_COMBINED_MAKEFILE_VALUES(GetAdditionalLIB)765 IMPLEMENT_COMBINED_MAKEFILE_VALUES   (GetAdditionalLIB)
766 IMPLEMENT_COMBINED_MAKEFILE_FILESLIST(GetExcludedSourceFiles)
767 IMPLEMENT_COMBINED_MAKEFILE_VALUES   (GetExcludedLIB)
768 IMPLEMENT_COMBINED_MAKEFILE_FILESLIST(GetAdditionalIncludeDirs)
769 IMPLEMENT_COMBINED_MAKEFILE_FILESLIST(GetHeadersInInclude)
770 IMPLEMENT_COMBINED_MAKEFILE_FILESLIST(GetHeadersInSrc)
771 IMPLEMENT_COMBINED_MAKEFILE_FILESLIST(GetInlinesInInclude)
772 IMPLEMENT_COMBINED_MAKEFILE_FILESLIST(GetInlinesInSrc)
773 IMPLEMENT_COMBINED_MAKEFILE_FILESLIST(GetResourceFiles)
774 
775 void CMsvcCombinedProjectMakefile::GetExtraFiles(map<string, list<string> >*  files) const
776 {
777    m_ProjectMakefile->GetExtraFiles(files);                                   \
778  }
779 
GetCustomBuildInfo(list<SCustomBuildInfo> * info) const780 void CMsvcCombinedProjectMakefile::GetCustomBuildInfo
781                                            (list<SCustomBuildInfo>* info) const
782 {
783     m_ProjectMakefile->GetCustomBuildInfo(info);
784 }
785 
GetCustomScriptInfo(SCustomScriptInfo & info,const string & section) const786 void CMsvcCombinedProjectMakefile::GetCustomScriptInfo
787                                            (SCustomScriptInfo& info, const string& section) const
788 {
789     m_ProjectMakefile->GetCustomScriptInfo(info, section);
790 }
791 
792 
793 //-----------------------------------------------------------------------------
GetConfigurationOpt(const IMsvcMetaMakefile & meta_file,const IMsvcMetaMakefile & project_file,const string & opt,const SConfigInfo & config)794 string GetConfigurationOpt(const IMsvcMetaMakefile&    meta_file,
795                       const IMsvcMetaMakefile& project_file,
796                       const string&               opt,
797                       const SConfigInfo&          config)
798 {
799     string val = project_file.GetConfigurationOpt(opt, config);
800     if ( val.empty() ) {
801         val = meta_file.GetConfigurationOpt(opt, config);
802     }
803     if (val == "-") {
804         return kEmptyStr;
805     }
806     return val;
807 }
808 
GetCompilerOpt(const IMsvcMetaMakefile & meta_file,const IMsvcMetaMakefile & project_file,const string & opt,const SConfigInfo & config)809 string GetCompilerOpt(const IMsvcMetaMakefile&    meta_file,
810                       const IMsvcMetaMakefile& project_file,
811                       const string&               opt,
812                       const SConfigInfo&          config)
813 {
814     string val = project_file.GetCompilerOpt(opt, config);
815     if ( val.empty() && CMsvc7RegSettings::GetMsvcVersion() < CMsvc7RegSettings::eMsvc1000 ) {
816         val = meta_file.GetCompilerOpt(opt, config);
817     }
818     if (val == "-") {
819         return kEmptyStr;
820     }
821     return val;
822 }
823 
824 
GetLinkerOpt(const IMsvcMetaMakefile & meta_file,const IMsvcMetaMakefile & project_file,const string & opt,const SConfigInfo & config)825 string GetLinkerOpt(const IMsvcMetaMakefile& meta_file,
826                     const IMsvcMetaMakefile& project_file,
827                     const string&            opt,
828                     const SConfigInfo&       config)
829 {
830     string val = project_file.GetLinkerOpt(opt, config);
831     if ( val.empty() && CMsvc7RegSettings::GetMsvcVersion() < CMsvc7RegSettings::eMsvc1000 ) {
832         val = meta_file.GetLinkerOpt(opt, config);
833     }
834     if (val == "-") {
835         return kEmptyStr;
836     }
837     return val;
838 }
839 
840 
GetLibrarianOpt(const IMsvcMetaMakefile & meta_file,const IMsvcMetaMakefile & project_file,const string & opt,const SConfigInfo & config)841 string GetLibrarianOpt(const IMsvcMetaMakefile& meta_file,
842                        const IMsvcMetaMakefile& project_file,
843                        const string&            opt,
844                        const SConfigInfo&       config)
845 {
846     string val = project_file.GetLibrarianOpt(opt, config);
847     if ( val.empty() && CMsvc7RegSettings::GetMsvcVersion() < CMsvc7RegSettings::eMsvc1000 ) {
848         val = meta_file.GetLibrarianOpt(opt, config);
849     }
850     if (val == "-") {
851         return kEmptyStr;
852     }
853     return val;
854 }
855 
GetResourceCompilerOpt(const IMsvcMetaMakefile & meta_file,const IMsvcMetaMakefile & project_file,const string & opt,const SConfigInfo & config)856 string GetResourceCompilerOpt(const IMsvcMetaMakefile& meta_file,
857                               const IMsvcMetaMakefile& project_file,
858                               const string&            opt,
859                               const SConfigInfo&       config)
860 {
861     string val = project_file.GetResourceCompilerOpt(opt, config);
862     if ( val.empty() && CMsvc7RegSettings::GetMsvcVersion() < CMsvc7RegSettings::eMsvc1000 ) {
863         val = meta_file.GetResourceCompilerOpt(opt, config);
864     }
865     if (val == "-") {
866         return kEmptyStr;
867     }
868     return val;
869 }
870 
871 END_NCBI_SCOPE
872