]> git.tdb.fi Git - builder.git/blob - source/lib/binarypackage.cpp
If a binary package is not found, briefly describe what was missing
[builder.git] / source / lib / binarypackage.cpp
1 #include <limits>
2 #include <msp/core/algorithm.h>
3 #include <msp/io/print.h>
4 #include <msp/strings/utils.h>
5 #include "binarypackage.h"
6 #include "builder.h"
7 #include "filetarget.h"
8 #include "staticlibrary.h"
9
10 using namespace std;
11 using namespace Msp;
12
13 BinaryPackage::BinaryPackage(Builder &b, const string &n):
14         Package(b, n)
15 {
16         use_pkgconfig = false;
17 }
18
19 BinaryPackage *BinaryPackage::from_flags(Builder &builder, const string &name, const Flags &flags, const Flags &static_flags)
20 {
21         BinaryPackage *pkg = new BinaryPackage(builder, name);
22         pkg->use_pkgconfig = true;
23
24         process_flags(flags, pkg->export_binfo);
25
26         Flags exclusive_static_flags;
27         for(const string &f: static_flags)
28                 if(!any_equals(flags, f))
29                         exclusive_static_flags.push_back(f);
30         process_flags(exclusive_static_flags, pkg->static_binfo);
31
32         return pkg;
33 }
34
35 void BinaryPackage::process_flags(const Flags &flags, BuildInfo &binfo)
36 {
37         for(const string &f: flags)
38         {
39                 if(!f.compare(0, 2, "-I"))
40                         binfo.incpath.push_back(f.substr(2));
41                 else if(!f.compare(0, 2, "-D"))
42                 {
43                         string::size_type equals = f.find('=');
44                         if(equals!=string::npos)
45                                 binfo.defines[f.substr(2, equals-2)] = f.substr(equals+1);
46                         else
47                                 binfo.defines[f.substr(2)] = string();
48                 }
49                 else if(!f.compare(0, 2, "-L"))
50                         binfo.libpath.push_back(f.substr(2));
51                 else if(!f.compare(0, 2, "-l"))
52                         binfo.libs.push_back(f.substr(2));
53                 else if(f=="-pthread")
54                         binfo.threads = true;
55         }
56 }
57
58 void BinaryPackage::do_prepare()
59 {
60         auto is_relative = [](const FS::Path &p){ return !p.is_absolute(); };
61         bool has_relative_paths = any_of(export_binfo.libpath.begin(), export_binfo.libpath.end(), is_relative) ||
62                 any_of(export_binfo.incpath.begin(), export_binfo.incpath.end(), is_relative);
63
64         vector<FS::Path> bases;
65
66         /* If we have any relative paths that need resolving, or we have no paths at
67         all and are not using pkg-config, look for files in prefix */
68         if(has_relative_paths || (!use_pkgconfig && export_binfo.libpath.empty() && export_binfo.incpath.empty()))
69                 bases.push_back(builder.get_prefix());
70
71         // Always look in system locations
72         bases.push_back(FS::Path());
73
74         bool system = false;
75         unsigned least_missing = numeric_limits<unsigned>::max();
76         string missing_name;
77         for(const FS::Path &b: bases)
78         {
79                 FS::Path prefix = b;
80                 system = prefix.empty();
81                 if(system)
82                 {
83                         prefix = "/usr";
84                         const Architecture &arch = builder.get_current_arch();
85                         if(arch.is_cross())
86                                 prefix /= arch.get_cross_prefix();
87                 }
88
89                 VirtualFileSystem::SearchPath libpath = export_binfo.libpath;
90                 if(!system && libpath.empty())
91                         libpath.push_back("lib");
92                 for(FS::Path &p: libpath)
93                         p = prefix/p;
94
95                 unsigned missing_count = 0;
96                 string first_missing;
97                 for(const string &l: export_binfo.libs)
98                         if(!builder.get_vfs().find_library(l, libpath, export_binfo.libmode, system))
99                                 if(!missing_count++)
100                                         first_missing = format("library %s", l);
101
102                 VirtualFileSystem::SearchPath incpath = export_binfo.incpath;
103                 if(!system && incpath.empty())
104                         incpath.push_back("include");
105                 for(FS::Path &p: incpath)
106                         p = prefix/p;
107
108                 for(const string &h: headers)
109                         if(!builder.get_vfs().find_header(h, 0, incpath, system))
110                                 if(!missing_count++)
111                                         first_missing = h;
112
113                 if(!missing_count)
114                 {
115                         base_path = prefix;
116                         builder.get_logger().log("configure", "%s found in %s", name, ((system && use_pkgconfig) ? "system" : base_path.str()));
117                         break;
118                 }
119                 else if(missing_count<least_missing)
120                 {
121                         least_missing = missing_count;
122                         missing_name = first_missing;
123                 }
124         }
125
126         if(base_path.empty())
127         {
128                 string missing_descr = (least_missing>1 ? format("%s and %d other files", missing_name, least_missing-1) : missing_name);
129                 builder.get_logger().log("problems", "Cannot locate %s for %s", missing_descr, name);
130                 problems.push_back(format("Cannot locate %s", missing_descr));
131                 return;
132         }
133
134         /* Add default entries to paths if they're empty and the package was found
135         in a non-system location */
136         if(!system && export_binfo.incpath.empty())
137                 export_binfo.incpath.push_back(base_path/"include");
138         if(!system && export_binfo.libpath.empty())
139                 export_binfo.libpath.push_back(base_path/"lib");
140
141         if(has_relative_paths)
142         {
143                 for(FS::Path &p: export_binfo.incpath)
144                         p = base_path/p;
145                 for(FS::Path &p: export_binfo.libpath)
146                         p = base_path/p;
147         }
148
149         if(!static_binfo.libs.empty())
150         {
151                 VirtualFileSystem::SearchPath combined_libpath = static_binfo.libpath;
152                 combined_libpath.insert(combined_libpath.end(), export_binfo.libpath.begin(), export_binfo.libpath.end());
153
154                 for(const string &l: export_binfo.libs)
155                         if(Target *lib = builder.get_vfs().find_library(l, export_binfo.libpath, BuildInfo::FORCE_STATIC, system))
156                                 if(StaticLibrary *stlib = dynamic_cast<StaticLibrary *>(lib))
157                                 {
158                                         for(const string &s: static_binfo.libs)
159                                                 stlib->add_required_library(s);
160                                         for(const FS::Path &p: combined_libpath)
161                                                 stlib->add_library_path(p);
162                                 }
163         }
164 }
165
166
167 BinaryPackage::Loader::Loader(BinaryPackage &p):
168         DataFile::DerivedObjectLoader<BinaryPackage, Package::Loader>(p)
169 {
170         add("build_info", &Loader::build_info);
171         add("header",     &Loader::header);
172 }
173
174 void BinaryPackage::Loader::build_info()
175 {
176         load_sub(obj.export_binfo);
177 }
178
179 void BinaryPackage::Loader::header(const string &h)
180 {
181         obj.headers.push_back(h);
182 }