]> git.tdb.fi Git - builder.git/blob - source/virtualfilesystem.cpp
Get rid of separate header targets which serve no useful purpose
[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 "misc.h"
6 #include "sharedlibrary.h"
7 #include "sourcefile.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 SourceFile(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         // Populate a list of candidate filenames
162         StringList candidates;
163
164         const Architecture &arch = builder.get_current_arch();
165         if(mode!=ALL_STATIC)
166         {
167                 // XXX Should probably let the Architecture populate the list
168                 if(arch.get_system()=="windows")
169                 {
170                         candidates.push_back("lib"+lib+".dll");
171                         candidates.push_back(lib+".dll");
172                 }
173                 else
174                         candidates.push_back("lib"+lib+".so");
175         }
176
177         /* Static libraries are always considered, since sometimes shared versions
178         may not be available */
179         candidates.push_back("lib"+lib+".a");
180         if(arch.get_system()=="windows")
181                 candidates.push_back("lib"+lib+".dll.a");
182
183         for(StringList::iterator i=candidates.begin(); i!=candidates.end(); ++i)
184         {
185                 FS::Path full = path/ *i;
186                 FileTarget *tgt = get_target(full);
187
188                 if(tgt)
189                 {
190                         Target *real_tgt = tgt->get_real_target();
191
192                         /* Ignore dynamic libraries from local packages unless library mode is
193                         DYNAMIC */
194                         if(dynamic_cast<SharedLibrary *>(real_tgt) && mode!=DYNAMIC)
195                                 continue;
196                         else if(tgt)
197                                 return tgt;
198                 }
199                 else if(FS::is_reg(full))
200                 {
201                         tgt = new SystemLibrary(builder, full.str());
202                         return tgt;
203                 }
204         }
205
206         return 0;
207 }