1 /* $Id: proj_src_resolver.cpp 575393 2018-11-28 16:02:09Z 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 "proj_src_resolver.hpp"
32 #include "proj_builder_app.hpp"
33 #include "proj_tree_builder.hpp"
34 
35 BEGIN_NCBI_SCOPE
36 
37 // collect include statements and resolve to abs pathes
s_GetMakefileIncludes(const string & applib_mfilepath,const string & source_base_dir,list<string> * includes)38 static void s_GetMakefileIncludes(const string& applib_mfilepath,
39                                   const string& source_base_dir,
40                                   list<string>* includes)
41 {
42     includes->clear();
43 
44     CNcbiIfstream ifs(applib_mfilepath.c_str(),
45                       IOS_BASE::in | IOS_BASE::binary);
46     if ( !ifs )
47         NCBI_THROW(CProjBulderAppException, eFileOpen, applib_mfilepath);
48 
49     string strline;
50     while ( getline(ifs, strline) ) {
51         const string include_token("include ");
52         strline = NStr::TruncateSpaces(strline);
53         if ( NStr::StartsWith(strline, include_token) ) {
54             string include = strline.substr(include_token.length());
55 
56             string root;
57             string srcdir_token("$(srcdir)");
58             if (include.find(srcdir_token) == 0) {
59                 root = source_base_dir;
60             } else {
61                 srcdir_token = "$(top_srcdir)";
62                 if (include.find(srcdir_token) == 0) {
63                     root = GetApp().GetProjectTreeInfo().m_Root;
64                 }
65                 else {
66 #if 0
67                     srcdir_token = "$(builddir)";
68                     if (NStr::StartsWith(include, srcdir_token)) {
69                         root = GetApp().GetBuildRoot();
70                         if (root.empty()) {
71                             root = CDirEntry(GetApp().m_Solution).GetDir();
72                         }
73                     }
74 #endif
75                 }
76             }
77             if (!root.empty()) {
78                 include = include.substr(srcdir_token.length());
79                 include = CDirEntry::ConcatPath(root, include);
80                 include = CDirEntry::NormalizePath(include);
81             }
82             includes->push_back(include);
83         }
84     }
85 }
86 
87 
88 //-----------------------------------------------------------------------------
CProjSRCResolver(const string & applib_mfilepath,const string & source_base_dir,const list<string> & sources_src)89 CProjSRCResolver::CProjSRCResolver(const string&       applib_mfilepath,
90                              const string&       source_base_dir,
91                              const list<string>& sources_src)
92  :m_MakefilePath    (applib_mfilepath),
93   m_SourcesBaseDir(source_base_dir),
94   m_SourcesSrc      (sources_src)
95 {
96 }
97 
98 
~CProjSRCResolver(void)99 CProjSRCResolver::~CProjSRCResolver(void)
100 {
101 }
102 
s_SourceFileExists(const string & dir,const string & name)103 static bool s_SourceFileExists(const string& dir, const string& name)
104 {
105     string path = CDirEntry::ConcatPath(dir, name);
106 
107     if ( CDirEntry(path + ".cpp").Exists() )
108         return true;
109     if ( CDirEntry(path + ".cxx").Exists() )
110         return true;
111     if ( CDirEntry(path + ".cc").Exists() )
112         return true;
113     if ( CDirEntry(path + ".c").Exists() )
114         return true;
115     if ( CDirEntry(path + ".metal").Exists() )
116         return true;
117 
118     return false;
119 }
120 
ResolveTo(list<string> * sources_dst)121 void CProjSRCResolver::ResolveTo(list<string>* sources_dst)
122 {
123     sources_dst->clear();
124     PrepareResolver();
125 
126     list<string> sources_names;
127     ITERATE(list<string>, p, m_SourcesSrc) {
128         const string& src = *p;
129         string src_define;
130         if (SMakeProjectT::IsConfigurableDefine(src)) {
131             src_define = "$(" + SMakeProjectT::StripConfigurableDefine(src) + ")";
132         } else if (CSymResolver::IsDefine(src)) {
133             src_define = FilterDefine(src);
134         } else {
135             sources_names.push_back(src);
136             continue;
137         }
138         list<string> resolved_src_defines;
139         m_Resolver.Resolve(src_define, &resolved_src_defines);
140         if (resolved_src_defines.size() == 1 && resolved_src_defines.front() == src_define) {
141             continue;
142         }
143         copy(resolved_src_defines.begin(),
144                 resolved_src_defines.end(),
145                 back_inserter(sources_names));
146     }
147 
148     ITERATE(list<string>, p, sources_names) {
149         const string& src = *p;
150         bool found = false;
151         if ( s_SourceFileExists(m_SourcesBaseDir, src) ) {
152             sources_dst->push_back(src);
153             found = true;
154         } else {
155             ITERATE(list<string>, n, m_MakefileDirs) {
156                 const string& dir = *n;
157                 if ( s_SourceFileExists(dir, src) ) {
158                     string path =
159                         CDirEntry::CreateRelativePath(m_SourcesBaseDir, dir);
160                     path = CDirEntry::ConcatPath(path, src);
161                     sources_dst->push_back(path);
162                     found = true;
163                     break;
164                 }
165             }
166         }
167         if ( !found )
168             sources_dst->push_back(src);
169     }
170 }
171 
172 
PrepareResolver(void)173 void CProjSRCResolver::PrepareResolver(void)
174 {
175     if ( !m_Resolver.IsEmpty() )
176         return;
177 
178     list<string> include_makefiles;
179     s_GetMakefileIncludes(m_MakefilePath,
180                           m_SourcesBaseDir, &include_makefiles);
181 
182     ITERATE(list<string>, p, include_makefiles) {
183         m_MakefileDirs.push_back( CDirEntry(*p).GetDir());
184     }
185     CSymResolver::LoadFrom(m_MakefilePath, &m_Resolver);
186     m_Resolver.Append( GetApp().GetSite().GetMacros());
187 }
188 
189 END_NCBI_SCOPE
190