]> git.tdb.fi Git - builder.git/blob - source/buildinfo.cpp
48b4832bba1139e8209651fa37b97ec5d02a31d9
[builder.git] / source / buildinfo.cpp
1 #include <set>
2 #include <msp/core/algorithm.h>
3 #include <msp/strings/format.h>
4 #include "buildinfo.h"
5
6 using namespace std;
7 using namespace Msp;
8
9 namespace {
10
11 /** Removes any duplicate entries from a list, leaving only the first one.  The
12 order of other elements is preserved.  O(nlogn) efficiency. */
13 template<typename T>
14 void unique(list<T> &l)
15 {
16         set<T> seen;
17         for(auto i=l.begin(); i!=l.end(); )
18         {
19                 if(seen.count(*i))
20                         l.erase(i++);
21                 else
22                         seen.insert(*i++);
23         }
24 }
25
26 }
27
28
29 BuildInfo::BuildInfo():
30         libmode(DYNAMIC),
31         rpath_mode(NO_RPATH),
32         threads(false),
33         debug(false),
34         optimize(0),
35         strip(false),
36         warning_level(0),
37         fatal_warnings(false)
38 { }
39
40 BuildInfo::LibraryMode BuildInfo::get_libmode_for(const string &lib) const
41 {
42         LibModeMap::const_iterator i = libmodes.find(lib);
43         if(i!=libmodes.end())
44                 return i->second;
45         return libmode;
46 }
47
48 void BuildInfo::update_from(const BuildInfo &bi, UpdateLevel level)
49 {
50         for(const auto &kvp: bi.defines)
51                 defines[kvp.first] = kvp.second;
52         incpath.insert(incpath.begin(), bi.incpath.begin(), bi.incpath.end());
53         threads = bi.threads;
54
55         for(const auto &kvp: bi.standards)
56         {
57                 StandardMap::iterator j = standards.find(kvp.first);
58                 if(j==standards.end())
59                         standards.insert(kvp);
60                 else if(kvp.second.type!=j->second.type || kvp.second.year!=j->second.year)
61                 {
62                         if(!kvp.second.type.compare(0, 3, "gnu"))
63                                 j->second.type = kvp.second.type;
64                         if(kvp.second.year>j->second.year)
65                                 j->second.year = kvp.second.year;
66                 }
67         }
68
69         if(level!=CHAINED)
70         {
71                 libpath.insert(libpath.begin(), bi.libpath.begin(), bi.libpath.end());
72                 libs.insert(libs.begin(), bi.libs.begin(), bi.libs.end());
73         }
74
75         if(level==LOCAL)
76         {
77                 sysroot = bi.sysroot;
78                 local_incpath.insert(local_incpath.begin(), bi.local_incpath.begin(), bi.local_incpath.end());
79                 libmode = bi.libmode;
80                 rpath_mode = bi.rpath_mode;
81                 for(const auto &kvp: bi.libmodes)
82                         libmodes[kvp.first] = kvp.second;
83                 keep_symbols.insert(keep_symbols.end(), bi.keep_symbols.begin(), bi.keep_symbols.end());
84                 debug = bi.debug;
85                 optimize = bi.optimize;
86                 strip = bi.strip;
87                 warning_level = bi.warning_level;
88                 fatal_warnings = bi.fatal_warnings;
89         }
90
91         unique(incpath);
92         unique(local_incpath);
93         unique(libpath);
94         unique(libs);
95         unique(keep_symbols);
96 }
97
98
99 BuildInfo::LanguageStandard::LanguageStandard(const string &std)
100 {
101         auto i = find_if(std, [](char c){ return isdigit(static_cast<unsigned char>(c)); });
102         string::size_type num = i-std.begin();
103         type = std.substr(0, num);
104         year = lexical_cast<unsigned>(std.substr(num));
105         year += (year<70 ? 2000 : 1900);
106 }
107
108 string BuildInfo::LanguageStandard::str() const
109 {
110         return format("%s%02d", type, year%100);
111 }
112
113
114 BuildInfo::Loader::Loader(BuildInfo &bi):
115         DataFile::ObjectLoader<BuildInfo>(bi)
116 {
117         add("debug",    &BuildInfo::debug);
118         add("define",   &Loader::define);
119         add("incpath",  &Loader::incpath);
120         add("keep_symbol", &Loader::keep_symbol);
121         add("libpath",  &Loader::libpath);
122         add("library",  &Loader::library);
123         add("libmode",  &BuildInfo::libmode);
124         add("libmode",  &Loader::libmode_for_lib);
125         add("local_incpath", &Loader::local_incpath);
126         add("optimize", &BuildInfo::optimize);
127         add("runtime_path_mode", &BuildInfo::rpath_mode);
128         add("standard", &Loader::standard);
129         add("strip",    &BuildInfo::strip);
130         add("sysroot",  &Loader::sysroot);
131         add("threads",  &BuildInfo::threads);
132         add("warning_level", &BuildInfo::warning_level);
133         add("fatal_warnings", &BuildInfo::fatal_warnings);
134 }
135
136 void BuildInfo::Loader::incpath(const string &s)
137 {
138         obj.incpath.push_back(s);
139 }
140
141 void BuildInfo::Loader::define(const string &d, const string &v)
142 {
143         obj.defines[d] = v;
144 }
145
146 void BuildInfo::Loader::keep_symbol(const string &s)
147 {
148         obj.keep_symbols.push_back(s);
149 }
150
151 void BuildInfo::Loader::libmode_for_lib(const string &l, LibraryMode m)
152 {
153         obj.libmodes[l] = m;
154 }
155
156 void BuildInfo::Loader::libpath(const string &s)
157 {
158         obj.libpath.push_back(s);
159 }
160
161 void BuildInfo::Loader::library(const string &s)
162 {
163         obj.libs.push_back(s);
164 }
165
166 void BuildInfo::Loader::local_incpath(const string &s)
167 {
168         obj.local_incpath.push_back(s);
169 }
170
171 void BuildInfo::Loader::standard(DataFile::Symbol tag, const string &std)
172 {
173         obj.standards[tag.name] = std;
174 }
175
176 void BuildInfo::Loader::sysroot(const string &s)
177 {
178         obj.sysroot = s;
179 }
180
181
182 void operator>>(const LexicalConverter &conv, BuildInfo::LibraryMode &libmode)
183 {
184         if(conv.get()=="FORCE_STATIC")
185                 libmode = BuildInfo::FORCE_STATIC;
186         else if(conv.get()=="STATIC")
187                 libmode = BuildInfo::STATIC;
188         else if(conv.get()=="DYNAMIC")
189                 libmode = BuildInfo::DYNAMIC;
190         else if(conv.get()=="FORCE_DYNAMIC")
191                 libmode = BuildInfo::FORCE_DYNAMIC;
192         else
193                 throw lexical_error(format("Conversion of '%s' to LibraryMode", conv.get()));
194 }
195
196
197 void operator>>(const LexicalConverter &conv, BuildInfo::RuntimePathMode &rpath_mode)
198 {
199         if(conv.get()=="NONE")
200                 rpath_mode = BuildInfo::NO_RPATH;
201         else if(conv.get()=="RELATIVE")
202                 rpath_mode = BuildInfo::RELATIVE;
203         else if(conv.get()=="ABSOLUTE")
204                 rpath_mode = BuildInfo::ABSOLUTE;
205         else
206                 throw lexical_error(format("Conversion of '%s' to RuntimePathMode", conv.get()));
207 }