1 /* $Id: msvc_prj_files_collector.cpp 568727 2018-08-09 18:33:41Z 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_prj_files_collector.hpp"
33 #include "msvc_prj_utils.hpp"
34 #include "configurable_file.hpp"
35 #include "ptb_err_codes.hpp"
36 #include "proj_tree_builder.hpp"
37 
38 
39 BEGIN_NCBI_SCOPE
40 
41 
42 static void s_CollectRelPathes(const string&        path_from,
43                                const list<string>&  abs_dirs,
44                                list<string>*        rel_pathes);
45 
46 // sort files by base file name, ignoring path and extension
s_FileName_less(const string & x,const string & y)47 bool s_FileName_less(const string& x, const string& y)
48 {
49     string base_x, base_y;
50     CDirEntry::SplitPath(x, NULL, &base_x);
51     CDirEntry::SplitPath(y, NULL, &base_y);
52     return NStr::CompareNocase(base_x, base_y) < 0;
53 }
54 
55 //-----------------------------------------------------------------------------
56 
CMsvcPrjFilesCollector(const CMsvcPrjProjectContext & project_context,const list<SConfigInfo> & project_configs,const CProjItem & project)57 CMsvcPrjFilesCollector::CMsvcPrjFilesCollector
58                                 (const CMsvcPrjProjectContext& project_context,
59                                  const list<SConfigInfo>&      project_configs,
60                                  const CProjItem&              project)
61     : m_Context(&project_context),
62       m_Configs(&project_configs),
63       m_Project(&project)
64 {
65     CollectSources();
66     CollectHeaders();
67     CollectInlines();
68     CollectResources();
69     CollectExtra();
70 }
71 
72 
~CMsvcPrjFilesCollector(void)73 CMsvcPrjFilesCollector::~CMsvcPrjFilesCollector(void)
74 {
75 }
76 
77 
SourceFiles(void) const78 const list<string>& CMsvcPrjFilesCollector::SourceFiles(void) const
79 {
80     return m_SourceFiles;
81 }
82 
83 
HeaderFiles(void) const84 const list<string>& CMsvcPrjFilesCollector::HeaderFiles(void) const
85 {
86     return m_HeaderFiles;
87 }
88 
89 
InlineFiles(void) const90 const list<string>& CMsvcPrjFilesCollector::InlineFiles(void) const
91 {
92     return m_InlineFiles;
93 }
94 
95 
96 // source files helpers -------------------------------------------------------
97 
ResourceFiles(void) const98 const list<string>& CMsvcPrjFilesCollector::ResourceFiles(void) const
99 {
100     return m_ResourceFiles;
101 }
102 
GetExtraFiles(void) const103 const map<string, list<string> > CMsvcPrjFilesCollector::GetExtraFiles(void) const
104 {
105     return m_ExtraFiles;
106 }
107 
108 struct PSourcesExclude
109 {
PSourcesExcludePSourcesExclude110     PSourcesExclude(const string& prj_id, const list<string>& excluded_sources)
111         : m_Prj(prj_id)
112     {
113         copy(excluded_sources.begin(), excluded_sources.end(),
114              inserter(m_ExcludedSources, m_ExcludedSources.end()) );
115     }
116 
operator ()PSourcesExclude117     bool operator() (const string& src) const
118     {
119         string src_base;
120         CDirEntry::SplitPath(src, NULL, &src_base);
121         if (m_ExcludedSources.find(src_base) != m_ExcludedSources.end()) {
122             PTB_WARNING_EX(src, ePTB_FileExcluded,
123                            "Project " << m_Prj << ": source file excluded");
124             return true;
125         }
126         return false;
127     }
128 
129 private:
130     string m_Prj;
131     set<string> m_ExcludedSources;
132 };
133 
s_IsInsideDatatoolSourceDir(const string & src_path_abs,string & ext)134 static bool s_IsInsideDatatoolSourceDir(const string& src_path_abs, string& ext)
135 {
136     string dir_name;
137     CDirEntry::SplitPath(src_path_abs, &dir_name);
138 
139     //This files must be inside datatool src dir
140     CDir dir(dir_name);
141 //    if ( dir.GetEntries("*.module").empty() )
142 //        return false;
143     if ( !dir.GetEntries("*.asn").empty() ||
144          !dir.GetEntries("*.dtd").empty() ||
145          !dir.GetEntries("*.xsd").empty() ||
146          !dir.GetEntries("*.wsdl").empty() ||
147          !dir.GetEntries("*.jsd").empty()
148         ) {
149         ext = ".cpp";
150         return true;
151     }
152     if (!dir.GetEntries("*.proto").empty()) {
153         ext = ".cc";
154         return true;
155     }
156     return false;
157 }
158 
159 
160 void
CollectSources(void)161 CMsvcPrjFilesCollector::CollectSources(void)
162 {
163     m_SourceFiles.clear();
164 
165     list<string> sources;
166     ITERATE(list<string>, p, m_Project->m_Sources) {
167 
168         const string& src_rel = *p;
169         string src_path =
170             CDirEntry::ConcatPath(m_Project->m_SourcesBaseDir, src_rel);
171         src_path = CDirEntry::NormalizePath(src_path);
172 
173         sources.push_back(src_path);
174     }
175 
176     list<string> included_sources;
177     m_Context->GetMsvcProjectMakefile().GetAdditionalSourceFiles //TODO
178                                             (SConfigInfo(),&included_sources);
179 
180     ITERATE(list<string>, p, included_sources) {
181         string fullpath = CDirEntry::NormalizePath(
182             CDirEntry::ConcatPath(m_Project->m_SourcesBaseDir, *p));
183         string ext = SourceFileExt(fullpath);
184         if (ext.empty() &&
185             CDirEntry::IsAbsolutePath(fullpath) &&
186             !GetApp().GetExtSrcRoot().empty()) {
187             string tpath = CDirEntry::CreateRelativePath( GetApp().m_Root, fullpath);
188             tpath = CDirEntry::ConcatPath(GetApp().GetExtSrcRoot(), tpath);
189             ext = SourceFileExt(tpath);
190             if (!ext.empty()) {
191                 fullpath = tpath;
192             }
193         }
194         sources.push_back(fullpath);
195     }
196 
197     list<string> excluded_sources;
198     m_Context->GetMsvcProjectMakefile().GetExcludedSourceFiles //TODO
199                                             (SConfigInfo(), &excluded_sources);
200     if (!excluded_sources.empty()) {
201         PSourcesExclude pred(m_Project->m_ID, excluded_sources);
202         EraseIf(sources, pred);
203     }
204 
205     ITERATE(list<string>, p, sources) {
206 
207         const string& abs_path = *p; // whithout ext.
208 
209         string ext = SourceFileExt(abs_path);
210         if ( NStr::EndsWith(ext, ".in") ) {
211             // Special case: skip configurable file generation
212             // if configurations was not specified
213             if ( m_Configs->empty() ) {
214                 m_SourceFiles.push_back(
215                     CDirEntry::CreateRelativePath(m_Context->ProjectDir(),
216                                                   abs_path));
217             } else {
218                 // configurable source file
219                 string orig_ext = NStr::Replace(ext, ".in", "");
220                 string dst_path;
221                 CDirEntry::SplitPath(abs_path, NULL, &dst_path, NULL);
222                 dst_path = CDirEntry::MakePath(m_Context->ProjectDir(), dst_path);
223                 GetApp().SetConfFileData(abs_path + ext, dst_path);
224 
225                 // Create configurable file for each enabled configuration
226                 ITERATE(list<SConfigInfo>, p , *m_Configs) {
227                     const SConfigInfo& cfg_info = *p;
228                     string file_dst_path;
229                     file_dst_path = dst_path + "." +
230                                     ConfigurableFileSuffix(cfg_info.GetConfigFullName())+
231                                     orig_ext;
232 #if 0
233                     CreateConfigurableFile(abs_path + ext, file_dst_path,
234                                            cfg_info.GetConfigFullName());
235 #else
236 // we postpone creation until later
237 // here we only create placeholders
238                     if (!CFile(file_dst_path).Exists()) {
239                         CNcbiOfstream os(file_dst_path.c_str(),
240                                          IOS_BASE::out | IOS_BASE::binary | IOS_BASE::trunc);
241                     }
242 #endif
243                 }
244                 dst_path += ".@config@" + orig_ext;
245                 m_SourceFiles.push_back(
246                     CDirEntry::CreateRelativePath(m_Context->ProjectDir(),
247                                                   dst_path));
248                 }
249         }
250         else if ( !ext.empty() ) {
251             // add ext to file
252             string source_file_abs_path = abs_path + ext;
253             string t;
254             try {
255                 t = CDirEntry::CreateRelativePath(
256                     m_Context->ProjectDir(), source_file_abs_path);
257             } catch (CFileException&) {
258                 t = source_file_abs_path;
259             }
260             m_SourceFiles.push_back(t);
261         }
262         else if ( /*IsProducedByDatatool(abs_path, *m_Project) ||*/
263                   s_IsInsideDatatoolSourceDir(abs_path, ext) ) {
264             // .cpp file extension                                                                    ;
265             m_SourceFiles.push_back(
266                 CDirEntry::CreateRelativePath(m_Context->ProjectDir(),
267                                               abs_path + ext));
268         } else {
269             if (m_Project->m_MakeType >= eMakeType_Excluded ||
270                 SMakeProjectT::IsConfigurableDefine(CDirEntry(abs_path).GetBase()) ||
271                 m_Project->HasDataspecDependency()) {
272                 PTB_WARNING_EX(abs_path, ePTB_FileNotFound,
273                             "Source file not found");
274             } else {
275                 PTB_ERROR_EX(abs_path, ePTB_FileNotFound,
276                            "Source file not found");
277             }
278         }
279     }
280     m_SourceFiles.sort(s_FileName_less);
281     m_SourceFiles.unique();
282 }
283 
284 
285 // header files helpers -------------------------------------------------------
286 void
CollectHeaders(void)287 CMsvcPrjFilesCollector::CollectHeaders(void)
288 {
289     m_HeaderFiles.clear();
290     s_CollectRelPathes(m_Context->ProjectDir(), m_Context->IncludeDirsAbs(),
291                        &m_HeaderFiles);
292     m_HeaderFiles.sort(s_FileName_less);
293     m_HeaderFiles.unique();
294 }
295 
296 
297 // inline files helpers -------------------------------------------------------
298 
299 void
CollectInlines(void)300 CMsvcPrjFilesCollector::CollectInlines(void)
301 {
302     m_InlineFiles.clear();
303     s_CollectRelPathes(m_Context->ProjectDir(), m_Context->InlineDirsAbs(),
304                        &m_InlineFiles);
305     m_InlineFiles.sort(s_FileName_less);
306     m_InlineFiles.unique();
307 }
308 
309 
310 // resource files helpers -------------------------------------------------------
311 
312 void
CollectResources(void)313 CMsvcPrjFilesCollector::CollectResources(void)
314 {
315     m_ResourceFiles.clear();
316 
317     // resources from msvc makefile - first priority
318     list<string> included_sources;
319     m_Context->GetMsvcProjectMakefile().GetResourceFiles
320                                             (SConfigInfo(),&included_sources);
321     list<string> sources;
322     ITERATE(list<string>, p, included_sources) {
323         sources.push_back(CDirEntry::NormalizePath
324                                         (CDirEntry::ConcatPath
325                                               (m_Project->m_SourcesBaseDir, *p)));
326     }
327 
328     ITERATE(list<string>, p, sources) {
329 
330         const string& abs_path = *p; // with ext.
331         m_ResourceFiles.push_back(
332             CDirEntry::CreateRelativePath(m_Context->ProjectDir(),
333                                           abs_path));
334     }
335     if ( m_ResourceFiles.empty() ) {
336         // if there is no makefile resources - use defaults
337         string default_rc;
338         if (m_Project->m_ProjType == CProjKey::eApp) {
339             default_rc = GetApp().GetSite().GetAppDefaultResource();
340         }
341         if ( !default_rc.empty() ) {
342             string abs_path = GetApp().GetProjectTreeInfo().m_Compilers;
343             abs_path =
344                 CDirEntry::ConcatPath(abs_path,
345                                     GetApp().GetRegSettings().m_CompilersSubdir);
346             abs_path = CDirEntry::ConcatPath(abs_path, default_rc);
347             abs_path = CDirEntry::NormalizePath(abs_path);
348             m_ResourceFiles.push_back(
349                 CDirEntry::CreateRelativePath(m_Context->ProjectDir(),
350                                             abs_path));
351         }
352     }
353     m_ResourceFiles.sort(s_FileName_less);
354     m_ResourceFiles.unique();
355 }
356 
357 void
CollectExtra(void)358 CMsvcPrjFilesCollector::CollectExtra(void)
359 {
360     m_ExtraFiles.clear();
361 
362     const map<string, list<string> >& extra = m_Project->m_ExtraFiles;
363     for (map<string, list<string> >::const_iterator g = extra.begin(); g != extra.end(); ++g) {
364         const list<string>& lst(g->second);
365         ITERATE( list<string>, f, lst) {
366             m_ExtraFiles[g->first].push_back(
367                 CDirEntry::CreateRelativePath(m_Context->ProjectDir(),
368                     CDirEntry::NormalizePath(CDirEntry::ConcatPath(m_Project->m_SourcesBaseDir, *f))));
369         }
370     }
371 
372     map<string, list<string> > files;
373     m_Context->GetMsvcProjectMakefile().GetExtraFiles(&files);
374     for (map<string, list<string> >::const_iterator g = files.begin(); g != files.end(); ++g) {
375         const list<string>& lst(g->second);
376         ITERATE( list<string>, f, lst) {
377             m_ExtraFiles[g->first].push_back(
378                 CDirEntry::CreateRelativePath(m_Context->ProjectDir(),
379                     CDirEntry::NormalizePath(CDirEntry::ConcatPath(m_Project->m_SourcesBaseDir, *f))));
380         }
381     }
382 }
383 
384 
385 
386 //-----------------------------------------------------------------------------
387 // Collect all files from specified dirs having specified exts
s_CollectRelPathes(const string & path_from,const list<string> & abs_dirs,list<string> * rel_pathes)388 static void s_CollectRelPathes(const string&        path_from,
389                                const list<string>&  abs_dirs,
390                                list<string>*        rel_pathes)
391 {
392     rel_pathes->clear();
393 
394     set<string> toremove;
395     list<string> pathes;
396     ITERATE(list<string>, n, abs_dirs) {
397         string value(*n), pdir, base, ext;
398         if (value.empty()) {
399             continue;
400         }
401 
402         SIZE_TYPE negation_pos = value.find('!');
403         bool remove = negation_pos != NPOS;
404         if (remove) {
405             value = NStr::Replace(value, "!", kEmptyStr);
406             if (value.empty() ||
407                 value[value.length()-1] == CDirEntry::GetPathSeparator()) {
408                 continue;
409             }
410         }
411         CDirEntry::SplitPath(value, &pdir, &base, &ext);
412         CDir dir(pdir);
413         if ( !dir.Exists() )
414             continue;
415         CDir::TEntries contents = dir.GetEntries(base + ext);
416         ITERATE(CDir::TEntries, i, contents) {
417             if ( (*i)->IsFile() ) {
418                 string path  = (*i)->GetPath();
419                 if ( NStr::EndsWith(path, ext, NStr::eNocase) ) {
420                     if (remove) {
421                         toremove.insert(path);
422                     } else {
423                         pathes.push_back(path);
424                     }
425                 }
426             }
427         }
428     }
429     ITERATE(set<string>, r, toremove) {
430         pathes.remove(*r);
431     }
432 
433     ITERATE(list<string>, p, pathes)
434         rel_pathes->push_back(CDirEntry::CreateRelativePath(path_from, *p));
435 }
436 
437 
438 END_NCBI_SCOPE
439