1 /* $Id: mac_prj_generator.cpp 600896 2020-01-29 15:48:51Z 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:  Andrei Gourianov
27  *
28  */
29 
30 #include <ncbi_pch.hpp>
31 
32 #include "mac_prj_generator.hpp"
33 
34 #include "proj_builder_app.hpp"
35 #include "msvc_project_context.hpp"
36 #include "proj_tree_builder.hpp"
37 
38 
39 #include "msvc_prj_utils.hpp"
40 #include "msvc_prj_defines.hpp"
41 #include "msvc_prj_files_collector.hpp"
42 #include "ptb_err_codes.hpp"
43 
44 #include <algorithm>
45 
46 #if defined(NCBI_XCODE_BUILD) || defined(PSEUDO_XCODE)
47 #  include <serial/objostrxml.hpp>
48 #  include <serial/serial.hpp>
49 #endif
50 
51 BEGIN_NCBI_SCOPE
52 
53 #if defined(NCBI_XCODE_BUILD) || defined(PSEUDO_XCODE)
54 
55 //
56 // 1 - use human-friendly names (still works with XCode, but generates lots of warnings)
57 // 0 - use XCode-friendly hexadecimal ids
58 #define USE_VERBOSE_NAMES 0
59 
60 /////////////////////////////////////////////////////////////////////////////
61 
62 const char* s_ptb_makecandidate = "__PTB__MAKE__CANDIDATE__";
63 
s_ProjId_less(const CProjItem * x,const CProjItem * y)64 bool s_ProjId_less(const CProjItem* x, const CProjItem* y)
65 {
66     return NStr::CompareNocase(
67         CMacProjectGenerator::GetProjId(*x),
68         CMacProjectGenerator::GetProjId(*y)) < 0;
69 }
70 
s_ProjItem_less(const CProjItem & x,const CProjItem & y)71 bool s_ProjItem_less(const CProjItem& x, const CProjItem& y)
72 {
73     ITERATE( list<CProjKey>, i, x.m_Depends) {
74         if (y.m_ID == i->Id()) {
75             return true;
76         }
77     }
78     return false;
79 }
80 
s_String_less(const CRef<CArray::C_E> & x,const CRef<CArray::C_E> & y)81 bool s_String_less(const CRef<CArray::C_E>& x, const CRef<CArray::C_E>& y)
82 {
83     return NStr::CompareNocase(x->GetString(), y->GetString()) < 0;
84 }
85 
s_Key_less(const CRef<CDict::C_E> & x,const CRef<CDict::C_E> & y)86 bool s_Key_less(const CRef<CDict::C_E>& x, const CRef<CDict::C_E>& y)
87 {
88     return NStr::CompareNocase(x->GetKey(), y->GetKey()) < 0;
89 }
90 
91 
92 /////////////////////////////////////////////////////////////////////////////
93 
CMacProjectGenerator(const list<SConfigInfo> & configs,const CProjectItemsTree & projects_tree)94 CMacProjectGenerator::CMacProjectGenerator(
95     const list<SConfigInfo>& configs, const CProjectItemsTree& projects_tree)
96     :m_Configs(configs), m_Projects_tree(projects_tree)
97 {
98 }
99 
~CMacProjectGenerator(void)100 CMacProjectGenerator::~CMacProjectGenerator(void)
101 {
102 }
103 
Generate(const string & solution)104 void CMacProjectGenerator::Generate(const string& solution)
105 {
106     m_SolutionDir = CDirEntry::IsAbsolutePath(solution) ?
107         solution : CDirEntry::ConcatPath( CDir::GetCwd(), solution);
108     string solution_name = CDirEntry(m_SolutionDir).GetName();
109     m_SolutionDir = CDirEntry(m_SolutionDir).GetDir(CDirEntry::eIfEmptyPath_Empty);
110 
111     m_OutputDir = CDirEntry::AddTrailingPathSeparator(
112         CDirEntry::ConcatPath( CDirEntry::ConcatPath(
113             GetApp().GetProjectTreeInfo().m_Compilers,
114             GetApp().GetRegSettings().m_CompilersSubdir),
115             GetApp().GetBuildType().GetTypeStr()));
116     m_OutputDir = GetRelativePath(m_OutputDir);
117 
118     CRef<CPlist> xproj( new CPlist);
119     CDict& dict_root = xproj->SetPlistObject().SetDict();
120 
121     xproj->SetAttlist().SetVersion("1.0");
122     AddString( dict_root, "archiveVersion", "1");
123     AddDict(   dict_root, "classes");
124 // 39  42  44
125     AddString( dict_root, "objectVersion", GetApp().GetRegSettings().m_Version);
126     CRef<CDict> dict_objects( AddDict( dict_root, "objects"));
127     string configs_root( CreateBuildConfigurations( *dict_objects));
128 
129     CRef<CArray> file_groups( new CArray);
130     CRef<CArray> targets( new CArray);
131     CRef<CArray> all_dependencies( new CArray);
132     CRef<CArray> app_dependencies( new CArray);
133     CRef<CArray> lib_dependencies( new CArray);
134     CRef<CArray> dataspec_dependencies( new CArray);
135     CRef<CArray> products( new CArray);
136     bool add_composite = GetApp().m_ProjTags == "*";
137     vector< CRef<CArray> > composite_dependencies;
138     for (map<string,string>::const_iterator composite = GetApp().m_CompositeProjectTags.begin();
139         composite != GetApp().m_CompositeProjectTags.end(); ++composite) {
140         composite_dependencies.push_back( CRef<CArray>(new CArray) );
141     }
142 
143 
144 #if USE_VERBOSE_NAMES
145     string root_name("ROOT_OBJECT");
146 #else
147     string root_name( GetUUID());
148 #endif
149     // set GUIDs
150     list<const CProjItem*> all_projects;
151     ITERATE(CProjectItemsTree::TProjects, p, m_Projects_tree.m_Projects) {
152         const CProjItem& prj(p->second);
153         prj.m_GUID = GetUUID();
154         all_projects.push_back(&prj);
155     }
156     all_projects.sort(s_ProjId_less);
157 
158     // generate product IDs
159     m_TargetProduct.clear();
160     ITERATE(list<const CProjItem*>, p, all_projects) {
161         const CProjItem& prj(**p);
162         string target_id(GetProjId(prj));
163         m_TargetProduct[target_id] = GetUUID();
164     }
165     // generate targets
166     ITERATE(list<const CProjItem*>, p, all_projects) {
167         const CProjItem& prj(**p);
168 
169 #if USE_VERBOSE_NAMES
170         string proj_dependency(GetProjDependency(prj));
171         string proj_container( GetProjContainer(prj));
172 #else
173         string proj_dependency(prj.m_GUID);
174         string proj_container( GetUUID());
175 #endif
176         string explicit_type( GetExplicitType( prj));
177         string target_name(GetTargetName(prj));
178         string target_id(GetProjId(prj));
179 
180         CProjectFileCollector prj_files( prj, m_Configs, m_SolutionDir+m_OutputDir);
181         if (!prj_files.CheckProjectConfigs()) {
182             continue;
183         }
184         if (prj.m_MakeType == eMakeType_ExcludedByReq) {
185             PTB_WARNING_EX(prj.m_ID, ePTB_ProjectExcluded,
186                            "Excluded due to unmet requirements");
187             continue;
188         }
189 // see CXX-542
190         bool excluded = (prj.m_MakeType >= eMakeType_Expendable);
191 //        bool excluded = (prj.m_MakeType > eMakeType_Expendable);
192 
193         prj_files.DoCollect();
194         if (!excluded) {
195             if (prj.m_ProjType == CProjKey::eLib || prj.m_ProjType == CProjKey::eDll) {
196                 AddString( *lib_dependencies, proj_dependency);
197 //            } else if (prj.m_ProjType == CProjKey::eApp) {
198 //                AddString( *app_dependencies, proj_dependency);
199 //            } else if (prj.m_ProjType == CProjKey::eDataSpec) {
200             }
201             if (!prj.m_DatatoolSources.empty()) {
202                 AddString( *dataspec_dependencies, proj_dependency);
203             }
204             if (prj.m_ProjType != CProjKey::eLib && prj.m_ProjType != CProjKey::eDll &&
205                 prj.m_ProjType != CProjKey::eApp && //prj.m_ProjType != CProjKey::eDataSpec &&
206                 prj.m_ProjType != CProjKey::eMsvc) {
207                 continue;
208             }
209             if (add_composite) {
210                 int c = 0;
211                 for (map<string,string>::const_iterator composite = GetApp().m_CompositeProjectTags.begin();
212                     composite != GetApp().m_CompositeProjectTags.end(); ++composite, ++c) {
213 
214                     if (GetApp().IsAllowedProjectTag(prj, &composite->second)) {
215                         AddString( *(composite_dependencies[c]), proj_dependency);
216                     }
217                 }
218             }
219             AddString( *all_dependencies, proj_dependency);
220         }
221 
222         if (prj.m_ProjType == CProjKey::eApp) {
223             string app_type = prj_files.GetProjectContext().GetMsvcProjectMakefile().GetLinkerOpt("APP_TYPE",SConfigInfo());
224             if (app_type == "application") {
225                 prj.m_IsBundle = true;
226                 explicit_type = GetExplicitType( prj);
227             }
228         }
229 
230         CRef<CArray> build_phases( new CArray);
231         CRef<CArray> build_files( new CArray);
232 
233         // project file groups
234         AddString( *file_groups,
235             CreateProjectFileGroups(prj, prj_files, *dict_objects, *build_files));
236 
237         // project custom script phase
238         string proj_prebuild_script(
239             CreateProjectCustomScriptPhase(prj, prj_files, *dict_objects, "PreBuild"));
240         if (!proj_prebuild_script.empty()) {
241             AddString( *build_phases, proj_prebuild_script);
242         }
243         // project script phase
244         string proj_script(
245             CreateProjectScriptPhase(prj, prj_files, *dict_objects));
246         if (!proj_script.empty()) {
247             AddString( *build_phases, proj_script);
248         }
249         // project build phase
250         string proj_build(
251             CreateProjectBuildPhase(prj, *dict_objects, build_files));
252         if (!proj_build.empty()) {
253             AddString( *build_phases, proj_build);
254         }
255         // project custom script phase
256         string proj_cust_script(
257             CreateProjectCustomScriptPhase(prj, prj_files, *dict_objects, "CustomScript"));
258         if (!proj_cust_script.empty()) {
259             AddString( *build_phases, proj_cust_script);
260         }
261         // link binary with libraries phase
262         string proj_link(
263             CreateProjectLinkPhase(prj, prj_files, *dict_objects));
264         if (!proj_link.empty()) {
265             AddString( *build_phases, proj_link);
266         }
267         // project copybin script phase
268         string proj_copybin_script(
269             CreateProjectCopyBinScript(prj, prj_files, *dict_objects));
270         if (!proj_copybin_script.empty()) {
271             AddString( *build_phases, proj_copybin_script);
272         }
273         // project target and dependencies
274         string proj_product( m_TargetProduct[target_id] );
275         string proj_target(
276             CreateProjectTarget( prj, prj_files, *dict_objects, build_phases,
277                                  proj_product));
278         if (!proj_target.empty()) {
279             AddString( *targets, proj_target);
280         }
281 
282         // project dependency key
283         {
284             CRef<CDict> dict_dep( AddDict( *dict_objects, proj_dependency));
285             AddString( *dict_dep, "isa", "PBXTargetDependency");
286             AddString( *dict_dep, "target", proj_target);
287             AddString( *dict_dep, "targetProxy", proj_container);
288         }
289         // project container
290         {
291             CRef<CDict> dict_con( AddDict( *dict_objects, proj_container));
292             AddString( *dict_con, "containerPortal", root_name);
293             AddString( *dict_con, "isa", "PBXContainerItemProxy");
294             AddString( *dict_con, "proxyType", "1");
295             AddString( *dict_con, "remoteGlobalIDString", proj_target);
296             AddString( *dict_con, "remoteInfo", target_name);
297         }
298         // project product
299         if (!explicit_type.empty()) {
300             AddString( *products, proj_product);
301             CRef<CDict> dict_product( AddDict( *dict_objects, proj_product));
302             AddString( *dict_product, "explicitFileType", explicit_type);
303             AddString( *dict_product, "includeInIndex", "0");
304             AddString( *dict_product, "isa", "PBXFileReference");
305             if (prj.m_ProjType == CProjKey::eDll) {
306                 AddString( *dict_product, "path", string("lib") + prj.m_ID + string(".dylib"));
307             } else if (prj.m_ProjType == CProjKey::eApp) {
308                 AddString( *dict_product, "path", prj.m_ID);
309             } else if (prj.m_ProjType == CProjKey::eLib) {
310                 if (prj.m_IsMetallib) {
311                     AddString( *dict_product, "path", prj.m_ID + string(".metallib"));
312                 } else {
313                     AddString( *dict_product, "path", string("lib") + prj.m_ID + string(".a"));
314                 }
315             }
316             AddString( *dict_product, "sourceTree", "BUILT_PRODUCTS_DIR");
317         }
318         // watchers
319         GetApp().RegisterProjectWatcher( target_name, prj.m_SourcesBaseDir, prj.m_Watchers);
320     }
321 
322 // collect file groups
323 #if USE_VERBOSE_NAMES
324     string source_files("Source_Files");
325     string root_group("Main_Group");
326     string products_group("Products_Group");
327 #else
328     string source_files(   GetUUID());
329     string root_group(     GetUUID());
330     string products_group( GetUUID());
331 #endif
332 
333     file_groups->Set().sort(s_String_less);
334     AddGroupDict( *dict_objects, source_files, file_groups, "Sources");
335     AddGroupDict( *dict_objects, products_group, products, "Products");
336     CRef<CArray> main_groups( new CArray);
337     AddString( *main_groups, source_files);
338     AddString( *main_groups, products_group);
339     AddGroupDict( *dict_objects, root_group, main_groups, "NCBI C++ Toolkit");
340 
341     targets->Set().sort(s_String_less);
342     dataspec_dependencies->Set().sort(s_String_less);
343     lib_dependencies->Set().sort(s_String_less);
344 //    app_dependencies->Set().sort(s_String_less);
345     all_dependencies->Set().sort(s_String_less);
346     if (add_composite) {
347         int c = 0;
348         for (map<string,string>::const_iterator composite = GetApp().m_CompositeProjectTags.begin();
349             composite != GetApp().m_CompositeProjectTags.end(); ++composite, ++c) {
350 
351             if (!composite_dependencies[c]->Get().empty()) {
352                 composite_dependencies[c]->Set().sort(s_String_less);
353                 InsertString( *targets,
354                     AddAggregateTarget("_TAG_" + composite->first, *dict_objects, composite_dependencies[c]));
355             }
356         }
357     }
358 // aggregate targets
359     string preconf_dependency(AddPreConfigureTarget(*targets,*dict_objects, root_name));
360     InsertString( *targets,
361         AddConfigureTarget(solution_name,  *dict_objects, true, preconf_dependency));
362     InsertString( *targets,
363         AddConfigureTarget(solution_name,  *dict_objects, false, preconf_dependency));
364     InsertString( *targets,
365         AddAggregateTarget("DATASPEC_ALL", *dict_objects, dataspec_dependencies));
366     InsertString( *targets,
367         AddAggregateTarget("LIBS_ALL", *dict_objects, lib_dependencies));
368 //    InsertString( *targets,
369 //        AddAggregateTarget("BUILD_APPS", *dict_objects, app_dependencies));
370     InsertString( *targets,
371         AddAggregateTarget("BUILD_ALL",  *dict_objects, all_dependencies));
372 
373 // root object
374     AddString( dict_root, "rootObject",
375         CreateRootObject(configs_root, *dict_objects, targets,
376             root_group, root_name, products_group));
377 
378 #if !USE_VERBOSE_NAMES
379     dict_objects->Set().sort(s_Key_less);
380 #endif
381 
382 // save project
383     Save(solution_name, *xproj);
384 }
385 
Save(const string & solution_name,CPlist & xproj)386 void CMacProjectGenerator::Save(const string& solution_name, CPlist& xproj)
387 {
388     bool make_candidate = !GetApp().GetEnvironment().Get(s_ptb_makecandidate).empty();
389     string solution_dir(m_SolutionDir);
390     solution_dir = CDirEntry::ConcatPath(solution_dir, solution_name);
391     solution_dir += ".xcodeproj";
392     CDir(solution_dir).CreatePath();
393     string solution_file( CDirEntry::ConcatPath(solution_dir, "project.pbxproj"));
394     GetApp().RegisterGeneratedFile( solution_file );
395     if (make_candidate) {
396         solution_file += ".candidate";
397     }
398     {
399         unique_ptr<CObjectOStream> out(CObjectOStream::Open(solution_file, eSerial_Xml));
400         CObjectOStreamXml *ox = dynamic_cast<CObjectOStreamXml*>(out.get());
401         ox->SetReferenceDTD(true);
402         ox->SetDTDPublicId("-//Apple//DTD PLIST 1.0//EN");
403         ox->SetDTDFilePrefix("http://www.apple.com/DTDs/");
404         ox->SetDTDFileName("PropertyList-1.0");
405         ox->SetEncoding(eEncoding_UTF8);
406         *out << xproj;
407     }
408     CreateConfigureScript(solution_name, false);
409     CreateConfigureScript(solution_name, true);
410 }
411 
CreateConfigureScript(const string & name,bool with_gui) const412 void CMacProjectGenerator::CreateConfigureScript(const string& name, bool with_gui) const
413 {
414     string script = CDirEntry::ConcatPath(m_SolutionDir,"UtilityProjects/configure_");
415     if (with_gui) {
416         script += "gui_";
417     }
418     script += name + ".sh";
419     string candidate = script + ".candidate";
420 
421     CNcbiOfstream  ofs(candidate.c_str(), IOS_BASE::out | IOS_BASE::trunc);
422     if ( !ofs )
423         NCBI_THROW(CProjBulderAppException, eFileCreation, script);
424 
425     GetApp().RegisterGeneratedFile( script );
426     ofs << "#!/bin/sh\n";
427     ofs << "export PTB_FLAGS=\"";
428     if ( GetApp().GetBuildType().GetType() == CBuildType::eDll )
429         ofs << " -dll";
430     if (!GetApp().m_BuildPtb) {
431         ofs << " -nobuildptb";
432     }
433     if (GetApp().m_Dtdep) {
434         ofs << " -dtdep";
435     }
436     if (!GetApp().m_AddMissingDep) {
437         ofs << " -noadddep";
438     }
439     ofs << " -libdep " << (GetApp().m_LibDep ? "true" : "false");
440     if (GetApp().m_AddMissingLibs) {
441         ofs << " -ext";
442     }
443     if (!GetApp().m_ScanWholeTree) {
444         ofs << " -nws";
445     }
446     if (!GetApp().m_BuildRoot.empty()) {
447         ofs << " -extroot \"" << GetApp().m_BuildRoot << "\"";
448     }
449     if (with_gui /*|| GetApp().m_ConfirmCfg*/) {
450         ofs << " -cfg";
451     }
452     if (GetApp().m_ProjTagCmnd) {
453         if (GetApp().m_ProjTags != "*") {
454             ofs << " -projtag \\\"" << GetApp().m_ProjTags << "\\\"";
455         } else {
456             ofs << " -projtag #";
457         }
458     }
459     ofs << "\"\n";
460     ofs << "export PTB_PROJECT_REQ=" << GetApp().m_Subtree << "\n";
461     ofs << "$BUILD_TREE_ROOT/ptb.sh\n";
462     ofs.close();
463     PromoteIfDifferent(script, candidate);
464     CDirEntry(script).SetMode(
465         CDirEntry::fExecute | CDirEntry::fRead | CDirEntry::fWrite,
466         CDirEntry::fExecute | CDirEntry::fRead | CDirEntry::fWrite,
467         CDirEntry::fExecute | CDirEntry::fRead | CDirEntry::fWrite);
468 }
469 
CreateProjectFileGroups(const CProjItem & prj,const CProjectFileCollector & prj_files,CDict & dict_objects,CArray & build_files)470 string CMacProjectGenerator::CreateProjectFileGroups(
471     const CProjItem& prj, const CProjectFileCollector& prj_files,
472     CDict& dict_objects, CArray& build_files)
473 {
474     CDllSrcFilesDistr& dll_src( GetApp().GetDllFilesDistr());
475     CProjKey proj_key(prj.m_ProjType, prj.m_ID);
476 
477     string proj_id(        GetProjId( prj) );
478 #if USE_VERBOSE_NAMES
479     string proj_src(       proj_id + "_src");
480     string proj_include(   proj_id + "_include");
481     string proj_specs(     proj_id + "_specs");
482     string src_group_name( proj_id + "_sources");
483 #else
484     string proj_src(       GetUUID());
485     string proj_include(   GetUUID());
486     string proj_specs(     GetUUID());
487     string src_group_name( GetUUID());
488 #endif
489 
490     CRef<CArray> proj_cpps(  new CArray);
491     CRef<CArray> proj_hpps(  new CArray);
492     CRef<CArray> specs( new CArray);
493 
494     map<string, CRef<CArray> > hosted_cpps;
495     map<string, CRef<CArray> > hosted_hpps;
496     map<string, CRef<CArray> > hosted_srcs;
497     ITERATE( list<string>, hosted_lib, prj.m_HostedLibs) {
498         hosted_cpps[ *hosted_lib] = new CArray;
499         hosted_hpps[ *hosted_lib] = new CArray;
500         hosted_srcs[ *hosted_lib] = new CArray;
501     }
502 
503     // for each source file in project
504     ITERATE ( list<string>, f, prj_files.GetSources()) {
505         string src( AddFile( dict_objects, *f, prj.m_StyleObjcpp));
506         if (!src.empty()) {
507             bool added=false;
508             if (prj.m_ProjType == CProjKey::eDll) {
509                 CProjKey hosted_key = dll_src.GetSourceLib( *f, proj_key);
510                 if (!hosted_key.Id().empty()) {
511                     AddString( *hosted_cpps[ hosted_key.Id() ], src);
512                     added = true;
513                 }
514             }
515             if (!added) {
516                 AddString( *proj_cpps, src);
517             }
518             AddString( build_files, AddFileSource( dict_objects, src));
519         }
520     }
521     // for each header file in project
522     ITERATE ( list<string>, f, prj_files.GetHeaders()) {
523         string src( AddFile( dict_objects, *f, prj.m_StyleObjcpp));
524         if (!src.empty()) {
525             bool added=false;
526             if (prj.m_ProjType == CProjKey::eDll) {
527                 CProjKey hosted_key = dll_src.GetHeaderLib( *f, proj_key);
528                 if (!hosted_key.Id().empty()) {
529                     AddString( *hosted_hpps[ hosted_key.Id() ], src);
530                     added = true;
531                 } else {
532                     CProjKey hosted_inl = dll_src.GetInlineLib( *f, proj_key);
533                     if (!hosted_inl.Id().empty()) {
534                         AddString( *hosted_hpps[ hosted_inl.Id() ], src);
535                         added = true;
536                     }
537                 }
538             }
539             if (!added) {
540                 AddString( *proj_hpps, src);
541             }
542         }
543     }
544     // dataspecs
545     ITERATE ( list<string>, f, prj_files.GetDataSpecs()) {
546         string src( AddFile( dict_objects, *f, prj.m_StyleObjcpp));
547         if (!src.empty()) {
548             AddString( *specs,src);
549         }
550     }
551 
552     string source_files(  "Source Files");
553     string header_files(  "Header Files");
554     string datatool_files("Datatool Files");
555     CRef<CArray> prj_sources( new CArray);
556     ITERATE( list<string>, hosted_lib, prj.m_HostedLibs) {
557         CRef<CArray>& cpps = hosted_cpps[ *hosted_lib];
558         CRef<CArray>& hpps = hosted_hpps[ *hosted_lib];
559         CRef<CArray>& srcs = hosted_srcs[ *hosted_lib];
560 #if USE_VERBOSE_NAMES
561         string hosted_src(   *hosted_lib + "_hosted_src");
562         string hosted_inc(   *hosted_lib + "_hosted_include");
563         string hosted_group( *hosted_lib + "_hosted_sources");
564 #else
565         string hosted_src(   GetUUID());
566         string hosted_inc(   GetUUID());
567         string hosted_group( GetUUID());
568 #endif
569         if (!cpps->Get().empty()) {
570             cpps->Set().sort(s_String_less);
571             AddString( *srcs, hosted_src);
572             AddGroupDict( dict_objects, hosted_src, cpps, source_files);
573         }
574         if (!hpps->Get().empty()) {
575             hpps->Set().sort(s_String_less);
576             AddString( *srcs, hosted_inc);
577             AddGroupDict( dict_objects, hosted_inc, hpps, header_files);
578         }
579         AddGroupDict( dict_objects, hosted_group, srcs, *hosted_lib);
580         AddString( *prj_sources, hosted_group);
581     }
582     if (!prj.m_HostedLibs.empty()) {
583         prj_sources->Set().sort(s_String_less);
584     }
585     if (!proj_cpps->Get().empty()) {
586         proj_cpps->Set().sort(s_String_less);
587         AddString( *prj_sources, proj_src);
588         AddGroupDict( dict_objects, proj_src,     proj_cpps, source_files);
589     }
590     if (!proj_hpps->Get().empty()) {
591         proj_hpps->Set().sort(s_String_less);
592         AddString( *prj_sources, proj_include);
593         AddGroupDict( dict_objects, proj_include, proj_hpps, header_files);
594     }
595     if (!specs->Get().empty()) {
596         AddString( *prj_sources, proj_specs);
597         AddGroupDict( dict_objects, proj_specs,   specs, datatool_files);
598     }
599     AddGroupDict( dict_objects, src_group_name, prj_sources, GetTargetName(prj));
600     return src_group_name;
601 }
602 
CreateProjectScriptPhase(const CProjItem & prj,const CProjectFileCollector & prj_files,CDict & dict_objects)603 string CMacProjectGenerator::CreateProjectScriptPhase(
604     const CProjItem& prj, const CProjectFileCollector& prj_files,
605     CDict& dict_objects)
606 {
607     string script;
608     CRef<CArray> inputs(  new CArray);
609     CRef<CArray> outputs( new CArray);
610     ITERATE( list<CProjKey>, p, prj_files.GetProjectContext().PreBuilds()) {
611         const CProjKey& proj_key = *p;
612         if (m_Projects_tree.m_Projects.find(proj_key) ==
613             m_Projects_tree.m_Projects.end()) {
614             PTB_WARNING_EX(
615                 CDirEntry::ConcatPath(prj.m_SourcesBaseDir, CreateProjectName(CProjKey(prj.m_ProjType, prj.m_ID))),
616                 ePTB_ProjectNotFound, " depends on missing project: " << proj_key.Id());
617             if (!SMakeProjectT::IsConfigurableDefine(proj_key.Id())) {
618                 script += "echo ERROR: this project depends on missing " + CreateProjectName(proj_key);
619                 script += "\nexit 1\n";
620             }
621         }
622     }
623     // configurable files
624     ITERATE ( list<string>, f, prj_files.GetConfigurableSources()) {
625         string outfile(GetRelativePath( *f));
626 //        AddString( *outputs, outfile);
627         CDirEntry ent(outfile);
628         string infile(CDirEntry::ConcatPath( ent.GetDir(), ent.GetBase()));
629         infile += ".$CONFIGURATION";
630         infile += ent.GetExt();
631         script += "cmp -s " + infile + " " + outfile + "\n";
632         script += "if test $? -ne 0; then\n";
633         script += "cp -p " + infile + " " + outfile + "\n";
634         script += "fi\n";
635         AddString( *outputs, outfile);
636     }
637     // datatool
638     if (!prj.m_DatatoolSources.empty()) {
639 #if 0
640         ITERATE ( list<string>, f, prj_files.GetSources()) {
641             if (prj_files.IsProducedByDatatool(prj,*f)) {
642                 string outfile(GetRelativePath( *f));
643                 AddString( *outputs, outfile);
644             }
645         }
646 #endif
647         string pch_name = GetApp().GetMetaMakefile().GetDefaultPch();
648         bool dataspec_first = true;
649         ITERATE ( list<string>, f, prj_files.GetDataSpecs()) {
650             CDirEntry entry(*f);
651             string spec_base( CDirEntry(GetRelativePath(*f)).GetDir() + entry.GetBase());
652             string spec_ext = entry.GetExt();
653             AddString( *inputs, GetRelativePath(*f));
654             if (spec_ext == ".proto") {
655                 AddString( *outputs, spec_base + ".pb.cc");
656                 AddString( *outputs, spec_base + ".grpc.pb.cc");
657             } else {
658                 AddString( *inputs, spec_base + ".def");
659                 AddString( *outputs, spec_base + ".files");
660                 AddString( *outputs, spec_base + "__.cpp");
661                 AddString( *outputs, spec_base + "___.cpp");
662                 {
663                     string deffile(spec_base + ".def");
664                     if (CFile(deffile).Exists()) {
665                         CPtbRegistry reg;
666                         CNcbiIfstream ifs(deffile.c_str());
667                         reg.Read(ifs);
668                         string clients = reg.GetString("-", "clients");
669                         if (!clients.empty()) {
670                             string clients_base = CDirEntry(GetRelativePath(*f)).GetDir() + clients;
671                             AddString( *outputs, clients_base + ".cpp");
672                             AddString( *outputs, clients_base + "_.cpp");
673                         }
674                     }
675                 }
676             }
677 #if 0
678             script += "echo Generating C++ classes from " + entry.GetName() + "\n";
679             script += m_OutputDir + GetApp().GetDatatoolPathForApp();
680 #else
681             if (dataspec_first) {
682                 script += "export PTB_PLATFORM=\"$ARCHS\"\n";
683                 if (spec_ext == ".proto") {
684                     script += "export GENERATOR_PATH=" + GetApp().GetSite().GetConfigureEntry("XCode_CustomCodeGenerator" + spec_ext) + "\n";
685                     script += "export PROJECT_REQUIRES=" + NStr::Join(prj.m_Requires,";") + "\n";
686                 } else {
687                     script += "export DATATOOL_PATH=" + m_OutputDir + "../static/bin/ReleaseDLL\n";
688                 }
689                 script += "export TREE_ROOT=" +
690                     CDirEntry::DeleteTrailingPathSeparator( GetRelativePath( GetApp().m_Root)) + "\n";
691                 script += "export BUILD_TREE_ROOT=" +
692                     CDirEntry::DeleteTrailingPathSeparator( GetRelativePath(
693                     CDirEntry::AddTrailingPathSeparator( CDirEntry::ConcatPath(
694                         GetApp().GetProjectTreeInfo().m_Compilers,
695                         GetApp().GetRegSettings().m_CompilersSubdir)))) + "\n";
696                 dataspec_first = false;
697             }
698             if (spec_ext == ".proto") {
699                 script +=  "\"$BUILD_TREE_ROOT/protoc.sh\"";
700             } else {
701                 script +=  "\"$BUILD_TREE_ROOT/datatool.sh\"";
702             }
703 #endif
704             script += " " + GetApp().GetDatatoolCommandLine() + " -pch " + pch_name;
705             script += " -m " + GetRelativePath( entry.GetPath(), &GetApp().GetProjectTreeInfo().m_Src);
706             string imports( prj_files.GetDataSpecImports(*f));
707             if (!imports.empty()) {
708 #ifdef PSEUDO_XCODE
709                 NStr::ReplaceInPlace(imports, "\\", "/");
710 #endif
711                 script += " -M \"" + imports + "\"";
712             }
713             script += " -oc " + entry.GetBase();
714             script += " -od " + spec_base + ".def";
715             script += " -or " + GetRelativePath( entry.GetDir(), &GetApp().GetProjectTreeInfo().m_Src);
716             script += " -oR " + GetRelativePath( GetApp().GetProjectTreeInfo().m_Root) + "\n";
717         }
718     }
719     if (!script.empty()) {
720 #if USE_VERBOSE_NAMES
721         string proj_script(   GetProjId(       prj) + "_script");
722 #else
723         string proj_script(   GetUUID());
724 #endif
725         CRef<CDict> dict_script( AddDict( dict_objects, proj_script));
726         AddArray(  *dict_script, "files");
727         AddArray(  *dict_script, "inputPaths",  inputs);
728         AddArray(  *dict_script, "outputPaths", outputs);
729         AddString( *dict_script, "isa", "PBXShellScriptBuildPhase");
730         AddString( *dict_script, "shellPath", "/bin/sh");
731         AddString( *dict_script, "shellScript", script);
732         AddString( *dict_script, "showEnvVarsInLog", "0");
733         return proj_script;
734     }
735     return kEmptyStr;
736 }
737 
CreateProjectCustomScriptPhase(const CProjItem & prj,const CProjectFileCollector & prj_files,CDict & dict_objects,const string & section)738 string CMacProjectGenerator::CreateProjectCustomScriptPhase(
739     const CProjItem& prj, const CProjectFileCollector& prj_files,
740     CDict& dict_objects, const string& section)
741 {
742     SCustomScriptInfo info;
743     prj_files.GetProjectContext().GetMsvcProjectMakefile().GetCustomScriptInfo(info, section);
744 
745     if (!info.m_Script.empty()) {
746 #if USE_VERBOSE_NAMES
747         string proj_script(   GetProjId(       prj) + section);
748 #else
749         string proj_script(   GetUUID());
750 #endif
751         CRef<CDict> dict_script( AddDict( dict_objects, proj_script));
752         string script_loc( prj.m_SourcesBaseDir);
753 
754         CRef<CArray> inputs(  new CArray);
755         CRef<CArray> outputs( new CArray);
756         list<string> in_list;
757         NStr::Split(info.m_Input, LIST_SEPARATOR, in_list, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
758         ITERATE( list<string>, i, in_list) {
759             AddString( *inputs,
760                 GetRelativePath(CDirEntry::ConcatPath(script_loc,*i)));
761         }
762         list<string> out_list;
763         NStr::Split(info.m_Output, LIST_SEPARATOR, out_list, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
764         ITERATE( list<string>, o, out_list) {
765             AddString( *outputs,
766                 GetRelativePath(CDirEntry::ConcatPath(script_loc,*o)));
767         }
768         AddArray(  *dict_script, "files");
769         AddArray(  *dict_script, "inputPaths",  inputs);
770         AddArray(  *dict_script, "outputPaths", outputs);
771         AddString( *dict_script, "isa", "PBXShellScriptBuildPhase");
772         if (info.m_Shell.empty()) {
773             info.m_Shell = "/bin/sh";
774         }
775         AddString( *dict_script, "shellPath", info.m_Shell);
776         AddString( *dict_script, "shellScript",
777             CDirEntry::IsAbsolutePath(info.m_Script) ? info.m_Script :
778             GetRelativePath(CDirEntry::ConcatPath(script_loc,info.m_Script)));
779         AddString( *dict_script, "showEnvVarsInLog", "0");
780         return proj_script;
781     }
782     return kEmptyStr;
783 }
784 
CreateProjectCopyBinScript(const CProjItem & prj,const CProjectFileCollector & prj_files,CDict & dict_objects)785 string CMacProjectGenerator::CreateProjectCopyBinScript(
786     const CProjItem& prj, const CProjectFileCollector& prj_files,
787     CDict& dict_objects)
788 {
789     string bins_out_install(m_OutputDir + "bin/${CONFIGURATION}");
790     if (prj.m_ProjType == CProjKey::eApp ||
791         (prj.m_ProjType == CProjKey::eDll && prj.m_IsBundle)) {
792 
793         string script;
794         script += "export BUILD_TREE_ROOT=" +
795             CDirEntry::DeleteTrailingPathSeparator( GetRelativePath(
796             CDirEntry::AddTrailingPathSeparator( CDirEntry::ConcatPath(
797                 GetApp().GetProjectTreeInfo().m_Compilers,
798                 GetApp().GetRegSettings().m_CompilersSubdir)))) + "\n";
799         script += "export BUILD_TREE_BIN=" + bins_out_install + "\n";
800         script +=  "\"$BUILD_TREE_ROOT/copybin.sh\"";
801         string proj_script(   GetUUID());
802         CRef<CArray> inputs(  new CArray);
803         AddString( *inputs, "$(TARGET_BUILD_DIR)/$(TARGET_NAME)");
804         CRef<CArray> outputs( new CArray);
805         CRef<CDict> dict_script( AddDict( dict_objects, proj_script));
806         AddArray(  *dict_script, "files");
807         AddArray(  *dict_script, "inputPaths",  inputs);
808         AddArray(  *dict_script, "outputPaths", outputs);
809         AddString( *dict_script, "isa", "PBXShellScriptBuildPhase");
810         AddString( *dict_script, "shellPath", "/bin/sh");
811         AddString( *dict_script, "shellScript", script);
812         AddString( *dict_script, "showEnvVarsInLog", "0");
813         return proj_script;
814     }
815     return kEmptyStr;
816 }
817 
CreateProjectLinkPhase(const CProjItem & prj,const CProjectFileCollector & prj_files,CDict & dict_objects)818 string CMacProjectGenerator::CreateProjectLinkPhase(
819     const CProjItem& prj, const CProjectFileCollector& prj_files,
820     CDict& dict_objects)
821 {
822     if (prj.m_ProjType == CProjKey::eDll || prj.m_ProjType == CProjKey::eApp) {
823         list<CProjItem> ldlibs;
824         ITERATE( list<CProjKey>, d, prj.m_Depends) {
825             CProjectItemsTree::TProjects::const_iterator
826                 dp = m_Projects_tree.m_Projects.find( *d);
827             if ( dp != m_Projects_tree.m_Projects.end() &&
828                 (dp->first.Id() != prj.m_ID || dp->first.Type() != prj.m_ProjType) &&
829                 (dp->first.Type() == CProjKey::eLib || dp->first.Type() == CProjKey::eDll)) {
830 
831                 if (dp->first.Type() == CProjKey::eLib &&
832                     GetApp().GetSite().Is3PartyLib(dp->first.Id())) {
833                         continue;
834                 }
835                 ldlibs.push_back(dp->second);
836             }
837         }
838         if (!ldlibs.empty()) {
839             string proj_link( GetUUID());
840             CRef<CDict> dict_link( AddDict( dict_objects, proj_link));
841             CRef<CArray> link_libs( AddArray( *dict_link, "files"));
842             ITERATE( list<CProjItem>, d, ldlibs) {
843                 string lib_ref( GetUUID());
844                 {
845                     CRef<CDict> dict_lib_ref( AddDict( dict_objects, lib_ref));
846                     AddString( *dict_lib_ref, "fileRef", m_TargetProduct[GetProjId(*d)]);
847                     AddString( *dict_lib_ref, "isa", "PBXBuildFile");
848                 }
849                 AddString( *link_libs, lib_ref);
850             }
851             AddString( *dict_link, "isa", "PBXFrameworksBuildPhase");
852             return proj_link;
853         }
854     }
855     return kEmptyStr;
856 }
857 
CreateProjectBuildPhase(const CProjItem & prj,CDict & dict_objects,CRef<CArray> & build_files)858 string CMacProjectGenerator::CreateProjectBuildPhase(
859     const CProjItem& prj,
860     CDict& dict_objects, CRef<CArray>& build_files)
861 {
862     if (prj.m_ProjType == CProjKey::eDataSpec || prj.m_ProjType == CProjKey::eMsvc) {
863         return kEmptyStr;
864     }
865 #if USE_VERBOSE_NAMES
866     string proj_build(    GetProjBuild( prj));
867 #else
868     string proj_build(    GetUUID());
869 #endif
870     CRef<CDict> dict_build( AddDict( dict_objects, proj_build));
871     AddArray( *dict_build, "files", build_files);
872     AddString( *dict_build, "isa", "PBXSourcesBuildPhase");
873     return proj_build;
874 }
875 
CollectLibToLibDependencies(set<string> & dep,set<string> & visited,const CProjItem & lib,const CProjItem & lib_dep)876 void CMacProjectGenerator::CollectLibToLibDependencies(
877     set<string>& dep, set<string>& visited,
878     const CProjItem& lib, const CProjItem& lib_dep)
879 {
880 #if USE_VERBOSE_NAMES
881     string lib_name(GetProjDependency(lib));
882     string lib_dep_name(GetProjDependency(lib_dep));
883 #else
884     string lib_name(lib.m_GUID);
885     string lib_dep_name(lib_dep.m_GUID);
886 #endif
887     if (GetApp().m_AllDllBuild) {
888         dep.insert(lib_dep_name);
889         return;
890     }
891 
892     if (visited.find(lib_dep_name) != visited.end() ||
893         lib_dep_name == lib_name) {
894         return;
895     }
896     visited.insert(lib_dep_name);
897     if (!lib_dep.m_DatatoolSources.empty() ||
898         !lib_dep.m_ExportHeaders.empty() ||
899         lib.m_UnconditionalDepends.find(
900             CProjKey(lib_dep.m_ProjType, lib_dep.m_ID)) !=
901             lib.m_UnconditionalDepends.end()) {
902         dep.insert(lib_dep_name);
903     }
904     ITERATE(list<CProjKey>, p, lib_dep.m_Depends) {
905         if (p->Type() == CProjKey::eLib) {
906             CProjectItemsTree::TProjects::const_iterator n =
907                 m_Projects_tree.m_Projects.find(*p);
908             if (n != m_Projects_tree.m_Projects.end()) {
909                 CollectLibToLibDependencies(dep, visited, lib, n->second);
910             }
911         }
912     }
913 }
914 
CreateProjectTarget(const CProjItem & prj,const CProjectFileCollector & prj_files,CDict & dict_objects,CRef<CArray> & build_phases,const string & product_id)915 string CMacProjectGenerator::CreateProjectTarget(
916     const CProjItem& prj, const CProjectFileCollector& prj_files,
917     CDict& dict_objects, CRef<CArray>& build_phases,
918     const string& product_id)
919 {
920 #if USE_VERBOSE_NAMES
921     string proj_target(   GetProjTarget(   prj));
922 #else
923     string proj_target(   GetUUID());
924 #endif
925     string target_name(   GetTargetName(   prj));
926     string product_type(  GetProductType(  prj));
927     CRef<CArray> dependencies( new CArray);
928     string configs_prj(
929         CreateProjectBuildConfigurations( prj, prj_files, dict_objects));
930     CRef<CDict> dict_target( AddDict( dict_objects, proj_target));
931     AddString( *dict_target, "buildConfigurationList",configs_prj);
932     AddArray( *dict_target, "buildPhases", build_phases);
933 
934     list<string> proj_guid;
935     set<string> lib_guid, visited;
936     ITERATE( list<CProjKey>, d, prj.m_Depends) {
937         CProjectItemsTree::TProjects::const_iterator
938             dp = m_Projects_tree.m_Projects.find( *d);
939         if ( dp != m_Projects_tree.m_Projects.end() &&
940             (dp->first.Id() != prj.m_ID || dp->first.Type() != prj.m_ProjType)) {
941 
942             if (dp->first.Type() == CProjKey::eLib &&
943                 GetApp().GetSite().Is3PartyLib(dp->first.Id())) {
944                     continue;
945             }
946             if (prj.m_ProjType == CProjKey::eLib && dp->first.Type() == CProjKey::eLib) {
947                 CollectLibToLibDependencies(lib_guid, visited, prj, dp->second);
948                 continue;
949             }
950 #if USE_VERBOSE_NAMES
951             proj_guid.push_back( GetProjDependency(dp->second));
952 #else
953             proj_guid.push_back( dp->second.m_GUID);
954 #endif
955         }
956     }
957     copy(lib_guid.begin(), lib_guid.end(), back_inserter(proj_guid));
958     if (!proj_guid.empty()) {
959         proj_guid.sort();
960         proj_guid.unique();
961         ITERATE(list<string>, p, proj_guid) {
962             AddString( *dependencies, *p);
963         }
964     }
965     AddArray(  *dict_target, "dependencies", dependencies);
966     if (prj.m_ProjType == CProjKey::eDataSpec || prj.m_ProjType == CProjKey::eMsvc) {
967         AddString( *dict_target, "isa", "PBXAggregateTarget");
968     } else {
969         AddString( *dict_target, "isa", "PBXNativeTarget");
970     }
971     AddString( *dict_target, "name", target_name);
972     AddString( *dict_target, "productName", target_name);
973     if (prj.m_ProjType != CProjKey::eDataSpec && prj.m_ProjType != CProjKey::eMsvc) {
974         AddString( *dict_target, "productReference", product_id);
975         AddString( *dict_target, "productType", product_type);
976     }
977     return proj_target;
978 }
979 
CreateBuildConfigurations(CDict & dict_objects)980 string CMacProjectGenerator::CreateBuildConfigurations(CDict& dict_objects)
981 {
982     CRef<CArray> build_settings( new CArray);
983 #if USE_VERBOSE_NAMES
984     string bld_cfg(      "Build_Configuration_");
985     string bld_cfg_list( "Build_Configurations");
986 #else
987     string bld_cfg_list( GetUUID());
988 #endif
989 
990     ITERATE(list<SConfigInfo>, cfg, m_Configs) {
991         if (cfg->m_rtType == SConfigInfo::rtSingleThreaded ||
992             cfg->m_rtType == SConfigInfo::rtSingleThreadedDebug ||
993             cfg->m_rtType == SConfigInfo::rtUnknown) {
994             continue;
995         }
996 #if USE_VERBOSE_NAMES
997         string bld_cfg_name(bld_cfg + cfg->m_Name);
998 #else
999         string bld_cfg_name( GetUUID());
1000 #endif
1001         CreateBuildSettings( *AddDict( dict_objects, bld_cfg_name), *cfg);
1002         AddString( *build_settings, bld_cfg_name);
1003     }
1004 
1005     CRef<CDict> configs( AddDict( dict_objects, bld_cfg_list));
1006     AddArray(  *configs, "buildConfigurations", build_settings);
1007     AddString( *configs, "defaultConfigurationIsVisible", "0");
1008     AddString( *configs, "defaultConfigurationName", "ReleaseDLL");
1009     AddString( *configs, "isa", "XCConfigurationList");
1010     return bld_cfg_list;
1011 }
1012 
CreateProjectBuildConfigurations(const CProjItem & prj,const CProjectFileCollector & prj_files,CDict & dict_objects)1013 string CMacProjectGenerator::CreateProjectBuildConfigurations(
1014     const CProjItem& prj, const CProjectFileCollector& prj_files,
1015     CDict& dict_objects)
1016 {
1017     CRef<CArray> build_settings( new CArray);
1018     string proj_id(      GetProjId( prj) );
1019 #if USE_VERBOSE_NAMES
1020     string bld_cfg(      proj_id + "_Build_Configuration_");
1021     string bld_cfg_list( proj_id + "_Build_Configurations");
1022 #else
1023     string bld_cfg_list( GetUUID());
1024 #endif
1025 
1026     ITERATE(list<SConfigInfo>, cfg, prj_files.GetEnabledConfigs()) {
1027         if (cfg->m_rtType == SConfigInfo::rtSingleThreaded ||
1028             cfg->m_rtType == SConfigInfo::rtSingleThreadedDebug ||
1029             cfg->m_rtType == SConfigInfo::rtUnknown) {
1030             continue;
1031         }
1032         prj.m_CheckConfigs.insert(cfg->GetConfigFullName());
1033 #if USE_VERBOSE_NAMES
1034         string bld_cfg_name(bld_cfg + cfg->m_Name);
1035 #else
1036         string bld_cfg_name( GetUUID());
1037 #endif
1038         CreateProjectBuildSettings( prj, prj_files,
1039             *AddDict( dict_objects, bld_cfg_name), *cfg);
1040         AddString( *build_settings, bld_cfg_name);
1041     }
1042 
1043     CRef<CDict> configs( AddDict( dict_objects, bld_cfg_list));
1044     AddArray(  *configs, "buildConfigurations", build_settings);
1045     AddString( *configs, "defaultConfigurationIsVisible", "0");
1046     AddString( *configs, "defaultConfigurationName", "ReleaseDLL");
1047     AddString( *configs, "isa", "XCConfigurationList");
1048     return bld_cfg_list;
1049 }
1050 
CreateAggregateBuildConfigurations(const string & target_name,CDict & dict_objects)1051 string CMacProjectGenerator::CreateAggregateBuildConfigurations(
1052     const string& target_name, CDict& dict_objects)
1053 {
1054     CRef<CArray> build_settings( new CArray);
1055     string proj_id(      target_name );
1056 #if USE_VERBOSE_NAMES
1057     string bld_cfg(      target_name + "_Build_Configuration_");
1058     string bld_cfg_list( target_name + "_Build_Configurations");
1059 #else
1060     string bld_cfg_list( GetUUID());
1061 #endif
1062 
1063     ITERATE(list<SConfigInfo>, cfg, m_Configs) {
1064         if (cfg->m_rtType == SConfigInfo::rtSingleThreaded ||
1065             cfg->m_rtType == SConfigInfo::rtSingleThreadedDebug ||
1066             cfg->m_rtType == SConfigInfo::rtUnknown) {
1067             continue;
1068         }
1069 #if USE_VERBOSE_NAMES
1070         string bld_cfg_name(bld_cfg + cfg->m_Name);
1071 #else
1072         string bld_cfg_name( GetUUID());
1073 #endif
1074         CreateAggregateBuildSettings( target_name,
1075             *AddDict( dict_objects, bld_cfg_name), *cfg);
1076         AddString( *build_settings, bld_cfg_name);
1077     }
1078 
1079     CRef<CDict> configs( AddDict( dict_objects, bld_cfg_list));
1080     AddArray(  *configs, "buildConfigurations", build_settings);
1081     AddString( *configs, "defaultConfigurationIsVisible", "0");
1082     AddString( *configs, "defaultConfigurationName", "ReleaseDLL");
1083     AddString( *configs, "isa", "XCConfigurationList");
1084     return bld_cfg_list;
1085 }
1086 
CreateBuildSettings(CDict & dict_cfg,const SConfigInfo & cfg)1087 void CMacProjectGenerator::CreateBuildSettings(CDict& dict_cfg, const SConfigInfo& cfg)
1088 {
1089     string tmp_str;
1090     list<string> tmp_list;
1091 
1092     CRef<CDict> settings( AddDict( dict_cfg, "buildSettings"));
1093     AddString( dict_cfg, "isa", "XCBuildConfiguration");
1094     AddString( dict_cfg, "name", cfg.m_Name);
1095 
1096     tmp_str = CMsvc7RegSettings::GetRequestedArchs();
1097     if (tmp_str.empty()) {
1098         tmp_str = GetApp().GetMetaMakefile().GetCompilerOpt("ARCHS", cfg);
1099     }
1100     tmp_list.clear();
1101     NStr::Split(tmp_str, LIST_SEPARATOR, tmp_list, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
1102     CRef<CArray> archs( AddArray( *settings, "ARCHS"));
1103     ITERATE( list<string>, a, tmp_list) {
1104         AddString( *archs, *a);
1105     }
1106 
1107     AddCompilerSetting( *settings, cfg, "GCC_WARN_ABOUT_RETURN_TYPE");
1108     AddCompilerSetting( *settings, cfg, "GCC_WARN_UNUSED_VARIABLE");
1109     AddCompilerSetting( *settings, cfg, "GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS");
1110     AddCompilerSetting( *settings, cfg, "GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS");
1111     AddCompilerSetting( *settings, cfg, "GCC_WARN_NON_VIRTUAL_DESTRUCTOR");
1112     AddCompilerSetting( *settings, cfg, "GCC_WARN_PEDANTIC");
1113     AddCompilerSetting( *settings, cfg, "GCC_WARN_SHADOW");
1114     AddCompilerSetting( *settings, cfg, "GCC_WARN_SIGN_COMPARE");
1115 
1116     AddCompilerSetting( *settings, cfg, "GCC_DYNAMIC_NO_PIC");
1117     AddCompilerSetting( *settings, cfg, "GCC_ENABLE_FIX_AND_CONTINUE");
1118     AddCompilerSetting( *settings, cfg, "GCC_MODEL_TUNING");
1119     AddCompilerSetting( *settings, cfg, "GCC_ENABLE_CPP_EXCEPTIONS");
1120     AddCompilerSetting( *settings, cfg, "GCC_ENABLE_CPP_RTTI");
1121 
1122     AddCompilerSetting( *settings, cfg, "COPY_PHASE_STRIP");
1123     AddCompilerSetting( *settings, cfg, "GCC_GENERATE_DEBUGGING_SYMBOLS");
1124     AddCompilerSetting( *settings, cfg, "GCC_OPTIMIZATION_LEVEL");
1125     AddCompilerSetting( *settings, cfg, "DEBUG_INFORMATION_FORMAT");
1126     AddCompilerSetting( *settings, cfg, "GCC_DEBUGGING_SYMBOLS");
1127 
1128     AddCompilerSetting( *settings, cfg, "SDKROOT");
1129     AddCompilerSetting( *settings, cfg, "FRAMEWORK_SEARCH_PATHS");
1130     AddCompilerSetting( *settings, cfg, "USE_HEADERMAP");
1131 
1132     AddCompilerSetting( *settings, cfg, "OTHER_CPLUSPLUSFLAGS");
1133 
1134     AddLinkerSetting( *settings, cfg, "DEAD_CODE_STRIPPING");
1135     AddLinkerSetting( *settings, cfg, "PREBINDING");
1136 //    AddLinkerSetting( *settings, cfg, "ZERO_LINK");
1137     if (cfg.m_rtType == SConfigInfo::rtMultiThreadedDebugDLL ||
1138         cfg.m_rtType == SConfigInfo::rtMultiThreadedDLL) {
1139         AddString( *settings, "STANDARD_C_PLUS_PLUS_LIBRARY_TYPE", "dynamic");
1140     } else {
1141         AddString( *settings, "STANDARD_C_PLUS_PLUS_LIBRARY_TYPE", "static");
1142     }
1143 }
1144 
CreateProjectBuildSettings(const CProjItem & prj,const CProjectFileCollector & prj_files,CDict & dict_cfg,const SConfigInfo & cfg)1145 void CMacProjectGenerator::CreateProjectBuildSettings(
1146         const CProjItem& prj, const CProjectFileCollector& prj_files,
1147         CDict& dict_cfg, const SConfigInfo& cfg)
1148 {
1149     const CMsvcMetaMakefile& metamake( GetApp().GetMetaMakefile());
1150     bool dll_build = GetApp().GetBuildType().GetType() == CBuildType::eDll;
1151     string def_lib_path(m_OutputDir + "lib/$(CONFIGURATION)");
1152 
1153     string libs_out(m_OutputDir + "lib/$(CONFIGURATION)");
1154     string libs_out_install(m_OutputDir + "lib/$(CONFIGURATION)");
1155 // CreateProjectCopyBinScript takes care of copying them into bin; CXX-1609
1156 //    string bins_out(m_OutputDir + "bin/$(CONFIGURATION)");
1157     string bins_out(m_OutputDir + "lib/$(CONFIGURATION)");
1158     string bins_out_install(m_OutputDir + "bin/$(CONFIGURATION)");
1159 
1160     string proj_dir("$(PROJECT_DIR)/");
1161 
1162 //    string temp_dir("$(BUILD_DIR)/$(CONFIGURATION)");
1163     string temp_dir("$(OBJROOT)/$(CONFIGURATION)");
1164     string objroot(m_OutputDir + "build");
1165 
1166     CRef<CArray> lib_paths(new CArray);
1167     AddString(*lib_paths, def_lib_path);
1168     list<string> prj_lib_dirs;
1169     if (prj_files.GetLibraryDirs(prj_lib_dirs, cfg)) {
1170         ITERATE ( list<string>, f, prj_lib_dirs) {
1171             AddString( *lib_paths, GetRelativePath( *f));
1172         }
1173     }
1174 
1175     CRef<CDict> settings( AddDict( dict_cfg, "buildSettings"));
1176     AddString( dict_cfg, "isa", "XCBuildConfiguration");
1177     AddString( dict_cfg, "name", cfg.m_Name);
1178 
1179     if (prj.m_ProjType == CProjKey::eLib) {
1180 
1181         AddLibrarianSetting( *settings, cfg, "GCC_ENABLE_SYMBOL_SEPARATION");
1182         AddLibrarianSetting( *settings, cfg, "GCC_INLINES_ARE_PRIVATE_EXTERN");
1183         AddLibrarianSetting( *settings, cfg, "GCC_SYMBOLS_PRIVATE_EXTERN");
1184 
1185         AddString( *settings, "CONFIGURATION_BUILD_DIR", libs_out);
1186         AddString( *settings, "CONFIGURATION_TEMP_DIR", temp_dir);
1187         AddString( *settings, "INSTALL_PATH", proj_dir + libs_out_install);
1188         AddString( *settings, "OBJROOT", objroot);
1189 
1190     } else if (prj.m_ProjType == CProjKey::eDll) {
1191 
1192         string bld_out(libs_out);
1193         string bld_out_install(libs_out_install);
1194         if (prj.m_IsBundle) {
1195             bld_out = bins_out;
1196             bld_out_install = bins_out_install;
1197         }
1198         AddLinkerSetting( *settings, cfg, "GCC_INLINES_ARE_PRIVATE_EXTERN");
1199         AddLinkerSetting( *settings, cfg, "GCC_SYMBOLS_PRIVATE_EXTERN");
1200 
1201         AddString( *settings, "CONFIGURATION_BUILD_DIR", bld_out);
1202         AddString( *settings, "CONFIGURATION_TEMP_DIR", temp_dir);
1203         AddString( *settings, "INSTALL_PATH", proj_dir + bld_out_install);
1204         AddString( *settings, "OBJROOT", objroot);
1205 
1206         AddArray( *settings, "LIBRARY_SEARCH_PATHS", lib_paths);
1207         AddString( *settings, "EXECUTABLE_PREFIX", "lib");
1208 
1209     } else if (prj.m_ProjType == CProjKey::eApp) {
1210 
1211         AddLinkerSetting( *settings, cfg, "GCC_INLINES_ARE_PRIVATE_EXTERN");
1212         AddLinkerSetting( *settings, cfg, "GCC_SYMBOLS_PRIVATE_EXTERN");
1213 
1214         AddString( *settings, "CONFIGURATION_BUILD_DIR", bins_out);
1215         AddString( *settings, "CONFIGURATION_TEMP_DIR", temp_dir);
1216         AddString( *settings, "INSTALL_PATH", proj_dir + bins_out_install);
1217         AddString( *settings, "OBJROOT", objroot);
1218 
1219         AddArray( *settings, "LIBRARY_SEARCH_PATHS", lib_paths);
1220     }
1221     if (prj.m_ProjType != CProjKey::eDataSpec && prj.m_ProjType != CProjKey::eMsvc) {
1222         AddString( *settings, "MACH_O_TYPE", GetMachOType(prj));
1223     }
1224 
1225 // library dependencies
1226     if (prj.m_ProjType == CProjKey::eDll || prj.m_ProjType == CProjKey::eApp) {
1227         string ldlib;
1228 #if 0
1229         list<CProjItem> ldlibs;
1230         ITERATE( list<CProjKey>, d, prj.m_Depends) {
1231             CProjectItemsTree::TProjects::const_iterator
1232                 dp = m_Projects_tree.m_Projects.find( *d);
1233             if ( dp != m_Projects_tree.m_Projects.end() &&
1234                 (dp->first.Id() != prj.m_ID || dp->first.Type() != prj.m_ProjType) &&
1235                 (dp->first.Type() == CProjKey::eLib || dp->first.Type() == CProjKey::eDll)) {
1236 
1237                 if (dp->first.Type() == CProjKey::eLib &&
1238                     GetApp().GetSite().Is3PartyLib(dp->first.Id())) {
1239                         continue;
1240                 }
1241                 ldlibs.push_back(dp->second);
1242             }
1243         }
1244         ldlibs.sort(s_ProjItem_less);
1245         ITERATE( list<CProjItem>, d, ldlibs) {
1246             ldlib += string(" -l") + GetTargetName(*d);
1247         }
1248 #endif
1249         string add;
1250         add = prj_files.GetProjectContext().GetMsvcProjectMakefile().GetLinkerOpt("OTHER_LDFLAGS",cfg);
1251         if (!add.empty()) {
1252             ldlib += " " + add;
1253         }
1254         add = prj_files.GetProjectContext().AdditionalLinkerOptions(cfg);
1255         if (!add.empty()) {
1256             ldlib += " " + add;
1257         }
1258         add = metamake.GetLinkerOpt("OTHER_LDFLAGS", cfg);
1259         if (!add.empty()) {
1260             ldlib += " " + add;
1261         }
1262         AddString( *settings, "OTHER_LDFLAGS", ldlib);
1263     }
1264 
1265 //    AddString( *settings, "PRODUCT_NAME", GetTargetName(prj));
1266     AddString( *settings, "PRODUCT_NAME", prj.m_ID);
1267     if (prj.m_ProjType == CProjKey::eDataSpec || prj.m_ProjType == CProjKey::eMsvc) {
1268         return;
1269     }
1270 
1271     CRef<CArray> inc_dirs( AddArray( *settings, "HEADER_SEARCH_PATHS"));
1272     list<string> prj_inc_dirs;
1273     if (prj_files.GetIncludeDirs(prj_inc_dirs, cfg)) {
1274         ITERATE ( list<string>, f, prj_inc_dirs) {
1275 /*
1276             if (CSymResolver::HasDefine(*f)) {
1277                 continue;
1278             }
1279 */
1280             AddString( *inc_dirs, GetRelativePath( *f));
1281         }
1282     }
1283 
1284 // preprocessor definitions
1285     list<string> tmp_list = prj.m_Defines;
1286     tmp_list = prj_files.GetProjectContext().Defines(cfg);
1287     string tmp_str = metamake.GetCompilerOpt("GCC_PREPROCESSOR_DEFINITIONS", cfg);
1288     NStr::Split(tmp_str, LIST_SEPARATOR, tmp_list, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
1289     if (dll_build) {
1290         tmp_str = GetApp().GetConfig().Get(CMsvc7RegSettings::GetMsvcSection(), "DllBuildDefine");
1291         NStr::Split(tmp_str, LIST_SEPARATOR, tmp_list, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate);
1292     }
1293     if (prj.m_ProjType == CProjKey::eApp) {
1294         tmp_list.push_back("NCBI_APP_BUILT_AS=$(TARGET_NAME)");
1295     }
1296 
1297     tmp_list.sort();
1298     tmp_list.unique();
1299     CRef<CArray> preproc( AddArray( *settings, "GCC_PREPROCESSOR_DEFINITIONS"));
1300     ITERATE( list<string>, a, tmp_list) {
1301         AddString( *preproc, *a);
1302     }
1303 
1304 // precompiled header
1305     SConfigInfo cfg_tmp;
1306     if (prj_files.GetProjectContext().IsPchEnabled(cfg_tmp)) {
1307         string nofile = CDirEntry::ConcatPath(prj.m_SourcesBaseDir,"aanofile");
1308         string pch_name = prj_files.GetProjectContext().GetPchHeader(
1309             prj.m_ID, nofile, GetApp().GetProjectTreeInfo().m_Src, cfg_tmp);
1310         if (!pch_name.empty()) {
1311             string pch_path;
1312             // find header (MacOS requires? path)
1313             if (prj_files.GetIncludeDirs(prj_inc_dirs, cfg)) {
1314                 ITERATE ( list<string>, f, prj_inc_dirs) {
1315                     if (pch_path.empty()) {
1316                         string t = CDirEntry::ConcatPath( *f, pch_name);
1317                         if (CDirEntry(t).IsFile()) {
1318                             pch_path = t;
1319                             break;
1320                         }
1321                     }
1322                 }
1323             }
1324             if (pch_path.empty()) {
1325                 pch_path = CDirEntry::ConcatPath(
1326                     GetApp().GetProjectTreeInfo().m_Include, pch_name);
1327             }
1328             AddString( *settings, "GCC_PRECOMPILE_PREFIX_HEADER", "YES");
1329             AddString( *settings, "GCC_PREFIX_HEADER", GetRelativePath( pch_path));
1330 // for some unknown reason, when I define NCBI_USE_PCH
1331 // xutil library does not compile
1332             string tmp(metamake.GetPchUsageDefine());
1333             if (!tmp.empty()) {
1334                 AddString( *preproc, tmp);
1335             }
1336         }
1337     }
1338 }
1339 
CreateAggregateBuildSettings(const string & target_name,CDict & dict_cfg,const SConfigInfo & cfg)1340 void CMacProjectGenerator::CreateAggregateBuildSettings(
1341     const string& target_name, CDict& dict_cfg, const SConfigInfo& cfg)
1342 {
1343     CRef<CDict> settings( AddDict( dict_cfg, "buildSettings"));
1344     AddString( dict_cfg, "isa", "XCBuildConfiguration");
1345     AddString( dict_cfg, "name", cfg.m_Name);
1346     AddString( *settings, "PRODUCT_NAME", target_name);
1347 }
1348 
AddAggregateTarget(const string & target_name,CDict & dict_objects,CRef<CArray> & dependencies)1349 string CMacProjectGenerator::AddAggregateTarget(
1350     const string& target_name, CDict& dict_objects, CRef<CArray>& dependencies)
1351 {
1352 #if USE_VERBOSE_NAMES
1353     string proj_target( target_name + "_target");
1354 #else
1355     string proj_target( GetUUID());
1356 #endif
1357     string configs_prj(
1358         CreateAggregateBuildConfigurations( target_name, dict_objects));
1359     CRef<CDict> dict_target( AddDict( dict_objects, proj_target));
1360     AddString( *dict_target, "buildConfigurationList", configs_prj);
1361     AddArray(  *dict_target, "buildPhases");
1362     AddString( *dict_target, "comments", NStr::NumericToString(dependencies->Get().size()) + " targets");
1363     AddArray(  *dict_target, "dependencies", dependencies);
1364     AddString( *dict_target, "isa", "PBXAggregateTarget");
1365     AddString( *dict_target, "name", target_name);
1366     AddString( *dict_target, "productName", target_name);
1367     return proj_target;
1368 }
1369 
AddPreConfigureTarget(CArray & targets,CDict & dict_objects,const string & root_name)1370 string CMacProjectGenerator::AddPreConfigureTarget(
1371     CArray& targets, CDict& dict_objects, const string& root_name)
1372 {
1373     string target_name("_pre_CONFIGURE");
1374     string proj_target( GetUUID());
1375     string configs_prj(
1376         CreateAggregateBuildConfigurations( target_name, dict_objects));
1377 
1378     string build_tree_root (
1379         CDirEntry::DeleteTrailingPathSeparator( GetRelativePath(
1380         CDirEntry::AddTrailingPathSeparator( CDirEntry::ConcatPath(
1381             GetApp().GetProjectTreeInfo().m_Compilers,
1382             GetApp().GetRegSettings().m_CompilersSubdir)))));
1383     string script("$(PROJECT_DIR)/");
1384     script += build_tree_root + "/precfg.sh";
1385 
1386     CRef<CDict> dict_target( AddDict( dict_objects, proj_target));
1387     AddString( *dict_target, "buildArgumentsString", script);
1388     AddString( *dict_target, "buildConfigurationList", configs_prj);
1389     AddArray(  *dict_target, "buildPhases");
1390     AddString( *dict_target, "buildToolPath", "/bin/sh");
1391     AddArray(  *dict_target, "dependencies");
1392     AddString( *dict_target, "isa", "PBXLegacyTarget");
1393     AddString( *dict_target, "name", target_name);
1394     AddString( *dict_target, "passBuildSettingsInEnvironment", "1");
1395     AddString( *dict_target, "productName", target_name);
1396 
1397     InsertString(targets, proj_target);
1398 
1399     string proj_dependency( GetUUID());
1400     string proj_container(  GetUUID());
1401     // project dependency key
1402     {
1403         CRef<CDict> dict_dep( AddDict( dict_objects, proj_dependency));
1404         AddString( *dict_dep, "isa", "PBXTargetDependency");
1405         AddString( *dict_dep, "target", proj_target);
1406         AddString( *dict_dep, "targetProxy", proj_container);
1407     }
1408     // project container
1409     {
1410         CRef<CDict> dict_con( AddDict( dict_objects, proj_container));
1411         AddString( *dict_con, "containerPortal", root_name);
1412         AddString( *dict_con, "isa", "PBXContainerItemProxy");
1413         AddString( *dict_con, "proxyType", "1");
1414         AddString( *dict_con, "remoteGlobalIDString", proj_target);
1415         AddString( *dict_con, "remoteInfo", target_name);
1416     }
1417     return proj_dependency;
1418 }
1419 
AddConfigureTarget(const string & solution_name,CDict & dict_objects,bool gui,const string & preconf_dependency)1420 string CMacProjectGenerator::AddConfigureTarget(
1421     const string& solution_name, CDict& dict_objects, bool gui,
1422     const string& preconf_dependency)
1423 {
1424     string target_name("CONFIGURE");
1425     if (gui) {
1426         target_name += "_DIALOG";
1427     }
1428 #if USE_VERBOSE_NAMES
1429     string proj_target( target_name + "_target");
1430     string proj_script( target_name + "_script");
1431 #else
1432     string proj_target( GetUUID());
1433     string proj_script( GetUUID());
1434 #endif
1435 
1436     string configs_prj(
1437         CreateAggregateBuildConfigurations( target_name, dict_objects));
1438 
1439     string script;
1440     script += "export PTB_PLATFORM=\"$ARCHS\"\n";
1441     script += "export PTB_PATH=" + m_OutputDir + "../static/bin/ReleaseDLL\n";
1442     script += "export SLN_PATH=" + m_OutputDir + "\"$PROJECT_NAME\""/*solution_name*/ + "\n";
1443     script += "export TREE_ROOT=" +
1444         CDirEntry::DeleteTrailingPathSeparator( GetRelativePath( GetApp().m_Root)) + "\n";
1445     script += "export BUILD_TREE_ROOT=" +
1446         CDirEntry::DeleteTrailingPathSeparator( GetRelativePath(
1447         CDirEntry::AddTrailingPathSeparator( CDirEntry::ConcatPath(
1448             GetApp().GetProjectTreeInfo().m_Compilers,
1449             GetApp().GetRegSettings().m_CompilersSubdir)))) + "\n";
1450     script += m_OutputDir + "UtilityProjects/configure_";
1451     if (gui) {
1452         script += "gui_";
1453     }
1454     script += solution_name + ".sh";
1455     CRef<CDict> dict_script( AddDict( dict_objects, proj_script));
1456     AddArray(  *dict_script, "files");
1457     AddArray(  *dict_script, "inputPaths");
1458     AddArray(  *dict_script, "outputPaths");
1459     AddString( *dict_script, "isa", "PBXShellScriptBuildPhase");
1460     AddString( *dict_script, "shellPath", "/bin/sh");
1461     AddString( *dict_script, "shellScript", script);
1462     AddString( *dict_script, "showEnvVarsInLog", "0");
1463 
1464     CRef<CDict> dict_target( AddDict( dict_objects, proj_target));
1465     AddString( *dict_target, "buildConfigurationList", configs_prj);
1466     CRef<CArray> build_phases(AddArray(  *dict_target, "buildPhases"));
1467     AddString( *build_phases, proj_script);
1468     CRef<CArray> dependencies(AddArray(  *dict_target, "dependencies"));
1469     AddString( *dependencies, preconf_dependency);
1470     AddString( *dict_target, "isa", "PBXAggregateTarget");
1471     AddString( *dict_target, "name", target_name);
1472     AddString( *dict_target, "productName", target_name);
1473     return proj_target;
1474 }
1475 
CreateRootObject(const string & configs_root,CDict & dict_objects,CRef<CArray> & targets,const string & root_group,const string & root_name,const string & products_group)1476 string CMacProjectGenerator::CreateRootObject(
1477     const string& configs_root, CDict& dict_objects, CRef<CArray>& targets,
1478     const string& root_group, const string& root_name, const string& products_group)
1479 {
1480     CRef<CDict> root_obj( AddDict( dict_objects, root_name));
1481     AddString( *root_obj, "buildConfigurationList", configs_root);
1482     AddString( *root_obj, "compatibilityVersion", "Xcode 3.0");
1483     AddString( *root_obj, "hasScannedForEncodings", "1");
1484     AddString( *root_obj, "isa", "PBXProject");
1485     AddString( *root_obj, "mainGroup", root_group);
1486     AddString( *root_obj, "productRefGroup", products_group);
1487     AddString( *root_obj, "projectDirPath", "");
1488     AddString( *root_obj, "projectRoot", "");
1489     AddArray(  *root_obj, "targets", targets);
1490     return root_name;
1491 }
1492 
GetUUID(void)1493 string CMacProjectGenerator::GetUUID(void)
1494 {
1495     static Uint4 uuid = 1;
1496     char buffer[64];
1497     ::sprintf(buffer, "ABCDABCDABCDABCD%08X", uuid++);
1498     return buffer;
1499 }
1500 
AddFile(CDict & dict,const string & name,bool style_objcpp)1501 string CMacProjectGenerator::AddFile(CDict& dict, const string& name, bool style_objcpp)
1502 {
1503     string filetype;
1504     CDirEntry entry(name);
1505     string ext = entry.GetExt();
1506     if ( ext == ".cpp" || ext == ".c") {
1507         if (style_objcpp) {
1508             filetype = "sourcecode.cpp.objcpp";
1509         } else {
1510             filetype = string("sourcecode") + ext + ext;
1511         }
1512     } else if (ext == ".cc" || ext == ".cxx") {
1513         filetype = "sourcecode.cpp.cpp";
1514     } else if (ext == ".hpp" || ext == ".inl") {
1515         filetype = "sourcecode.cpp.h";
1516     } else if (ext == ".h") {
1517         filetype = "sourcecode.c.h";
1518     } else if (ext == ".xsd") {
1519         filetype = "text.xml";
1520     } else if (ext == ".wsdl") {
1521         filetype = "text.xml";
1522     } else if (ext == ".jsd") {
1523         filetype = "text.json";
1524     } else if (ext == ".metal") {
1525         filetype = "sourcecode.metal";
1526     } else {
1527         filetype = "text";
1528     }
1529 
1530     string base_name = entry.GetName();
1531 #if USE_VERBOSE_NAMES
1532     static size_t counter = 0;
1533     string name_id = "FILE" + NStr::UIntToString(counter++);
1534 #else
1535     string name_id( GetUUID());
1536 #endif
1537     CRef<CDict> file( AddDict( dict, name_id));
1538     AddString( *file, "isa", "PBXFileReference");
1539     if (!filetype.empty()) {
1540         AddString( *file, "lastKnownFileType", filetype);
1541     }
1542     AddString( *file, "name", base_name);
1543     AddString( *file, "path", GetRelativePath(name));
1544     AddString( *file, "sourceTree", "SOURCE_ROOT");
1545     return name_id;
1546 }
1547 
AddFileSource(CDict & dict,const string & name)1548 string CMacProjectGenerator::AddFileSource(CDict& dict, const string& name)
1549 {
1550 #if USE_VERBOSE_NAMES
1551     string name_ref = "SRC_" + name;
1552 #else
1553     string name_ref( GetUUID());
1554 #endif
1555     CRef<CDict> file( AddDict( dict, name_ref));
1556     AddString( *file, "fileRef", name);
1557     AddString( *file, "isa", "PBXBuildFile");
1558     return name_ref;
1559 }
1560 
AddGroupDict(CDict & dict,const string & key,CRef<CArray> & children,const string & name)1561 void  CMacProjectGenerator::AddGroupDict(
1562     CDict& dict, const string& key, CRef<CArray>& children, const string& name)
1563 {
1564     CRef<CDict> group( AddDict( dict, key));
1565     AddArray(  *group, "children", children);
1566     AddString( *group, "isa", "PBXGroup");
1567     AddString( *group, "name", name);
1568     AddString( *group, "sourceTree", "<group>");
1569 }
1570 
1571 
AddString(CArray & ar,const string & value)1572 void CMacProjectGenerator::AddString(CArray& ar, const string& value)
1573 {
1574     CRef<CArray::C_E> e(new CArray::C_E);
1575     e->SetString( value);
1576     ar.Set().push_back(e);
1577 }
1578 
InsertString(CArray & ar,const string & value)1579 void CMacProjectGenerator::InsertString(CArray& ar, const string& value)
1580 {
1581     CRef<CArray::C_E> e(new CArray::C_E);
1582     e->SetString( value);
1583     ar.Set().push_front(e);
1584 }
1585 
AddString(CDict & dict,const string & key,const string & value)1586 void CMacProjectGenerator::AddString(
1587     CDict& dict, const string& key, const string& value)
1588 {
1589     CRef<CDict::C_E> e(new CDict::C_E);
1590     e->SetKey(key);
1591     e->SetPlistObject().SetString(value);
1592     dict.Set().push_back(e);
1593 }
1594 
AddArray(CDict & dict,const string & key)1595 CRef<CArray> CMacProjectGenerator::AddArray(
1596     CDict& dict, const string& key)
1597 {
1598     CRef<CDict::C_E> e(new CDict::C_E);
1599     e->SetKey(key);
1600     CArray& a = e->SetPlistObject().SetArray();
1601     dict.Set().push_back(e);
1602     return CRef<CArray>(&a);
1603 }
1604 
AddArray(CDict & dict,const string & key,CRef<CArray> & array)1605 void CMacProjectGenerator::AddArray(
1606     CDict& dict, const string& key, CRef<CArray>& array)
1607 {
1608     CRef<CDict::C_E> e(new CDict::C_E);
1609     e->SetKey(key);
1610     e->SetPlistObject().SetArray(*array);
1611     dict.Set().push_back(e);
1612 }
1613 
AddDict(CDict & dict,const string & key)1614 CRef<CDict> CMacProjectGenerator::AddDict(
1615     CDict& dict, const string& key)
1616 {
1617     CRef<CDict::C_E> e(new CDict::C_E);
1618     e->SetKey(key);
1619     CDict& d = e->SetPlistObject().SetDict();
1620     dict.Set().push_back(e);
1621     return CRef<CDict>(&d);
1622 }
1623 
AddCompilerSetting(CDict & settings,const SConfigInfo & cfg,const string & key)1624 void CMacProjectGenerator::AddCompilerSetting(CDict& settings,
1625     const SConfigInfo& cfg, const string& key)
1626 {
1627     string value = GetApp().GetMetaMakefile().GetCompilerOpt(key,cfg);
1628     if (!value.empty()) {
1629         AddString( settings, key, value);
1630     }
1631 }
AddLinkerSetting(CDict & settings,const SConfigInfo & cfg,const string & key)1632 void CMacProjectGenerator::AddLinkerSetting(CDict& settings,
1633     const SConfigInfo& cfg, const string& key)
1634 {
1635     string value = GetApp().GetMetaMakefile().GetLinkerOpt(key,cfg);
1636     if (!value.empty()) {
1637         AddString( settings, key, value);
1638     }
1639 }
AddLibrarianSetting(CDict & settings,const SConfigInfo & cfg,const string & key)1640 void CMacProjectGenerator::AddLibrarianSetting(CDict& settings,
1641     const SConfigInfo& cfg, const string& key)
1642 {
1643     string value = GetApp().GetMetaMakefile().GetLibrarianOpt(key,cfg);
1644     if (!value.empty()) {
1645         AddString( settings, key, value);
1646     }
1647 }
1648 
GetRelativePath(const string & name,const string * from) const1649 string CMacProjectGenerator::GetRelativePath(const string& name, const string* from) const
1650 {
1651     if (!from) {
1652         from = &m_SolutionDir;
1653     }
1654     if (GetApp().UseAbsolutePath(*from) || !SameRootDirs(name, *from)) {
1655         return name;
1656     }
1657     string file_path;
1658     try {
1659         file_path = CDirEntry::CreateRelativePath(*from, name);
1660 //  On REAL MacOS, it is not needed
1661 #ifdef PSEUDO_XCODE
1662         NStr::ReplaceInPlace(file_path, "\\", "/");
1663 #endif
1664     } catch (CFileException&) {
1665         file_path = name;
1666     }
1667     return file_path;
1668 }
1669 
GetProjId(const CProjItem & prj)1670 string CMacProjectGenerator::GetProjId( const CProjItem& prj)
1671 {
1672     string id(prj.m_ID);
1673     if (prj.m_ProjType == CProjKey::eLib) {
1674         id += "_ar";
1675     } else if (prj.m_ProjType == CProjKey::eDll) {
1676         id += "_dylib";
1677     } else if (prj.m_ProjType == CProjKey::eApp) {
1678         id += "_exe";
1679     }
1680     return id;
1681 }
GetProjTarget(const CProjItem & prj)1682 string CMacProjectGenerator::GetProjTarget(const CProjItem& prj)
1683 {
1684     return GetProjId(prj) + "_target";
1685 }
GetProjBuild(const CProjItem & prj)1686 string CMacProjectGenerator::GetProjBuild(const CProjItem& prj)
1687 {
1688     return GetProjId(prj) + "_build";
1689 }
GetProjProduct(const CProjItem & prj)1690 string CMacProjectGenerator::GetProjProduct(const CProjItem& prj)
1691 {
1692     return GetProjId(prj) + "_product";
1693 }
GetProjHeaders(const CProjItem & prj)1694 string CMacProjectGenerator::GetProjHeaders(const CProjItem& prj)
1695 {
1696     return GetProjId(prj) + "_headers";
1697 }
GetProjDependency(const CProjItem & prj)1698 string CMacProjectGenerator::GetProjDependency(  const CProjItem& prj)
1699 {
1700     return GetProjId(prj) + "_dependency";
1701 }
GetProjContainer(const CProjItem & prj)1702 string CMacProjectGenerator::GetProjContainer(   const CProjItem& prj)
1703 {
1704     return GetProjId(prj) + "_container";
1705 }
GetTargetName(const CProjItem & prj)1706 string CMacProjectGenerator::GetTargetName( const CProjItem& prj)
1707 {
1708     if (prj.m_ProjType == CProjKey::eLib) {
1709         return /*string("lib") +*/ prj.m_ID;
1710     }
1711     if (prj.m_ProjType == CProjKey::eApp) {
1712         CProjKey klib(CProjKey::eLib, prj.m_ID), kdll(CProjKey::eDll, prj.m_ID);
1713         if (m_Projects_tree.m_Projects.find(klib) != m_Projects_tree.m_Projects.end() ||
1714             m_Projects_tree.m_Projects.find(kdll) != m_Projects_tree.m_Projects.end()) {
1715             return string(prj.m_ID) + ".exe";
1716         }
1717     }
1718     return prj.m_ID;
1719 }
1720 
GetMachOType(const CProjItem & prj)1721 string CMacProjectGenerator::GetMachOType(  const CProjItem& prj)
1722 {
1723     if (prj.m_ProjType == CProjKey::eLib) {
1724         return "staticlib";
1725     } else if (prj.m_ProjType == CProjKey::eDll) {
1726 /*
1727         if (prj.m_IsBundle) {
1728             return "mh_bundle";
1729         }
1730 */
1731         return "mh_dylib";
1732     } else if (prj.m_ProjType == CProjKey::eApp) {
1733 /*
1734         if (prj.m_IsBundle) {
1735             return "mh_bundle";
1736         }
1737 */
1738 //        return "mh_executable";
1739         return "mh_execute";
1740     }
1741     return "";
1742 }
1743 
GetProductType(const CProjItem & prj)1744 string CMacProjectGenerator::GetProductType( const CProjItem& prj)
1745 {
1746     if (prj.m_ProjType == CProjKey::eLib) {
1747         if (prj.m_IsMetallib) {
1748             return "com.apple.product-type.metal-library";
1749         } else {
1750             return "com.apple.product-type.library.static";
1751         }
1752     } else if (prj.m_ProjType == CProjKey::eDll) {
1753         return "com.apple.product-type.library.dynamic";
1754     } else if (prj.m_ProjType == CProjKey::eApp) {
1755         if (prj.m_IsBundle) {
1756             return "com.apple.product-type.application";
1757         }
1758         return "com.apple.product-type.tool";
1759     }
1760     return "";
1761 }
GetExplicitType(const CProjItem & prj)1762 string CMacProjectGenerator::GetExplicitType( const CProjItem& prj)
1763 {
1764     if (prj.m_ProjType == CProjKey::eLib) {
1765         if (prj.m_IsMetallib) {
1766             return "archive.metal-library";
1767         } else {
1768             return "archive.ar";
1769         }
1770     } else if (prj.m_ProjType == CProjKey::eDll) {
1771         return "compiled.mach-o.dylib";
1772     } else if (prj.m_ProjType == CProjKey::eApp) {
1773         if (prj.m_IsBundle) {
1774             return "wrapper.application";
1775         }
1776         return "compiled.mach-o.executable";
1777     }
1778     return "";
1779 }
1780 
1781 #endif
1782 
1783 
1784 END_NCBI_SCOPE
1785