From: Mikko Rasa Date: Fri, 15 Sep 2023 18:54:54 +0000 (+0300) Subject: Add helper functions to process sources in a uniform way X-Git-Url: https://git.tdb.fi/?a=commitdiff_plain;h=b6df5d02e5640c5157866c08d99b16ba62be77e0;p=builder.git Add helper functions to process sources in a uniform way --- diff --git a/plugins/android/androidassetpackagingtool.cpp b/plugins/android/androidassetpackagingtool.cpp index ba321cb..da6a0a2 100644 --- a/plugins/android/androidassetpackagingtool.cpp +++ b/plugins/android/androidassetpackagingtool.cpp @@ -31,17 +31,7 @@ Target *AndroidAssetPackagingTool::create_target(const vector &sources { AndroidManifestFile *manifest = 0; vector resources; - resources.reserve(sources.size()); - for(Target *s: sources) - { - if(AndroidManifestFile *m = dynamic_cast(s)) - manifest = m; - else if(FileTarget *f = dynamic_cast(s)) - resources.push_back(f); - } - - if(!manifest) - throw invalid_argument("AndroidAssetPackagingTool::create_target"); + extract_sources(sources, required(manifest), resources); AndroidResourceBundle *res = new AndroidResourceBundle(builder, *manifest->get_component(), *manifest, resources); res->set_tool(*this); diff --git a/plugins/android/apkbuilder.cpp b/plugins/android/apkbuilder.cpp index ec20854..b262d18 100644 --- a/plugins/android/apkbuilder.cpp +++ b/plugins/android/apkbuilder.cpp @@ -25,14 +25,8 @@ Target *ApkBuilder::create_target(const vector &sources, const string { AndroidResourceBundle *resource_bundle = 0; vector other_files; - other_files.reserve(sources.size()); - for(Target *s: sources) - { - if(AndroidResourceBundle *r = dynamic_cast(s)) - resource_bundle = r; - else if(FileTarget *f = dynamic_cast(s)) - other_files.push_back(f); - } + extract_sources(sources, required(resource_bundle), other_files); + AndroidPackageFile *apk = new AndroidPackageFile(builder, *resource_bundle->get_component(), *resource_bundle, other_files); apk->set_tool(*this); return apk; diff --git a/plugins/base/copy.cpp b/plugins/base/copy.cpp index 0633ff9..0a82d38 100644 --- a/plugins/base/copy.cpp +++ b/plugins/base/copy.cpp @@ -22,8 +22,10 @@ Copy::Copy(Builder &b): Target *Copy::create_target(const vector &sources, const string &arg) { - FileTarget &file_tgt = dynamic_cast(*sources.front()); - InstalledFile *inst = new InstalledFile(builder, *file_tgt.get_package(), file_tgt, arg); + FileTarget *file_tgt = 0; + extract_sources(sources, required(file_tgt)); + + InstalledFile *inst = new InstalledFile(builder, *file_tgt->get_package(), *file_tgt, arg); inst->set_tool(*this); return inst; } diff --git a/plugins/datafile/datatool.cpp b/plugins/datafile/datatool.cpp index 04592e3..71a7768 100644 --- a/plugins/datafile/datatool.cpp +++ b/plugins/datafile/datatool.cpp @@ -29,21 +29,18 @@ Target *DataTool::create_target(const vector &sources, const string &a { if(arg=="collection") { - if(sources.size()!=1) - throw invalid_argument("DataTool::create_target"); - DataTransform &source = dynamic_cast(*sources.front()); - DataCollection *coll = new DataCollection(builder, *source.get_component(), source); + DataTransform *source = 0; + extract_sources(sources, required(source)); + + DataCollection *coll = new DataCollection(builder, *source->get_component(), *source); coll->set_tool(*this); return coll; } else if(arg=="pack") { - if(sources.empty()) - throw invalid_argument("DataTool::create_target"); vector files; - files.reserve(sources.size()); - for(Target *t: sources) - files.push_back(&dynamic_cast(*t)); + extract_sources(sources, required(files)); + DataPack *pack = new DataPack(builder, *files.front()->get_component(), files); pack->set_tool(*this); return pack; diff --git a/plugins/gnu/gnuarchiver.cpp b/plugins/gnu/gnuarchiver.cpp index c977eaa..4f21674 100644 --- a/plugins/gnu/gnuarchiver.cpp +++ b/plugins/gnu/gnuarchiver.cpp @@ -22,13 +22,8 @@ GnuArchiver::GnuArchiver(Builder &b, const Architecture &a): Target *GnuArchiver::create_target(const vector &sources, const string &) { - if(sources.empty()) - throw invalid_argument("GnuArchiver::create_target"); - vector objs; - objs.reserve(sources.size()); - for(Target *s: sources) - objs.push_back(&dynamic_cast(*s)); + extract_sources(sources, required(objs)); const Component &comp = *objs.front()->get_component(); StaticLibrary *lib = new StaticLibrary(builder, comp, objs); diff --git a/plugins/gnu/gnucompiler.cpp b/plugins/gnu/gnucompiler.cpp index 252f394..5e89a4e 100644 --- a/plugins/gnu/gnucompiler.cpp +++ b/plugins/gnu/gnucompiler.cpp @@ -70,10 +70,10 @@ Target *GnuCompiler::create_source(const FS::Path &path) const Target *GnuCompiler::create_target(const vector &sources, const string &) { - if(sources.size()!=1) - throw invalid_argument("GnuCompiler::create_target"); - SourceFile &source = dynamic_cast(*sources.front()); - ObjectFile *obj = new ObjectFile(builder, *source.get_component(), source); + SourceFile *source = 0; + extract_sources(sources, required(source)); + + ObjectFile *obj = new ObjectFile(builder, *source->get_component(), *source); obj->set_tool(*this); return obj; } diff --git a/plugins/gnu/gnulinker.cpp b/plugins/gnu/gnulinker.cpp index 3d81fcc..95e74fd 100644 --- a/plugins/gnu/gnulinker.cpp +++ b/plugins/gnu/gnulinker.cpp @@ -35,25 +35,20 @@ GnuLinker::GnuLinker(Builder &b, const Architecture &a): Target *GnuLinker::create_target(const vector &sources, const string &arg) { - if(sources.empty()) - throw invalid_argument("GnuLinker::create_target"); - if(arg=="import") { - if(sources.size()!=1) - throw invalid_argument("GnuLinker::create_target"); - SharedLibrary &shlib = dynamic_cast(*sources.front()); + SharedLibrary *shlib = 0; + extract_sources(sources, required(shlib)); + if(architecture->get_system()!="windows") return 0; Tool &dlltool = builder.get_toolchain().get_tool("DLL"); - return dlltool.create_target(shlib); + return dlltool.create_target(*shlib); } vector objs; - objs.reserve(sources.size()); - for(Target *s: sources) - objs.push_back(&dynamic_cast(*s)); + extract_sources(sources, required(objs)); const Component &comp = *objs.front()->get_component(); Binary *bin = 0; diff --git a/plugins/gnu/mingwdlltool.cpp b/plugins/gnu/mingwdlltool.cpp index a3fdadb..bf869cc 100644 --- a/plugins/gnu/mingwdlltool.cpp +++ b/plugins/gnu/mingwdlltool.cpp @@ -24,20 +24,20 @@ MingwDllTool::MingwDllTool(Builder &b, const Architecture &a): Target *MingwDllTool::create_target(const vector &sources, const string &) { - if(sources.size()!=1) - throw invalid_argument("MingwDllTool::create_target"); - SharedLibrary &shlib = dynamic_cast(*sources.front()); + SharedLibrary *shlib = 0; + extract_sources(sources, required(shlib)); vector objs; - objs.reserve(shlib.get_dependencies().size()); - for(Target *d: shlib.get_dependencies()) - if(ObjectFile *obj = dynamic_cast(d)) - objs.push_back(obj); + ExportDefinitions *exp = 0; + extract_sources(shlib->get_dependencies(), objs, exp); - ExportDefinitions *exp = new ExportDefinitions(builder, *shlib.get_component(), objs); - exp->set_tool(*this); + if(!exp) + { + exp = new ExportDefinitions(builder, *shlib->get_component(), objs); + exp->set_tool(*this); + } - ImportLibrary *imp = new ImportLibrary(builder, *shlib.get_component(), shlib); + ImportLibrary *imp = new ImportLibrary(builder, *shlib->get_component(), *shlib); imp->add_dependency(*exp); imp->set_tool(*this); diff --git a/plugins/msvc/msvcarchiver.cpp b/plugins/msvc/msvcarchiver.cpp index 2434eeb..b8d3d19 100644 --- a/plugins/msvc/msvcarchiver.cpp +++ b/plugins/msvc/msvcarchiver.cpp @@ -21,13 +21,8 @@ MsvcArchiver::MsvcArchiver(Builder &b, const Architecture &a, const MicrosoftToo Target *MsvcArchiver::create_target(const vector &sources, const string &) { - if(sources.empty()) - throw invalid_argument("MsvcArchiver::create_target"); - vector objs; - objs.reserve(sources.size()); - for(Target *s: sources) - objs.push_back(&dynamic_cast(*s)); + extract_sources(sources, required(objs)); const Component &comp = *objs.front()->get_component(); StaticLibrary *lib = new StaticLibrary(builder, comp, objs); diff --git a/plugins/msvc/msvccompiler.cpp b/plugins/msvc/msvccompiler.cpp index 9eac872..bb94634 100644 --- a/plugins/msvc/msvccompiler.cpp +++ b/plugins/msvc/msvccompiler.cpp @@ -48,10 +48,10 @@ Target *MsvcCompiler::create_source(const FS::Path &path) const Target *MsvcCompiler::create_target(const vector &sources, const string &) { - if(sources.size()!=1) - throw invalid_argument("MsvcCompiler::create_target"); - SourceFile &source = dynamic_cast(*sources.front()); - ObjectFile *obj = new ObjectFile(builder, *source.get_component(), source); + SourceFile *source = 0; + extract_sources(sources, source); + + ObjectFile *obj = new ObjectFile(builder, *source->get_component(), *source); obj->set_tool(*this); return obj; } diff --git a/plugins/msvc/msvclinker.cpp b/plugins/msvc/msvclinker.cpp index 8f0ac94..a9ada99 100644 --- a/plugins/msvc/msvclinker.cpp +++ b/plugins/msvc/msvclinker.cpp @@ -31,27 +31,21 @@ MsvcLinker::MsvcLinker(Builder &b, const Architecture &a, const MicrosoftTools & Target *MsvcLinker::create_target(const vector &sources, const string &arg) { - if(sources.empty()) - throw invalid_argument("MsvcLinker::create_target"); - if(arg=="import") { - if(sources.size()!=1) - throw invalid_argument("MsvcLinker::create_target"); - SharedLibrary &shlib = dynamic_cast(*sources.front()); + SharedLibrary *shlib = 0; + extract_sources(sources, required(shlib)); - ImportLibrary *imp = new ImportLibrary(builder, *shlib.get_component(), shlib); - for(ObjectFile *o: shlib.get_objects()) + ImportLibrary *imp = new ImportLibrary(builder, *shlib->get_component(), *shlib); + for(ObjectFile *o: shlib->get_objects()) imp->add_dependency(*o); - shlib.add_side_effect(*imp); + shlib->add_side_effect(*imp); return imp; } vector objs; - objs.reserve(sources.size()); - for(Target *s: sources) - objs.push_back(&dynamic_cast(*s)); + extract_sources(sources, required(objs)); const Component &comp = *objs.front()->get_component(); Binary *bin = 0; diff --git a/source/lib/tool.cpp b/source/lib/tool.cpp index eaf4977..2aa47e2 100644 --- a/source/lib/tool.cpp +++ b/source/lib/tool.cpp @@ -37,6 +37,11 @@ Target *Tool::create_target(Target &source, const string &arg) return create_target(sources, arg); } +void Tool::extract_source(Target *source) const +{ + throw logic_error(format("%s can't process %s", tag, source->get_type())); +} + void Tool::prepare() { if(prepared) diff --git a/source/lib/tool.h b/source/lib/tool.h index 5921c2d..ce631da 100644 --- a/source/lib/tool.h +++ b/source/lib/tool.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "buildinfo.h" #include "externaltask.h" #include "internaltask.h" @@ -43,6 +44,12 @@ public: }; protected: + template + struct RequiredSource + { + T &ref; + }; + Builder &builder; const Architecture *architecture = 0; std::string tag; @@ -130,6 +137,37 @@ public: alternative target type for tools that can create multiple kinds of targets. */ virtual Target *create_target(const std::vector &, const std::string & = std::string()) = 0; +protected: + template + void extract_sources(const std::vector &, Ts &...) const; + + template + const RequiredSource required(T &s) const { return { s }; } + +private: + void extract_source(Target *) const; + + template + void extract_source(Target *, T *&, Rest &...) const; + + template + void extract_source(Target *, std::vector &, Rest &...) const; + + template + void extract_source(Target *s, const RequiredSource &t, Rest &... r) const { extract_source(s, t.ref, r...); } + + bool check_required_sources() const { return true; } + + template + bool check_required_sources(const RequiredSource &, Rest &...) const; + + template + bool check_required_sources(const RequiredSource> &, Rest &...) const; + + template + bool check_required_sources(T &, Rest &... rest) const { return check_required_sources(rest...); } + +public: /** 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. */ virtual Target *create_install(Target &) const { return 0; } @@ -171,6 +209,49 @@ void Tool::set_run_internal(bool (*f)(const T &)) }); } +template +void Tool::extract_sources(const std::vector &sources, Ts &... store) const +{ + for(Target *t: sources) + extract_source(t, store...); + if(!check_required_sources(store...)) + throw std::logic_error(Msp::format("required sources missing for %s", tag)); +} + +template +void Tool::extract_source(Target *source, T *&store, Rest &... rest) const +{ + if(T *cast_src = dynamic_cast(source)) + { + if(store) + throw std::logic_error(Msp::format("extraneous %s given to %s", source->get_type(), tag)); + store = cast_src; + } + else + extract_source(source, rest...); +} + +template +void Tool::extract_source(Target *source, std::vector &store, Rest &... rest) const +{ + if(T *cast_src = dynamic_cast(source)) + store.push_back(cast_src); + else + extract_source(source, rest...); +} + +template +bool Tool::check_required_sources(const RequiredSource &store, Rest &... rest) const +{ + return store.ref && check_required_sources(rest...); +} + +template +bool Tool::check_required_sources(const RequiredSource> &store, Rest &... rest) const +{ + return !store.ref.empty() && check_required_sources(rest...); +} + void operator>>(const Msp::LexicalConverter &, Tool::ProcessingUnit &);