From: Mikko Rasa Date: Wed, 8 May 2013 07:24:45 +0000 (+0300) Subject: Delay locating tool executables until the tool is needed X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=9e28243c9687608ec3c32954b4031490296ae877;p=builder.git Delay locating tool executables until the tool is needed This solves a problem where the mspdatatool executable is not detected as built by the mspdatafile package. --- diff --git a/source/component.cpp b/source/component.cpp index 371e145..d0cc1e9 100644 --- a/source/component.cpp +++ b/source/component.cpp @@ -138,7 +138,7 @@ void Component::create_targets() const string inst_loc; if(type==TARBALL) { - const Tool &tar = toolchain.get_tool("TAR"); + Tool &tar = toolchain.get_tool("TAR"); list files; for(SourceList::const_iterator i=source_filenames.begin(); i!=source_filenames.end(); ++i) @@ -171,7 +171,7 @@ void Component::create_targets() const else if(type==INSTALL) { Target *inst = build_graph.get_target("install"); - const Tool © = toolchain.get_tool("CP"); + Tool © = toolchain.get_tool("CP"); for(SourceList::const_iterator i=source_filenames.begin(); i!=source_filenames.end(); ++i) { FileTarget *ft; @@ -184,7 +184,7 @@ void Component::create_targets() const } else if(type==DATAPACK) { - const Tool &dcomp = toolchain.get_tool("DATA"); + Tool &dcomp = toolchain.get_tool("DATA"); list files; for(SourceList::const_iterator i=source_filenames.begin(); i!=source_filenames.end(); ++i) @@ -214,7 +214,7 @@ void Component::create_targets() const for(SourceList::const_iterator i=source_filenames.begin(); i!=source_filenames.end(); ++i) { string ext = FS::extpart(FS::basename(*i)); - const Tool *tool = toolchain.get_tool_for_suffix(ext, true); + Tool *tool = toolchain.get_tool_for_suffix(ext, true); if(tool) { Target *src = tool->create_source(*this, *i); @@ -232,12 +232,12 @@ void Component::create_targets() const } } - const Tool &linker = toolchain.get_tool("LINK"); + Tool &linker = toolchain.get_tool("LINK"); list results; if(type==LIBRARY) { - const Tool &archiver = toolchain.get_tool("AR"); + Tool &archiver = toolchain.get_tool("AR"); results.push_back(linker.create_target(objs, "shared")); results.push_back(archiver.create_target(objs)); } diff --git a/source/copy.cpp b/source/copy.cpp index 75d047d..24be942 100644 --- a/source/copy.cpp +++ b/source/copy.cpp @@ -16,7 +16,7 @@ Copy::Copy(Builder &b): Tool(b, "CP") { } -Target *Copy::create_target(const list &sources, const string &arg) const +Target *Copy::create_target(const list &sources, const string &arg) { FileTarget &file_tgt = dynamic_cast(*sources.front()); InstalledFile *inst = new InstalledFile(builder, *file_tgt.get_package(), file_tgt, arg); diff --git a/source/copy.h b/source/copy.h index 3aa10a9..dedd0f5 100644 --- a/source/copy.h +++ b/source/copy.h @@ -31,7 +31,7 @@ private: public: Copy(Builder &); - virtual Target *create_target(const std::list &, const std::string &) const; + virtual Target *create_target(const std::list &, const std::string &); virtual Task *run(const Target &) const; }; diff --git a/source/datatool.cpp b/source/datatool.cpp index a956984..4a4fc8a 100644 --- a/source/datatool.cpp +++ b/source/datatool.cpp @@ -16,10 +16,6 @@ using namespace Msp; DataTool::DataTool(Builder &b): Tool(b, "DATA") { - executable = builder.get_vfs().find_binary("mspdatatool"); - if(!executable) - builder.problem(string(), format("Can't find executable mspdatatool for tool %s", tag)); - input_suffixes.push_back(".mdt"); } @@ -28,7 +24,7 @@ Target *DataTool::create_source(const Component &comp, const FS::Path &path) con return new DataTransform(builder, comp, path); } -Target *DataTool::create_target(const list &sources, const string &arg) const +Target *DataTool::create_target(const list &sources, const string &arg) { if(arg=="collection") { @@ -52,6 +48,13 @@ Target *DataTool::create_target(const list &sources, const string &arg throw invalid_argument("DataTool::create_target"); } +void DataTool::do_prepare() +{ + executable = builder.get_vfs().find_binary("mspdatatool"); + if(!executable) + builder.problem(string(), format("Can't find executable mspdatatool for tool %s", tag)); +} + Task *DataTool::run(const Target &tgt) const { const Component &comp = *tgt.get_component(); diff --git a/source/datatool.h b/source/datatool.h index b6c4f5b..f2720c0 100644 --- a/source/datatool.h +++ b/source/datatool.h @@ -9,7 +9,10 @@ public: DataTool(Builder &); virtual Target *create_source(const Component &, const Msp::FS::Path &) const; - virtual Target *create_target(const std::list &, const std::string &) const; + virtual Target *create_target(const std::list &, const std::string &); +private: + virtual void do_prepare(); +public: virtual Task *run(const Target &) const; }; diff --git a/source/gnuarchiver.cpp b/source/gnuarchiver.cpp index 3499204..7482b0d 100644 --- a/source/gnuarchiver.cpp +++ b/source/gnuarchiver.cpp @@ -17,15 +17,10 @@ using namespace Msp; GnuArchiver::GnuArchiver(Builder &b, const Architecture &a): Tool(b, a, "AR") { - string command = "ar"; - if(architecture->is_cross()) - command = format("%s-%s", architecture->get_cross_prefix(), command); - executable = builder.get_vfs().find_binary(command); - input_suffixes.push_back(".o"); } -Target *GnuArchiver::create_target(const list &sources, const string &) const +Target *GnuArchiver::create_target(const list &sources, const string &) { if(sources.empty()) throw invalid_argument("GnuArchiver::create_target"); @@ -45,6 +40,14 @@ Target *GnuArchiver::create_target(const list &sources, const string & return lib; } +void GnuArchiver::do_prepare() +{ + string command = "ar"; + if(architecture->is_cross()) + command = format("%s-%s", architecture->get_cross_prefix(), command); + executable = builder.get_vfs().find_binary(command); +} + Task *GnuArchiver::run(const Target &target) const { const StaticLibrary &lib = dynamic_cast(target); diff --git a/source/gnuarchiver.h b/source/gnuarchiver.h index 41386f6..2c625b6 100644 --- a/source/gnuarchiver.h +++ b/source/gnuarchiver.h @@ -8,7 +8,10 @@ class GnuArchiver: public Tool public: GnuArchiver(Builder &, const Architecture &); - virtual Target *create_target(const std::list &, const std::string &) const; + virtual Target *create_target(const std::list &, const std::string &); +private: + virtual void do_prepare(); +public: virtual Task *run(const Target &) const; }; diff --git a/source/gnucompiler.cpp b/source/gnucompiler.cpp index 06ad5a9..7d1d166 100644 --- a/source/gnucompiler.cpp +++ b/source/gnucompiler.cpp @@ -14,22 +14,16 @@ using namespace std; using namespace Msp; GnuCompiler::GnuCompiler(Builder &b, const Architecture &a, const string &t, const string &c): - Tool(b, a, t) + Tool(b, a, t), + command(c) { - string command = c; - if(architecture->is_cross()) - command = format("%s-%s", architecture->get_cross_prefix(), command); - executable = builder.get_vfs().find_binary(command); - if(!executable) - builder.problem(string(), format("Can't find executable %s for tool %s", command, tag)); - if(architecture->is_native()) system_path.push_back("/usr/include"); else system_path.push_back("/usr/"+architecture->get_cross_prefix()+"/include"); } -Target *GnuCompiler::create_target(const list &sources, const string &) const +Target *GnuCompiler::create_target(const list &sources, const string &) { if(sources.size()!=1) throw invalid_argument("GnuCCompiler::create_target"); @@ -58,6 +52,15 @@ string GnuCompiler::create_build_signature(const BuildInfo &binfo) const return result; } +void GnuCompiler::do_prepare() +{ + if(architecture->is_cross()) + command = format("%s-%s", architecture->get_cross_prefix(), command); + executable = builder.get_vfs().find_binary(command); + if(!executable) + builder.problem(string(), format("Can't find executable %s for tool %s", command, tag)); +} + Task *GnuCompiler::run(const Target &target) const { const ObjectFile &object = dynamic_cast(target); diff --git a/source/gnucompiler.h b/source/gnucompiler.h index 5992876..0c283e2 100644 --- a/source/gnucompiler.h +++ b/source/gnucompiler.h @@ -12,12 +12,18 @@ appropriate type. */ class GnuCompiler: public Tool { +private: + std::string command; + protected: GnuCompiler(Builder &, const Architecture &, const std::string &, const std::string &); public: - virtual Target *create_target(const std::list &, const std::string &) const; + virtual Target *create_target(const std::list &, const std::string &); virtual std::string create_build_signature(const BuildInfo &) const; +protected: + virtual void do_prepare(); +public: virtual Task *run(const Target &) const; }; diff --git a/source/gnucxxcompiler.cpp b/source/gnucxxcompiler.cpp index 9e206cc..1926a5e 100644 --- a/source/gnucxxcompiler.cpp +++ b/source/gnucxxcompiler.cpp @@ -16,9 +16,6 @@ GnuCxxCompiler::GnuCxxCompiler(Builder &b, const Architecture &a): input_suffixes.push_back(".cpp"); input_suffixes.push_back(".cc"); aux_suffixes.push_back(".hpp"); - - if(executable) - query_version(); } void GnuCxxCompiler::query_version() @@ -50,3 +47,10 @@ Target *GnuCxxCompiler::create_source(const FS::Path &path) const { return new CSourceFile(builder, path); } + +void GnuCxxCompiler::do_prepare() +{ + GnuCompiler::do_prepare(); + if(executable) + query_version(); +} diff --git a/source/gnucxxcompiler.h b/source/gnucxxcompiler.h index 314bb51..5cdc34b 100644 --- a/source/gnucxxcompiler.h +++ b/source/gnucxxcompiler.h @@ -16,6 +16,9 @@ private: public: virtual Target *create_source(const Component &, const Msp::FS::Path &) const; virtual Target *create_source(const Msp::FS::Path &) const; + +private: + virtual void do_prepare(); }; #endif diff --git a/source/gnulinker.cpp b/source/gnulinker.cpp index 21b765b..cfdee8d 100644 --- a/source/gnulinker.cpp +++ b/source/gnulinker.cpp @@ -49,7 +49,7 @@ GnuLinker::~GnuLinker() delete cxx_linker; } -Target *GnuLinker::create_target(const list &sources, const string &arg) const +Target *GnuLinker::create_target(const list &sources, const string &arg) { if(sources.empty()) throw invalid_argument("GnuLinker::create_target"); @@ -74,7 +74,7 @@ Target *GnuLinker::create_target(const list &sources, const string &ar SharedLibrary *shlib = new SharedLibrary(builder, comp, objs); if(architecture->get_system()=="windows") { - const Tool &dlltool = builder.get_toolchain().get_tool("DLL"); + Tool &dlltool = builder.get_toolchain().get_tool("DLL"); dlltool.create_target(*shlib); } bin = shlib; @@ -89,7 +89,7 @@ Target *GnuLinker::create_install(Target &target) const { if(SharedLibrary *shlib = dynamic_cast(&target)) { - const Tool © = builder.get_toolchain().get_tool("CP"); + Tool © = builder.get_toolchain().get_tool("CP"); InstalledFile *inst_tgt = dynamic_cast(copy.create_target(target)); if(architecture->get_system()=="windows") builder.get_build_graph().add_installed_target(*shlib->get_import_library()); @@ -112,28 +112,12 @@ Task *GnuLinker::run(const Target &) const } -GnuLinker::Linker::Linker(GnuLinker &p, const string &compiler_tag): - SubTool(p) -{ - const Tool &compiler = builder.get_toolchain().get_tool(compiler_tag); - if(dynamic_cast(&compiler)) - executable = compiler.get_executable(); - else - { - string command; - if(compiler_tag=="CC") - command = "gcc"; - else if(compiler_tag=="CXX") - command = "g++"; - else - throw invalid_argument("GnuLinker::Linker::Linker"); - if(architecture->is_cross()) - command = format("%s-%s", architecture->get_cross_prefix(), command); - executable = builder.get_vfs().find_binary(command); - } -} +GnuLinker::Linker::Linker(GnuLinker &p, const string &ct): + SubTool(p), + compiler_tag(ct) +{ } -Target *GnuLinker::Linker::create_target(const list &sources, const string &arg) const +Target *GnuLinker::Linker::create_target(const list &sources, const string &arg) { return parent.create_target(sources, arg); } @@ -158,6 +142,29 @@ string GnuLinker::Linker::create_build_signature(const BuildInfo &binfo) const return result; } +void GnuLinker::Linker::do_prepare() +{ + Tool &compiler = builder.get_toolchain().get_tool(compiler_tag); + if(dynamic_cast(&compiler)) + { + compiler.prepare(); + executable = compiler.get_executable(); + } + else + { + string command; + if(compiler_tag=="CC") + command = "gcc"; + else if(compiler_tag=="CXX") + command = "g++"; + else + throw invalid_argument("GnuLinker::Linker::Linker"); + if(architecture->is_cross()) + command = format("%s-%s", architecture->get_cross_prefix(), command); + executable = builder.get_vfs().find_binary(command); + } +} + Task *GnuLinker::Linker::run(const Target &target) const { const Binary &bin = dynamic_cast(target); diff --git a/source/gnulinker.h b/source/gnulinker.h index 07e6a0c..4673c07 100644 --- a/source/gnulinker.h +++ b/source/gnulinker.h @@ -15,12 +15,18 @@ class GnuLinker: public Tool private: class Linker: public SubTool { + private: + std::string compiler_tag; + public: Linker(GnuLinker &, const std::string &); - virtual Target *create_target(const std::list &, const std::string &) const; + virtual Target *create_target(const std::list &, const std::string &); virtual Target *create_install(Target &) const; virtual std::string create_build_signature(const BuildInfo &) const; + private: + virtual void do_prepare(); + public: virtual Task *run(const Target &) const; }; @@ -31,7 +37,7 @@ public: GnuLinker(Builder &, const Architecture &); ~GnuLinker(); - virtual Target *create_target(const std::list &, const std::string &) const; + virtual Target *create_target(const std::list &, const std::string &); virtual Target *create_install(Target &) const; virtual Task *run(const Target &) const; }; diff --git a/source/mingwdlltool.cpp b/source/mingwdlltool.cpp index 5f62a02..f44f575 100644 --- a/source/mingwdlltool.cpp +++ b/source/mingwdlltool.cpp @@ -18,14 +18,9 @@ using namespace Msp; MingwDllTool::MingwDllTool(Builder &b, const Architecture &a): Tool(b, a, "DLL") -{ - string command = "dlltool"; - if(architecture->is_cross()) - command = format("%s-%s", architecture->get_cross_prefix(), command); - executable = builder.get_vfs().find_binary(command); -} +{ } -Target *MingwDllTool::create_target(const list &sources, const string &) const +Target *MingwDllTool::create_target(const list &sources, const string &) { if(sources.size()!=1) throw invalid_argument("MingwDllTool::create_target"); @@ -50,7 +45,7 @@ Target *MingwDllTool::create_install(Target &target) const { if(ImportLibrary *imp = dynamic_cast(&target)) { - const Tool © = builder.get_toolchain().get_tool("CP"); + Tool © = builder.get_toolchain().get_tool("CP"); InstalledFile *inst_tgt = dynamic_cast(copy.create_target(target)); string link_name = format("lib%s.dll.a", imp->get_shared_library()->get_libname()); if(link_name!=FS::basename(inst_tgt->get_path())) @@ -61,6 +56,14 @@ Target *MingwDllTool::create_install(Target &target) const return 0; } +void MingwDllTool::do_prepare() +{ + string command = "dlltool"; + if(architecture->is_cross()) + command = format("%s-%s", architecture->get_cross_prefix(), command); + executable = builder.get_vfs().find_binary(command); +} + Task *MingwDllTool::run(const Target &target) const { const ImportLibrary *imp = dynamic_cast(&target); diff --git a/source/mingwdlltool.h b/source/mingwdlltool.h index 25a1e10..796da75 100644 --- a/source/mingwdlltool.h +++ b/source/mingwdlltool.h @@ -8,9 +8,13 @@ class MingwDllTool: public Tool public: MingwDllTool(Builder &, const Architecture &); - virtual Target *create_target(const std::list &, const std::string &) const; + virtual Target *create_target(const std::list &, const std::string &); virtual Target *create_install(Target &) const; +private: + virtual void do_prepare(); + +public: virtual Task *run(const Target &) const; }; diff --git a/source/pkgconfiggenerator.cpp b/source/pkgconfiggenerator.cpp index b4ba545..677ef9b 100644 --- a/source/pkgconfiggenerator.cpp +++ b/source/pkgconfiggenerator.cpp @@ -13,7 +13,7 @@ PkgConfigGenerator::PkgConfigGenerator(Builder &b): { } -Target *PkgConfigGenerator::create_target(const list &, const string &) const +Target *PkgConfigGenerator::create_target(const list &, const string &) { throw logic_error("Not implemented"); } diff --git a/source/pkgconfiggenerator.h b/source/pkgconfiggenerator.h index 14ba317..a9adbc6 100644 --- a/source/pkgconfiggenerator.h +++ b/source/pkgconfiggenerator.h @@ -26,7 +26,7 @@ private: public: PkgConfigGenerator(Builder &); - virtual Target *create_target(const std::list &, const std::string &) const; + virtual Target *create_target(const std::list &, const std::string &); virtual Task *run(const Target &) const; }; diff --git a/source/tar.cpp b/source/tar.cpp index ac2f9e8..bcaa852 100644 --- a/source/tar.cpp +++ b/source/tar.cpp @@ -15,7 +15,7 @@ Tar::Tar(Builder &b): Tool(b, "TAR") { } -Target *Tar::create_target(const list &sources, const string &arg) const +Target *Tar::create_target(const list &sources, const string &arg) { if(!sources.front()->get_package()) throw invalid_argument("Tar::create_target"); diff --git a/source/tar.h b/source/tar.h index c11587e..9be26d9 100644 --- a/source/tar.h +++ b/source/tar.h @@ -26,7 +26,7 @@ private: public: Tar(Builder &); - virtual Target *create_target(const std::list &, const std::string &) const; + virtual Target *create_target(const std::list &, const std::string &); virtual Task *run(const Target &) const; }; diff --git a/source/target.cpp b/source/target.cpp index a9ad8e7..87b0d00 100644 --- a/source/target.cpp +++ b/source/target.cpp @@ -64,7 +64,7 @@ Target *Target::get_buildable_target() return 0; } -void Target::set_tool(const Tool &t) +void Target::set_tool(Tool &t) { tool = &t; for(Dependencies::const_iterator i=side_effects.begin(); i!=side_effects.end(); ++i) @@ -102,12 +102,12 @@ void Target::prepare() } state = PREPARING; + if(tool) + tool->prepare(); find_dependencies(); if(tool) - { if(FileTarget *tool_exe = tool->get_executable()) add_dependency(*tool_exe); - } for(Dependencies::iterator i=depends.begin(); i!=depends.end(); ++i) (*i)->prepare(); diff --git a/source/target.h b/source/target.h index 0b9d230..eda77d0 100644 --- a/source/target.h +++ b/source/target.h @@ -42,7 +42,7 @@ protected: const Component *component; std::string name; - const Tool *tool; + Tool *tool; State state; std::string rebuild_reason; @@ -95,7 +95,7 @@ public: the function recursively to find the final target. */ virtual Target *get_real_target() { return this; } - void set_tool(const Tool &); + void set_tool(Tool &); /** Returns the tool used to build the target. To actually build it, call the build() function. */ diff --git a/source/tool.cpp b/source/tool.cpp index cefbb8c..a23de63 100644 --- a/source/tool.cpp +++ b/source/tool.cpp @@ -7,14 +7,16 @@ Tool::Tool(Builder &b, const string &t): builder(b), architecture(0), tag(t), - executable(0) + executable(0), + prepared(false) { } Tool::Tool(Builder &b, const Architecture &a, const string &t): builder(b), architecture(&a), tag(t), - executable(0) + executable(0), + prepared(false) { } bool Tool::accepts_suffix(const string &suffix, bool aux) const @@ -27,13 +29,22 @@ bool Tool::accepts_suffix(const string &suffix, bool aux) const return false; } -Target *Tool::create_target(Target &source, const string &arg) const +Target *Tool::create_target(Target &source, const string &arg) { list sources; sources.push_back(&source); return create_target(sources, arg); } +void Tool::prepare() +{ + if(prepared) + return; + + prepared = true; + do_prepare(); +} + SubTool::SubTool(Tool &p): Tool(p), diff --git a/source/tool.h b/source/tool.h index 2948053..73be90d 100644 --- a/source/tool.h +++ b/source/tool.h @@ -31,6 +31,7 @@ protected: SuffixList input_suffixes; SuffixList aux_suffixes; SearchPath system_path; + bool prepared; Tool(Builder &, const std::string &); Tool(Builder &, const Architecture &, const std::string &); @@ -41,7 +42,6 @@ public: /** Returns a target for the tool's own executable. If the tool does not use an external program, returns null. */ - // XXX The executable target should be retrieved when first needed FileTarget *get_executable() const { return executable; } /// Returns a list of suffixes that can be processed with this tool. @@ -67,12 +67,12 @@ public: virtual Target *create_source(const Msp::FS::Path &) const { return 0; } /// Convenience function to create a target from a single source. - Target *create_target(Target &, const std::string & = std::string()) const; + Target *create_target(Target &, const std::string & = std::string()); /** Creates a target from sources. The exact types of accepted sources depends on the tool. The optional second argument can be used to select an alternative target type for tools that can create multiple kinds of targets. */ - virtual Target *create_target(const std::list &, const std::string & = std::string()) const = 0; + virtual Target *create_target(const std::list &, const std::string & = std::string()) = 0; /** Creates an install target for a target created by this tool. Can return null if the tool does not want to handle installing in a special way. */ @@ -80,6 +80,12 @@ public: virtual std::string create_build_signature(const BuildInfo &) const { return std::string(); } + void prepare(); + +protected: + virtual void do_prepare() { } + +public: /** Invokes the tool to build a target. This should not be called directly; use Target::build() instead. */ virtual Task *run(const Target &) const = 0; diff --git a/source/toolchain.cpp b/source/toolchain.cpp index cdbc7aa..9d23403 100644 --- a/source/toolchain.cpp +++ b/source/toolchain.cpp @@ -16,12 +16,12 @@ void Toolchain::add_tool(Tool *tool) insert_unique(tools, tool->get_tag(), tool); } -const Tool &Toolchain::get_tool(const string &tag) const +Tool &Toolchain::get_tool(const string &tag) const { return *get_item(tools, tag); } -const Tool *Toolchain::get_tool_for_suffix(const string &suffix, bool aux) const +Tool *Toolchain::get_tool_for_suffix(const string &suffix, bool aux) const { for(ToolMap::const_iterator i=tools.begin(); i!=tools.end(); ++i) if(i->second->accepts_suffix(suffix, aux)) diff --git a/source/toolchain.h b/source/toolchain.h index 2c0e3d2..572e42f 100644 --- a/source/toolchain.h +++ b/source/toolchain.h @@ -20,8 +20,8 @@ public: ~Toolchain(); void add_tool(Tool *); - const Tool &get_tool(const std::string &) const; - const Tool *get_tool_for_suffix(const std::string &, bool = false) const; + Tool &get_tool(const std::string &) const; + Tool *get_tool_for_suffix(const std::string &, bool = false) const; }; #endif