list<const Component *> queue;
list<Target *> dep_libs;
+ set<string> missing_libs;
queue.push_back(component);
while(!queue.empty())
{
else
dep_libs.push_back(lib);
}
- else
- builder.problem(package->get_name(), format("Couldn't find library %s for %s", *i, name));
+ else if(missing_libs.insert(*i).second)
+ problems.push_back(format("Required library %s not found", *i));
}
}
if(base_path.empty())
{
- builder.problem(name, "Cannot locate files");
+ // TODO report which files were not found
+ problems.push_back("Cannot locate files");
return;
}
logger = (l ? l : &default_logger);
}
-void Builder::problem(const string &p, const string &d)
+list<string> Builder::collect_problems() const
{
- problems.push_back(Problem(p, d));
+ list<string> problems;
+ set<const Package *> broken_packages;
+ set<const Component *> broken_components;
+ set<const Tool *> broken_tools;
+
+ const BuildGraph::TargetMap &targets = build_graph.get_targets();
+ for(BuildGraph::TargetMap::const_iterator i=targets.begin(); i!=targets.end(); ++i)
+ if(i->second->is_broken())
+ {
+ const list<string> &tgt_problems = i->second->get_problems();
+ for(list<string>::const_iterator j=tgt_problems.begin(); j!=tgt_problems.end(); ++j)
+ problems.push_back(format("%s: %s", i->second->get_name(), *j));
+
+ const Package *package = i->second->get_package();
+ if(package && !package->get_problems().empty())
+ broken_packages.insert(package);
+
+ const Component *component = i->second->get_component();
+ if(component && !component->get_problems().empty())
+ broken_components.insert(component);
+
+ const Tool *tool = i->second->get_tool();
+ if(tool && !tool->get_problems().empty())
+ broken_tools.insert(tool);
+ }
+
+ // TODO Sort components after their packages, and targets last
+ for(set<const Package *>::const_iterator i=broken_packages.begin(); i!=broken_packages.end(); ++i)
+ {
+ const list<string> &pkg_problems = (*i)->get_problems();
+ for(list<string>::const_iterator j=pkg_problems.begin(); j!=pkg_problems.end(); ++j)
+ problems.push_back(format("%s: %s", (*i)->get_name(), *j));
+ }
+
+ for(set<const Component *>::const_iterator i=broken_components.begin(); i!=broken_components.end(); ++i)
+ {
+ const list<string> &comp_problems = (*i)->get_problems();
+ for(list<string>::const_iterator j=comp_problems.begin(); j!=comp_problems.end(); ++j)
+ problems.push_back(format("%s/%s: %s", (*i)->get_package().get_name(), (*i)->get_name(), *j));
+ }
+
+ for(set<const Tool *>::const_iterator i=broken_tools.begin(); i!=broken_tools.end(); ++i)
+ {
+ const list<string> &tool_problems = (*i)->get_problems();
+ for(list<string>::const_iterator j=tool_problems.begin(); j!=tool_problems.end(); ++j)
+ problems.push_back(format("%s: %s", (*i)->get_tag(), *j));
+ }
+
+ return problems;
}
void Builder::load_build_file(const FS::Path &fn, const Config::InputOptions *opts, bool all)
#include "config.h"
#include "logger.h"
#include "packagemanager.h"
-#include "problem.h"
#include "target.h"
#include "toolchain.h"
#include "virtualfilesystem.h"
void package(const std::string &);
};
-public:
- typedef std::list<Problem> ProblemList;
-
private:
typedef std::map<std::string, BuildType> BuildTypeMap;
Logger default_logger;
const Logger *logger;
- ProblemList problems;
Msp::FS::Path prefix;
Msp::FS::Path tempdir;
void set_logger(const Logger *);
const Logger &get_logger() const { return *logger; }
- void problem(const std::string &, const std::string &);
- const ProblemList &get_problems() const { return problems; }
+ std::list<std::string> collect_problems() const;
/** Loads a build file. If opts is not null, it is used to configure any
packages loaded from this file. If all is true, external packages are also
if(analyzer)
analyzer->analyze();
- const Builder::ProblemList &problems = builder.get_problems();
- if(!problems.empty())
+ if(build_graph.get_goals().is_broken())
{
+ list<string> problems = builder.collect_problems();
IO::print(IO::cerr, "The following problems were detected:\n");
- for(Builder::ProblemList::const_iterator i=problems.begin(); i!=problems.end(); ++i)
- IO::print(IO::cerr, " %s: %s\n", i->package, i->descr);
+ for(list<string>::const_iterator i=problems.begin(); i!=problems.end(); ++i)
+ IO::print(IO::cerr, " %s\n", *i);
if(!analyzer)
IO::print(IO::cerr, "Please fix them and try again.\n");
return 1;
Package *req = obj.package.get_builder().get_package_manager().find_package(n);
if(req)
obj.requires.push_back(req);
+ else
+ obj.problems.push_back(format("Required package %s not found", n));
}
void Component::Loader::source(const string &s)
UseList uses;
bool deflt;
InstallMap install_map;
+ std::list<std::string> problems;
public:
Component(SourcePackage &, Type, const std::string &);
const Package::Requirements &get_required_packages() const { return requires; }
const UseList &get_used_components() const { return uses; }
bool is_default() const { return deflt; }
+ const std::list<std::string> &get_problems() const { return problems; }
/** Prepares any required packages. */
void prepare();
Package *req = obj.builder.get_package_manager().find_package(n);
if(req)
obj.requires.push_back(req);
+ else
+ obj.problems.push_back(format("Required package %s not found", n));
}
Requirements requires;
BuildInfo export_binfo;
bool prepared;
+ std::list<std::string> problems;
bool use_pkgconfig;
public:
bool is_prepared() const { return prepared; }
+ const std::list<std::string> &get_problems() const { return problems; }
+
virtual void save_caches() { }
};
}
catch(...)
{
- builder.problem(name, "not found");
not_found.insert(name);
return 0;
}
+++ /dev/null
-#ifndef PROBLEM_H_
-#define PROBLEM_H_
-
-#include <list>
-#include <string>
-
-struct Problem
-{
- std::string package;
- std::string descr;
-
- Problem(const std::string &p, const std::string &d): package(p), descr(d) { }
-};
-
-#endif
return;
if(state==PREPARING)
{
- builder.problem((package ? package->get_name() : string()), "Dependency cycle detected at "+name);
+ problems.push_back("Dependency cycle detected");
+ state = BROKEN;
return;
}
state = PREPARING;
if(tool)
tool->prepare();
+
find_dependencies();
+ bool broken = !problems.empty();
+
if(tool)
+ {
if(FileTarget *tool_exe = tool->get_executable())
add_dependency(*tool_exe);
+ broken |= !tool->get_problems().empty();
+
+ // Only check package and component problems for buildable targets
+ // XXX How to propagate nested package problems?
+ broken |= (package && !package->get_problems().empty());
+ broken |= (component && !component->get_problems().empty());
+ }
for(Dependencies::iterator i=depends.begin(); i!=depends.end(); ++i)
+ {
(*i)->prepare();
+ broken |= (*i)->is_broken();
+ }
check_rebuild();
- if(state==PREPARING)
+ if(broken)
+ state = BROKEN;
+ else if(state==PREPARING)
state = UPTODATE;
for(Dependencies::iterator i=depends.begin(); i!=depends.end(); ++i)
PREPARING,
REBUILD,
BUILDING,
- UPTODATE
+ UPTODATE,
+ BROKEN
};
public:
Tool *tool;
State state;
std::string rebuild_reason;
+ std::list<std::string> problems;
Dependencies depends;
Dependencies side_effects;
virtual void check_rebuild() = 0;
public:
+ bool is_broken() const { return state==BROKEN; }
+
+ const std::list<std::string> &get_problems() const { return problems; }
+
/** Prepares the target by finding dependencies, recursively preparing them
and then checking whether rebuilding is needed. */
void prepare();
executable = builder.get_vfs().find_binary(command);
if(!executable)
- builder.problem(string(), format("Can't find executable %s for tool %s", command, tag));
+ problems.push_back(format("Can't find executable %s", command));
}
SuffixList aux_suffixes;
SearchPath system_path;
bool prepared;
+ std::list<std::string> problems;
Tool(Builder &, const std::string &);
Tool(Builder &, const Architecture &, const std::string &);
void set_executable(const std::string &command, bool cross = false);
public:
+ const std::list<std::string> &get_problems() const { return problems; }
+
/** Invokes the tool to build a target. This should not be called directly;
use Target::build() instead. */
virtual Task *run(const Target &) const = 0;