2 #include <msp/fs/dir.h>
3 #include <msp/fs/stat.h>
4 #include <msp/fs/utils.h>
5 #include <msp/io/print.h>
6 #include <msp/strings/format.h>
7 #include <msp/strings/utils.h>
8 #include <msp/time/units.h>
9 #include <msp/time/utils.h>
10 #include "binarypackage.h"
12 #include "externaltask.h"
14 #include "packagemanager.h"
19 PackageManager::PackageManager(Builder &b):
24 pkg_path.push_back(builder.get_work_directory()/".");
25 pkg_path.push_back(builder.get_work_directory()/"..");
28 PackageManager::~PackageManager()
30 for(PackageMap::iterator i=packages.begin(); i!=packages.end(); ++i)
34 void PackageManager::set_no_externals(bool x)
39 void PackageManager::add_package(Package *pkg)
41 PackageMap::iterator i = packages.find(pkg->get_name());
45 throw invalid_argument("Package name conflict");
47 throw logic_error("Package is already managed");
50 packages.insert(PackageMap::value_type(pkg->get_name(), pkg));
53 Package *PackageManager::find_package(const string &name)
55 PackageMap::iterator i = packages.find(format("%s/%s", name, builder.get_current_arch().get_system()));
57 i = packages.find(name);
63 FS::Path path = get_package_location(name);
64 if(!path.empty() && !builder.load_build_file(path/"Build"))
66 i = packages.find(name);
75 // Package source not found - create a binary package
76 string flags_str = run_pkgconfig(name, "flags");
77 vector<string> flags = split(flags_str);
78 pkg = BinaryPackage::from_flags(builder, name, flags);
82 builder.problem(name, "not found");
85 packages.insert(PackageMap::value_type(name, pkg));
90 string PackageManager::run_pkgconfig(const string &pkg, const string &what)
94 const FS::Path &prefix = builder.get_prefix();
95 if(prefix.str()!="/usr")
97 FS::Path pcdir = prefix/"lib/pkgconfig";
98 if(const char *pcp = getenv("PKG_CONFIG_PATH"))
100 vector<string> path = split(pcp, ':');
102 for(vector<string>::const_iterator i=path.begin(); (!found && i!=path.end()); ++i)
103 found = (*i==pcdir.str());
106 path.push_back(pcdir.str());
107 setenv("PKG_CONFIG_PATH", join(path.begin(), path.end(), ":").c_str(), true);
111 setenv("PKG_CONFIG_PATH", pcdir.str().c_str(), true);
115 ExternalTask::Arguments argv;
116 argv.push_back("pkg-config");
117 if(what=="cflags" || what=="libs")
118 argv.push_back("--"+what);
119 else if(what=="flags")
121 argv.push_back("--cflags");
122 argv.push_back("--libs");
125 argv.push_back("--variable="+what);
128 builder.get_logger().log("auxcommands", format("Running %s", join(argv.begin(), argv.end())));
130 return ExternalTask::run_and_capture_output(argv);
133 FS::Path PackageManager::get_package_location(const string &name)
135 builder.get_logger().log("packagemgr", format("Looking for package %s", name));
139 // Try to get source directory with pkgconfig
140 string srcdir = strip(run_pkgconfig(name, "source"));
149 for(list<FS::Path>::const_iterator i=pkg_path.begin(); i!=pkg_path.end(); ++i)
151 builder.get_logger().log("files", format("Traversing %s", *i));
152 list<string> files = list_files(*i);
153 for(list<string>::const_iterator j=files.begin(); j!=files.end(); ++j)
155 FS::Path full = *i / *j;
156 if(FS::exists(full/"Build"))
157 pkg_dirs.push_back(full);
160 builder.get_logger().log("packagemgr", format("%d packages found in path", pkg_dirs.size()));
163 bool msp = !name.compare(0, 3, "msp");
164 for(list<FS::Path>::const_iterator i=pkg_dirs.begin(); i!=pkg_dirs.end(); ++i)
166 string base = basename(*i);
167 unsigned dash = base.rfind('-');
169 if(!base.compare(0, dash, name))
171 else if(msp && !base.compare(0, dash-3, name, 3, string::npos))