]> git.tdb.fi Git - builder.git/blob - source/virtualfilesystem.cpp
Tool names are no longer retrieved from Architecture
[builder.git] / source / virtualfilesystem.cpp
1 #include <msp/fs/stat.h>
2 #include <msp/io/print.h>
3 #include <msp/strings/utils.h>
4 #include "builder.h"
5 #include "csourcefile.h"
6 #include "misc.h"
7 #include "sharedlibrary.h"
8 #include "systemlibrary.h"
9 #include "virtualfilesystem.h"
10
11 using namespace std;
12 using namespace Msp;
13
14 namespace {
15
16 void update_hash(string &hash, const string &value)
17 {
18         for(unsigned i=0; i<value.size(); ++i)
19                 hash[i%hash.size()] ^= value[i];
20 }
21
22 }
23
24
25 VirtualFileSystem::VirtualFileSystem(Builder &b):
26         builder(b)
27 {
28 }
29
30 FileTarget *VirtualFileSystem::get_target(const FS::Path &p) const
31 {
32         TargetMap::const_iterator i = targets.find(p.str());
33         if(i!=targets.end())
34                 return static_cast<FileTarget *>(i->second);
35         return 0;
36 }
37
38 void VirtualFileSystem::register_path(const FS::Path &path, FileTarget *t)
39 {
40         targets.insert(TargetMap::value_type(path.str(), t));
41 }
42
43 FileTarget *VirtualFileSystem::find_header(const string &include, const FS::Path &from, const list<string> &path)
44 {
45         string hash(8, 0);
46         if(include[0]=='\"')
47                 update_hash(hash, from.str());
48         for(list<string>::const_iterator i=path.begin(); i!=path.end(); ++i)
49                 update_hash(hash, *i);
50
51         string id = hash+include;
52         TargetMap::iterator i = include_cache.find(id);
53         if(i!=include_cache.end())
54                 return i->second;
55
56         static string cxx_ver;
57         if(cxx_ver.empty())
58         {
59                 // XXX This needs to go elsewhere
60                 /*StringList argv;
61                 argv.push_back(current_arch->get_tool("CXX"));
62                 argv.push_back("--version");
63                 if(RegMatch m = Regex("[0-9]\\.[0-9.]+").match(run_command(argv)))
64                 {
65                         cxx_ver = m[0].str;
66                         while(!cxx_ver.empty() && !FS::is_dir(FS::Path("/usr/include/c++")/cxx_ver))
67                         {
68                                 string::size_type dot = cxx_ver.rfind('.');
69                                 if(dot==string::npos)
70                                         break;
71                                 cxx_ver.erase(dot);
72                         }
73                         if(verbose>=5)
74                                 IO::print("C++ version is %s\n", cxx_ver);
75                 }
76                 else*/
77                         cxx_ver = "-";
78         }
79
80         string fn = include.substr(1);
81         if(builder.get_verbose()>=5)
82                 IO::print("Looking for include %s from %s with path %s\n", fn, from, join(path.begin(), path.end()));
83
84         SearchPath syspath;
85         const Architecture &arch = builder.get_current_arch();
86         if(arch.is_native())
87                 syspath.push_back("/usr/include");
88         else
89                 syspath.push_back("/usr/"+arch.get_cross_prefix()+"/include");
90         if(cxx_ver!="-")
91                 syspath.push_back((FS::Path("/usr/include/c++/")/cxx_ver).str());
92
93         FileTarget *tgt = 0;
94         if(include[0]=='\"')
95                 tgt = get_header(FS::Path(from)/fn);
96         for(list<string>::const_iterator j=path.begin(); (!tgt && j!=path.end()); ++j)
97                 tgt = get_header(FS::Path(*j)/fn);
98         for(list<string>::const_iterator j=syspath.begin(); (!tgt && j!=syspath.end()); ++j)
99                 tgt = get_header(FS::Path(*j)/fn);
100
101         include_cache.insert(TargetMap::value_type(id, tgt));
102
103         return tgt;
104 }
105
106 FileTarget *VirtualFileSystem::find_library(const string &lib, const list<string> &path, LibMode mode)
107 {
108         string hash(8, 0);
109         for(list<string>::const_iterator i=path.begin(); i!=path.end(); ++i)
110                 update_hash(hash, *i);
111
112         string id = hash+string(1, mode)+lib;
113         TargetMap::iterator i = library_cache.find(id);
114         if(i!=library_cache.end())
115                 return i->second;
116
117         SearchPath syspath;
118         const Architecture &arch = builder.get_current_arch();
119         if(arch.is_native())
120         {
121                 syspath.push_back("/lib");
122                 syspath.push_back("/usr/lib");
123                 if(arch.match_name("pc-32-linux"))
124                         syspath.push_back("/usr/lib/i386-linux-gnu");
125                 else if(arch.match_name("pc-64-linux"))
126                         syspath.push_back("/usr/lib/x86_64-linux-gnu");
127         }
128         else
129                 syspath.push_back("/usr/"+arch.get_cross_prefix()+"/lib");
130
131         if(builder.get_verbose()>=5)
132                 IO::print("Looking for library %s with path %s\n", lib, join(path.begin(), path.end()));
133
134         FileTarget *tgt = 0;
135         for(StringList::const_iterator j=path.begin(); (!tgt && j!=path.end()); ++j)
136                 tgt = get_library(lib, *j, mode);
137         for(StringList::iterator j=syspath.begin(); (!tgt && j!=syspath.end()); ++j)
138                 tgt = get_library(lib, *j, mode);
139
140         library_cache.insert(TargetMap::value_type(id, tgt));
141
142         return tgt;
143 }
144
145 FileTarget *VirtualFileSystem::get_header(const FS::Path &fn)
146 {
147         FileTarget *tgt = get_target(fn);
148         if(tgt)
149                 return tgt;
150
151         if(FS::is_reg(fn))
152         {
153                 tgt = new CSourceFile(builder, fn);
154                 return tgt;
155         }
156         return 0;
157 }
158
159 FileTarget *VirtualFileSystem::get_library(const string &lib, const FS::Path &path, LibMode mode)
160 {
161         const Architecture &arch = builder.get_current_arch();
162
163         /* Try dynamic libraries only if library mode permits it */
164         if(mode!=ALL_STATIC)
165         {
166                 FS::Path fn = try_patterns(path, arch.get_shared_library_patterns(), lib);
167                 if(!fn.empty())
168                 {
169                         FileTarget *tgt = get_target(fn);
170                         if(!tgt)
171                                 return new SystemLibrary(builder, fn.str());
172                         else if(mode==DYNAMIC || !tgt->get_package())
173                                 return tgt;
174                 }
175         }
176
177         /* Static libraries are always considered, since sometimes shared versions
178         may not be available */
179         FS::Path fn = try_patterns(path, arch.get_static_library_patterns(), lib);
180         if(!fn.empty())
181         {
182                 if(FileTarget *tgt = get_target(fn))
183                         return tgt;
184                 else
185                         return new SystemLibrary(builder, fn.str());
186         }
187
188         return 0;
189 }
190
191 FS::Path VirtualFileSystem::try_patterns(const FS::Path &dir, const list<Pattern> &patterns, const string &base)
192 {
193         for(list<Pattern>::const_iterator i=patterns.begin(); i!=patterns.end(); ++i)
194         {
195                 FS::Path full = dir/i->apply(base);
196                 if(get_target(full) || FS::is_reg(full))
197                         return full;
198         }
199
200         return FS::Path();
201 }