1 /* $Id: msvc_dlls_info.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 "msvc_dlls_info.hpp"
32 #include "proj_builder_app.hpp"
33 #include "msvc_prj_defines.hpp"
34 #include "proj_projects.hpp"
35 #include "proj_tree_builder.hpp"
36 #include "msvc_project_context.hpp"
37 #include "msvc_prj_files_collector.hpp"
38 #include "msvc_dlls_info_utils.hpp"
39 #include "ptb_err_codes.hpp"
40
41 #include <corelib/ncbistre.hpp>
42
43 #include <algorithm>
44
45 BEGIN_NCBI_SCOPE
46
47
48 //-----------------------------------------------------------------------------
FilterOutDllHostedProjects(const CProjectItemsTree & tree_src,CProjectItemsTree * tree_dst)49 void FilterOutDllHostedProjects(const CProjectItemsTree& tree_src,
50 CProjectItemsTree* tree_dst)
51 {
52 tree_dst->m_RootSrc = tree_src.m_RootSrc;
53
54 tree_dst->m_Projects.clear();
55 ITERATE(CProjectItemsTree::TProjects, p, tree_src.m_Projects) {
56
57 const CProjKey& proj_id = p->first;
58 const CProjItem& project = p->second;
59
60 if (proj_id.Type() == CProjKey::eDll) {
61 continue;
62 }
63 bool dll_hosted =
64 (proj_id.Type() == CProjKey::eLib) &&
65 !project.m_DllHost.empty();
66 if ( !dll_hosted) {
67 tree_dst->m_Projects[proj_id] = project;
68 }
69 }
70 }
71
s_IsInTree(CProjKey::TProjType proj_type,const string & proj_id,const CProjectItemsTree * tree)72 static bool s_IsInTree(CProjKey::TProjType proj_type,
73 const string& proj_id,
74 const CProjectItemsTree* tree)
75 {
76 return tree->m_Projects.find
77 (CProjKey(proj_type,
78 proj_id)) !=
79 tree->m_Projects.end();
80 }
81
82
s_InitalizeDllProj(const string & dll_id,CProjItem * dll,const CProjectItemsTree & tree_src,CProjectItemsTree * tree_dst)83 static void s_InitalizeDllProj(const string& dll_id,
84 CProjItem* dll,
85 const CProjectItemsTree& tree_src,
86 CProjectItemsTree* tree_dst)
87 {
88 list<CProjKey> new_depends;
89 ITERATE(list<CProjKey>, p, dll->m_Depends) {
90
91 const string& depend_id = p->Id();
92 const CProjectItemsTree* tree;
93
94 // Is this a dll?
95 if ( s_IsInTree(CProjKey::eDll, depend_id, tree = &tree_src) ||
96 s_IsInTree(CProjKey::eDll, depend_id, tree = &GetApp().GetWholeTree())) {
97 new_depends.push_back(CProjKey(CProjKey::eDll, depend_id));
98 } else {
99 if ( s_IsInTree(CProjKey::eApp, depend_id, tree = &tree_src) ||
100 s_IsInTree(CProjKey::eApp, depend_id, tree = &GetApp().GetWholeTree()) ) {
101
102 CProjKey depend_key(CProjKey::eApp, depend_id);
103 new_depends.push_back(depend_key);
104 tree_dst->m_Projects[depend_key] =
105 (tree->m_Projects.find(depend_key))->second;
106 }
107 else if ( s_IsInTree(CProjKey::eLib, depend_id, tree = &tree_src) ||
108 s_IsInTree(CProjKey::eLib, depend_id, tree = &GetApp().GetWholeTree()) ) {
109
110 string dll_host = tree->m_Projects.find(CProjKey(CProjKey::eLib, depend_id))->second.m_DllHost;
111 if (!dll_host.empty()) {
112 new_depends.push_back(CProjKey(CProjKey::eDll, dll_host));
113 } else {
114 CProjKey depend_key(CProjKey::eLib, depend_id);
115 new_depends.push_back(depend_key);
116 tree_dst->m_Projects[depend_key] =
117 (tree->m_Projects.find(depend_key))->second;
118 }
119
120 } else {
121 if (GetApp().m_AddMissingLibs) {
122 CProjKey depend_key(CProjKey::eLib, depend_id);
123 new_depends.push_back(depend_key);
124 }
125 PTB_WARNING_EX(dll_id, ePTB_MissingDependency,
126 "Missing dependency: " << depend_id);
127 }
128 }
129 }
130 dll->m_Depends = new_depends;
131
132 if (CMsvc7RegSettings::GetMsvcPlatform() < CMsvc7RegSettings::eUnix) {
133 string dll_main = GetApp().GetProjectTreeInfo().m_Compilers;
134 dll_main = CDirEntry::ConcatPath(dll_main, GetApp().GetRegSettings().m_CompilersSubdir);
135 dll_main = CDirEntry::ConcatPath(dll_main, GetApp().GetBuildType().GetTypeStr());
136 dll_main = CDirEntry::ConcatPath(dll_main, "dll_main");
137 dll->m_Sources.push_back(CDirEntry::CreateRelativePath(dll->m_SourcesBaseDir, dll_main));
138 }
139 }
140
141
s_AddProjItemToDll(const CProjectItemsTree & tree_src,const CProjItem & lib,CProjItem & dll)142 static void s_AddProjItemToDll(const CProjectItemsTree& tree_src,
143 const CProjItem& lib, CProjItem& dll)
144 {
145 // If this library is available as a third-party,
146 // then we'll require it
147 if (GetApp().GetSite().GetChoiceForLib(lib.m_ID)
148 == CMsvcSite::e3PartyLib ) {
149 CMsvcSite::SLibChoice choice =
150 GetApp().GetSite().GetLibChoiceForLib(lib.m_ID);
151 dll.m_Requires.push_back(choice.m_3PartyLib);
152 dll.m_Requires.sort();
153 dll.m_Requires.unique();
154 return;
155 }
156 if (!lib.m_External) {
157 dll.m_External = false;
158 }
159 if (lib.m_StyleObjcpp) {
160 dll.m_StyleObjcpp = true;
161 }
162
163 CMsvcPrjProjectContext lib_context(lib);
164 // Define empty configuration list -- to skip configurable file
165 // generation on this step. They will be generated later.
166 const list<SConfigInfo> no_configs;
167 CMsvcPrjFilesCollector collector(lib_context, no_configs, lib);
168
169 // Sources - all pathes are relative to one dll->m_SourcesBaseDir
170 ITERATE(list<string>, p, collector.SourceFiles()) {
171 const string& rel_path = *p;
172 string abs_path =
173 CDirEntry::ConcatPath(lib_context.ProjectDir(), rel_path);
174 abs_path = CDirEntry::NormalizePath(abs_path);
175
176 // Register DLL source files as belongs to lib
177 // With .ext
178 GetApp().GetDllFilesDistr().RegisterSource
179 (abs_path,
180 CProjKey(CProjKey::eDll, dll.m_ID),
181 CProjKey(CProjKey::eLib, lib.m_ID) );
182
183 string dir;
184 string base;
185 CDirEntry::SplitPath(abs_path, &dir, &base);
186 string abs_source_path = dir + base;
187
188 string new_rel_path =
189 CDirEntry::CreateRelativePath(dll.m_SourcesBaseDir,
190 abs_source_path);
191 dll.m_Sources.push_back(new_rel_path);
192 }
193 dll.m_Sources.sort();
194 dll.m_Sources.unique();
195
196 copy(lib_context.IncludeDirsAbs().begin(),
197 lib_context.IncludeDirsAbs().end(), back_inserter(dll.m_Includes));
198 copy(lib_context.InlineDirsAbs().begin(),
199 lib_context.InlineDirsAbs().end(), back_inserter(dll.m_Inlines));
200
201 // Header files - also register them
202 ITERATE(list<string>, p, collector.HeaderFiles()) {
203 const string& rel_path = *p;
204 string abs_path =
205 CDirEntry::ConcatPath(lib_context.ProjectDir(), rel_path);
206 abs_path = CDirEntry::NormalizePath(abs_path);
207 GetApp().GetDllFilesDistr().RegisterHeader
208 (abs_path,
209 CProjKey(CProjKey::eDll, dll.m_ID),
210 CProjKey(CProjKey::eLib, lib.m_ID) );
211 }
212 // Inline files - also register them
213 ITERATE(list<string>, p, collector.InlineFiles()) {
214 const string& rel_path = *p;
215 string abs_path =
216 CDirEntry::ConcatPath(lib_context.ProjectDir(), rel_path);
217 abs_path = CDirEntry::NormalizePath(abs_path);
218 GetApp().GetDllFilesDistr().RegisterInline
219 (abs_path,
220 CProjKey(CProjKey::eDll, dll.m_ID),
221 CProjKey(CProjKey::eLib, lib.m_ID) );
222 }
223
224 if (!collector.GetExtraFiles().empty()) {
225 const map<string, list<string> >& extra(collector.GetExtraFiles());
226 for (map<string, list<string> >::const_iterator g = extra.begin(); g != extra.end(); ++g) {
227 const list<string>& lst(g->second);
228
229 ITERATE(list<string>, f, lst) {
230 string abs_path = CDirEntry::NormalizePath(
231 CDirEntry::ConcatPath(lib_context.ProjectDir(), *f));
232
233 GetApp().GetDllFilesDistr().RegisterExtraFile
234 (abs_path,
235 CProjKey(CProjKey::eDll, dll.m_ID),
236 CProjKey(CProjKey::eLib, lib.m_ID) );
237
238 string new_rel_path =
239 CDirEntry::CreateRelativePath(dll.m_SourcesBaseDir, abs_path);
240 (dll.m_ExtraFiles[g->first]).push_back(new_rel_path);
241 }
242 }
243 }
244 copy(lib_context.GetCustomBuildInfo().begin(),
245 lib_context.GetCustomBuildInfo().end(), back_inserter(dll.m_CustomBuild));
246
247 // Depends
248 ITERATE(list<CProjKey>, p, lib.m_Depends) {
249
250 const CProjKey& depend_id = *p;
251
252 CProjectItemsTree::TProjects::const_iterator i = tree_src.m_Projects.find(depend_id);
253 if (i != tree_src.m_Projects.end()) {
254 if (i->second.m_DllHost.empty()) {
255 dll.m_Depends.push_back(depend_id);
256 } else {
257 dll.m_Depends.push_back(CProjKey(CProjKey::eDll, i->second.m_DllHost));
258 }
259 } else {
260 string host = GetDllHost(tree_src,depend_id.Id());
261 if (!host.empty()) {
262 dll.m_Depends.push_back(CProjKey(CProjKey::eDll, host));
263 }
264 }
265 }
266 dll.m_Depends.sort();
267 dll.m_Depends.unique();
268
269
270 // m_Requires
271 copy(lib.m_Requires.begin(),
272 lib.m_Requires.end(), back_inserter(dll.m_Requires));
273 dll.m_Requires.sort();
274 dll.m_Requires.unique();
275
276 // Libs 3-Party
277 copy(lib.m_Libs3Party.begin(),
278 lib.m_Libs3Party.end(), back_inserter(dll.m_Libs3Party));
279 dll.m_Libs3Party.sort();
280 dll.m_Libs3Party.unique();
281
282 // m_IncludeDirs
283 copy(lib.m_IncludeDirs.begin(),
284 lib.m_IncludeDirs.end(), back_inserter(dll.m_IncludeDirs));
285 dll.m_IncludeDirs.sort();
286 dll.m_IncludeDirs.unique();
287
288 // m_DatatoolSources
289 copy(lib.m_DatatoolSources.begin(),
290 lib.m_DatatoolSources.end(), back_inserter(dll.m_DatatoolSources));
291 dll.m_DatatoolSources.sort();
292 dll.m_DatatoolSources.unique();
293
294 // m_Defines
295 copy(lib.m_Defines.begin(),
296 lib.m_Defines.end(), back_inserter(dll.m_Defines));
297 dll.m_Defines.sort();
298 dll.m_Defines.unique();
299
300 // watchers
301 if (!lib.m_Watchers.empty()) {
302 if (!dll.m_Watchers.empty()) {
303 dll.m_Watchers += " ";
304 }
305 dll.m_Watchers += lib.m_Watchers;
306 }
307 {{
308 string makefile_name =
309 SMakeProjectT::CreateMakeAppLibFileName(lib.m_SourcesBaseDir,
310 lib.m_Name);
311 CSimpleMakeFileContents makefile(makefile_name,eMakeType_Undefined);
312 CSimpleMakeFileContents::TContents::const_iterator p =
313 makefile.m_Contents.find("NCBI_C_LIBS");
314
315 list<string> ncbi_clibs;
316 if (p != makefile.m_Contents.end()) {
317 SAppProjectT::CreateNcbiCToolkitLibs(makefile, &ncbi_clibs);
318
319 dll.m_Libs3Party.push_back("NCBI_C_LIBS");
320 dll.m_Libs3Party.sort();
321 dll.m_Libs3Party.unique();
322
323 copy(ncbi_clibs.begin(),
324 ncbi_clibs.end(),
325 back_inserter(dll.m_NcbiCLibs));
326 dll.m_NcbiCLibs.sort();
327 dll.m_NcbiCLibs.unique();
328
329 }
330 }}
331
332 // m_NcbiCLibs
333 copy(lib.m_NcbiCLibs.begin(),
334 lib.m_NcbiCLibs.end(), back_inserter(dll.m_NcbiCLibs));
335 dll.m_NcbiCLibs.sort();
336 dll.m_NcbiCLibs.unique();
337
338 dll.m_MakeType = max(lib.m_MakeType, dll.m_MakeType);
339 }
340
AnalyzeDllData(CProjectItemsTree & tree)341 void AnalyzeDllData(CProjectItemsTree& tree)
342 {
343 set<string> dll_to_erase;
344 NON_CONST_ITERATE(CProjectItemsTree::TProjects, p, tree.m_Projects) {
345 const CProjKey& key = p->first;
346 CProjItem& project = p->second;
347 if (key.Type() == CProjKey::eDll) {
348 ITERATE( list<string>, h, project.m_HostedLibs) {
349 CProjectItemsTree::TProjects::iterator i;
350 i = tree.m_Projects.find(CProjKey(CProjKey::eLib, *h));
351 if (i != tree.m_Projects.end()) {
352 if (*h != key.Id()) {
353 i->second.m_DllHost = key.Id();
354 i = tree.m_Projects.find(CProjKey(CProjKey::eDll, *h));
355 if (i != tree.m_Projects.end()) {
356 dll_to_erase.insert(*h);
357 }
358 } else if (i->second.m_DllHost.empty()) {
359 i->second.m_DllHost = key.Id();
360 }
361 }
362 }
363 }
364 }
365 ITERATE(set<string>, d, dll_to_erase) {
366 CProjectItemsTree::TProjects::iterator i;
367 i = tree.m_Projects.find(CProjKey(CProjKey::eDll, *d));
368 if (i != tree.m_Projects.end()) {
369 tree.m_Projects.erase(i);
370 }
371 }
372 }
373
GetDllHost(const CProjectItemsTree & tree,const string & lib)374 string GetDllHost(const CProjectItemsTree& tree, const string& lib)
375 {
376 ITERATE(CProjectItemsTree::TProjects, p, tree.m_Projects) {
377 const CProjKey& key = p->first;
378 const CProjItem& project = p->second;
379 if (key.Type() == CProjKey::eDll) {
380 ITERATE( list<string>, h, project.m_HostedLibs) {
381 if (*h == lib) {
382 return key.Id();
383 }
384 }
385 }
386 }
387 return kEmptyStr;
388 }
389
CreateDllBuildTree(const CProjectItemsTree & tree_src,CProjectItemsTree * tree_dst)390 void CreateDllBuildTree(const CProjectItemsTree& tree_src,
391 CProjectItemsTree* tree_dst)
392 {
393 tree_dst->m_RootSrc = tree_src.m_RootSrc;
394
395 FilterOutDllHostedProjects(tree_src, tree_dst);
396
397 list<string> dll_ids;
398 CreateDllsList(tree_src, &dll_ids);
399
400 list<string> dll_depends_ids;
401 CollectDllsDepends(tree_src, dll_ids, &dll_depends_ids);
402 copy(dll_depends_ids.begin(),
403 dll_depends_ids.end(), back_inserter(dll_ids));
404 dll_ids.sort();
405 dll_ids.unique();
406
407 ITERATE(list<string>, p, dll_ids) {
408
409 const string& dll_id = *p;
410 CProjectItemsTree::TProjects::const_iterator d;
411 d = tree_src.m_Projects.find(CProjKey(CProjKey::eDll, dll_id));
412 if (d == tree_src.m_Projects.end()) {
413 d = GetApp().GetWholeTree().m_Projects.find(CProjKey(CProjKey::eDll, dll_id));
414 if (d == GetApp().GetWholeTree().m_Projects.end()) {
415 PTB_ERROR_EX(kEmptyStr, ePTB_ProjectNotFound, "DLL project not found: " << dll_id);
416 continue;
417 }
418 }
419 CProjItem dll( d->second);
420 s_InitalizeDllProj(dll_id, &dll, tree_src, tree_dst);
421
422 CProjectItemsTree::TProjects::const_iterator k;
423 bool is_empty = true;
424 string str_log;
425 ITERATE(list<string>, n, dll.m_HostedLibs) {
426 const string& lib_id = *n;
427 k = tree_src.m_Projects.find(CProjKey(CProjKey::eLib,lib_id));
428 if (k == tree_src.m_Projects.end()) {
429 k = GetApp().GetWholeTree().m_Projects.find(CProjKey(CProjKey::eLib, lib_id));
430 if (k != GetApp().GetWholeTree().m_Projects.end()) {
431 const CProjItem& lib = k->second;
432 s_AddProjItemToDll(tree_src, lib, dll);
433 is_empty = false;
434 } else if (GetApp().GetSite().GetChoiceForLib(lib_id)
435 == CMsvcSite::e3PartyLib ) {
436 CMsvcSite::SLibChoice choice =
437 GetApp().GetSite().GetLibChoiceForLib(lib_id);
438 dll.m_Requires.push_back(choice.m_3PartyLib);
439 dll.m_Requires.sort();
440 dll.m_Requires.unique();
441 } else {
442 str_log += " " + lib_id;
443 }
444 continue;
445 }
446 const CProjItem& lib = k->second;
447 s_AddProjItemToDll(tree_src, lib, dll);
448 is_empty = false;
449 }
450 if ( !is_empty ) {
451 tree_dst->m_Projects[CProjKey(CProjKey::eDll, dll_id)] = dll;
452 if ( !str_log.empty() ) {
453 string path = CDirEntry::ConcatPath(dll.m_SourcesBaseDir, dll_id);
454 path += CMsvc7RegSettings::GetVcprojExt();
455 PTB_WARNING_EX(path, ePTB_ConfigurationError,
456 "Missing libraries not found: " << str_log);
457 }
458 } else {
459 string path = CDirEntry::ConcatPath(dll.m_SourcesBaseDir, dll_id);
460 path += CMsvc7RegSettings::GetVcprojExt();
461 PTB_WARNING_EX(path, ePTB_ProjectExcluded,
462 "Skipped empty project: " << dll_id);
463 }
464 }
465 NON_CONST_ITERATE(CProjectItemsTree::TProjects, p, tree_dst->m_Projects) {
466
467 list<CProjKey> new_depends;
468 CProjItem& project = p->second;
469 ITERATE(list<CProjKey>, n, project.m_Depends) {
470 const CProjKey& depend_id = *n;
471
472 bool found = false;
473 for (int pass=0; !found && pass<2; ++pass) {
474 const CProjectItemsTree& tree = pass ? tree_src : *tree_dst;
475 CProjectItemsTree::TProjects::const_iterator i = tree.m_Projects.find(depend_id);
476 if (i != tree.m_Projects.end()) {
477 if (i->second.m_DllHost.empty()) {
478 new_depends.push_back(depend_id);
479 } else {
480 new_depends.push_back(CProjKey(CProjKey::eDll, i->second.m_DllHost));
481 }
482 found = true;
483 if (pass == 1 && GetApp().m_AddMissingLibs &&
484 i->second.m_MakeType >= eMakeType_Excluded) {
485 copy(i->second.m_Depends.begin(), i->second.m_Depends.end(),
486 back_inserter(new_depends));
487 }
488 } else /* if (!GetApp().m_ScanWholeTree)*/ {
489 ITERATE(CProjectItemsTree::TProjects, d, tree.m_Projects) {
490 const list<string>& lst = d->second.m_HostedLibs;
491 if ( find (lst.begin(), lst.end(), depend_id.Id()) != lst.end()) {
492 new_depends.push_back(d->first);
493 found = true;
494 break;
495 }
496 }
497 }
498 }
499 if (!found) {
500 string path = CDirEntry::ConcatPath(project.m_SourcesBaseDir, project.m_ID);
501 if (!SMakeProjectT::IsConfigurableDefine(depend_id.Id())) {
502 if (GetApp().m_AddMissingLibs) {
503 new_depends.push_back(depend_id);
504 } else {
505 PTB_WARNING_EX(path, ePTB_ProjectNotFound,
506 "Depends on missing project: " << depend_id.Id());
507 }
508 }
509
510 }
511 }
512 new_depends.sort();
513 new_depends.unique();
514 project.m_Depends = new_depends;
515 }
516 }
517
518
CreateDllsList(const CProjectItemsTree & tree_src,list<string> * dll_ids)519 void CreateDllsList(const CProjectItemsTree& tree_src,
520 list<string>* dll_ids)
521 {
522 dll_ids->clear();
523
524 set<string> dll_set;
525
526 ITERATE(CProjectItemsTree::TProjects, p, tree_src.m_Projects) {
527 if ( !p->second.m_DllHost.empty() ) {
528 dll_set.insert(p->second.m_DllHost);
529 }
530 }
531 copy(dll_set.begin(), dll_set.end(), back_inserter(*dll_ids));
532 }
533
534
CollectDllsDepends(const CProjectItemsTree & tree_src,const list<string> & dll_ids,list<string> * dll_depends_ids)535 void CollectDllsDepends(const CProjectItemsTree& tree_src,
536 const list<string>& dll_ids,
537 list<string>* dll_depends_ids)
538 {
539 size_t depends_cnt = dll_depends_ids->size();
540
541 ITERATE(list<string>, p, dll_ids) {
542
543 const string& dll_id = *p;
544 CProjectItemsTree::TProjects::const_iterator i;
545 i = tree_src.m_Projects.find( CProjKey(CProjKey::eDll,dll_id));
546 if (i != tree_src.m_Projects.end()) {
547 ITERATE(list<CProjKey>, n, i->second.m_Depends) {
548 if ( tree_src.m_Projects.find( CProjKey(CProjKey::eDll,n->Id())) !=
549 tree_src.m_Projects.end() &&
550 find(dll_ids.begin(), dll_ids.end(), n->Id()) == dll_ids.end()) {
551 dll_depends_ids->push_back(n->Id());
552 }
553 }
554 }
555 }
556
557 dll_depends_ids->sort();
558 dll_depends_ids->unique();
559 if ( !(dll_depends_ids->size() > depends_cnt) )
560 return;
561
562 list<string> total_dll_ids(dll_ids);
563 copy(dll_depends_ids->begin(),
564 dll_depends_ids->end(), back_inserter(total_dll_ids));
565 total_dll_ids.sort();
566 total_dll_ids.unique();
567
568 CollectDllsDepends(tree_src, total_dll_ids, dll_depends_ids);
569 }
570
571
572 END_NCBI_SCOPE
573