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