]> git.tdb.fi Git - builder.git/commitdiff
Add support for generating source files
authorMikko Rasa <tdb@tdb.fi>
Tue, 20 Aug 2013 15:17:56 +0000 (18:17 +0300)
committerMikko Rasa <tdb@tdb.fi>
Tue, 20 Aug 2013 15:17:56 +0000 (18:17 +0300)
source/component.cpp
source/installmap.cpp
source/sourcegenerator.cpp [new file with mode: 0644]
source/sourcegenerator.h [new file with mode: 0644]
source/sourcepackage.cpp
source/sourcepackage.h
source/templatefile.cpp [new file with mode: 0644]
source/templatefile.h [new file with mode: 0644]

index 5f50a6525b349eb921a04648cfd7bc44ad224384..d23e1b3d1cc34825250b44b81570094514c69682 100644 (file)
@@ -210,13 +210,28 @@ void Component::create_targets() const
        if(type==PROGRAM || type==LIBRARY || type==MODULE)
        {
                list<Target *> objs;
+               const Toolchain &pkg_tools = package.get_toolchain();
                for(SourceList::const_iterator i=source_filenames.begin(); i!=source_filenames.end(); ++i)
                {
                        string ext = FS::extpart(FS::basename(*i));
+                       Target *src = 0;
+
+                       Tool *gen = pkg_tools.get_tool_for_suffix(ext);
+                       if(gen)
+                       {
+                               Target *tmpl = gen->create_source(*this, *i);
+                               if(tmpl)
+                               {
+                                       src = gen->create_target(*tmpl);
+                                       ext = FS::extpart(FS::basename(dynamic_cast<FileTarget &>(*src).get_path()));
+                               }
+                       }
+
                        Tool *tool = toolchain.get_tool_for_suffix(ext, true);
                        if(tool)
                        {
-                               Target *src = tool->create_source(*this, *i);
+                               if(!src)
+                                       src = tool->create_source(*this, *i);
                                if(!src)
                                        continue;
 
@@ -226,8 +241,16 @@ void Component::create_targets() const
                                        objs.push_back(obj);
                                }
 
-                               if(type==LIBRARY && install && dynamic_cast<FileTarget *>(src)->is_installable())
-                                       build_graph.add_installed_target(*src);
+                               if(type==LIBRARY && install)
+                               {
+                                       if(dynamic_cast<FileTarget *>(src)->is_installable())
+                                               build_graph.add_installed_target(*src);
+
+                                       const Target::Dependencies &side_effects = src->get_side_effects();
+                                       for(Target::Dependencies::const_iterator j=side_effects.begin(); j!=side_effects.end(); ++j)
+                                               if(dynamic_cast<FileTarget *>(*j)->is_installable())
+                                                       build_graph.add_installed_target(**j);
+                               }
                        }
                }
 
index 942b932b98c29babf1fd0d59eb090d53cb1cda30..8f1995bc905c3a4a6d38dfea113958570191712e 100644 (file)
@@ -2,6 +2,8 @@
 #include "component.h"
 #include "filetarget.h"
 #include "installmap.h"
+#include "sourcepackage.h"
+#include "templatefile.h"
 
 using namespace std;
 using namespace Msp;
@@ -20,6 +22,7 @@ FS::Path InstallMap::get_install_location(const FileTarget &target) const
        unsigned overlay_depth = 0;
        if(comp && !comp->get_overlays().empty())
        {
+               // Check if the target resides in an overlay directory
                const Component::OverlayList &overlays = comp->get_overlays();
                string last_dir = FS::basename(FS::dirname(target.get_path()));
                for(Component::OverlayList::const_iterator i=overlays.begin(); i!=overlays.end(); ++i)
@@ -27,7 +30,28 @@ FS::Path InstallMap::get_install_location(const FileTarget &target) const
                                overlay_depth = 1;
        }
 
-       const FS::Path &source = target.get_path();
+       FS::Path source = target.get_path();
+       if(comp)
+       {
+               /* Check if the target is a generated source file, residing in the
+               temporary directory */
+               const SourcePackage &pkg = comp->get_package();
+               int temp_depth = FS::descendant_depth(source, pkg.get_temp_directory());
+               if(temp_depth>0)
+               {
+                       // If it is, use the generating template's directory instead
+                       const Target::Dependencies &deps = target.get_dependencies();
+                       for(Target::Dependencies::const_iterator i=deps.begin(); i!=deps.end(); ++i)
+                               if(const TemplateFile *tmpl = dynamic_cast<const TemplateFile *>(*i))
+                               {
+                                       source = FS::dirname(tmpl->get_path())/FS::basename(source);
+                                       break;
+                               }
+               }
+       }
+
+       /* Look for a mapping entry matching both the target's original location
+       and default install location */
        FS::Path install = target.get_install_location();
        for(list<Entry>::const_iterator i=entries.begin(); i!=entries.end(); ++i)
        {
diff --git a/source/sourcegenerator.cpp b/source/sourcegenerator.cpp
new file mode 100644 (file)
index 0000000..c09e5c7
--- /dev/null
@@ -0,0 +1,100 @@
+#include <msp/fs/utils.h>
+#include "builder.h"
+#include "executable.h"
+#include "externaltask.h"
+#include "sourcegenerator.h"
+#include "sourcepackage.h"
+#include "templatefile.h"
+
+using namespace std;
+using namespace Msp;
+
+SourceGenerator::SourceGenerator(Builder &b, const SourcePackage &p, const string &t):
+       Tool(b, t),
+       package(p)
+{ }
+
+Target *SourceGenerator::create_source(const Component &comp, const FS::Path &path) const
+{
+       return new TemplateFile(builder, comp, path);
+}
+
+Target *SourceGenerator::create_target(const list<Target *> &sources, const string &)
+{
+       if(sources.size()!=1)
+               throw invalid_argument("SourceGenerator::create_target");
+
+       TemplateFile &tmpl = dynamic_cast<TemplateFile &>(*sources.front());
+       const Component *comp = tmpl.get_component();
+       const SourcePackage *pkg = tmpl.get_package();
+       string base = FS::basepart(FS::basename(tmpl.get_path()));
+
+       Target *primary = 0;
+       for(list<string>::const_iterator i=out_suffixes.begin(); i!=out_suffixes.end(); ++i)
+       {
+               Tool *tool = builder.get_toolchain().get_tool_for_suffix(*i, true);
+               if(tool)
+               {
+                       FS::Path fn = pkg->get_temp_directory()/comp->get_name()/(base+*i);
+                       Target *target = tool->create_source(*comp, fn);
+                       target->set_tool(*this);
+                       target->add_dependency(tmpl);
+                       if(primary)
+                               primary->add_side_effect(*target);
+                       else
+                               primary = target;
+               }
+       }
+
+       return primary;
+}
+
+void SourceGenerator::do_prepare()
+{
+       FS::Path exe_fn = package.get_source_directory()/command;
+       executable = builder.get_vfs().get_target(exe_fn);
+       if(!executable)
+               executable = new Executable(builder, exe_fn);
+}
+
+Task *SourceGenerator::run(const Target &target) const
+{
+       const SourceFile &out_src = dynamic_cast<const SourceFile &>(target);
+       const FS::Path &work_dir = out_src.get_package()->get_source_directory();
+
+       vector<string> args;
+       args.push_back(executable->get_path().str());
+
+       const Target::Dependencies &deps = target.get_dependencies();
+       for(Target::Dependencies::const_iterator i=deps.begin(); i!=deps.end(); ++i)
+               if(const TemplateFile *tmpl = dynamic_cast<const TemplateFile *>(*i))
+                       args.push_back(FS::relative(tmpl->get_path(), work_dir).str());
+
+       args.push_back(FS::relative(out_src.get_path(), work_dir).str());
+
+       return new ExternalTask(args, work_dir);
+}
+
+
+SourceGenerator::Loader::Loader(SourceGenerator &sg):
+       DataFile::ObjectLoader<SourceGenerator>(sg)
+{
+       add("command",    &Loader::command);
+       add("in_suffix",  &Loader::in_suffix);
+       add("out_suffix", &Loader::out_suffix);
+}
+
+void SourceGenerator::Loader::command(const string &c)
+{
+       obj.set_command(c);
+}
+
+void SourceGenerator::Loader::in_suffix(const string &s)
+{
+       obj.input_suffixes.push_back(s);
+}
+
+void SourceGenerator::Loader::out_suffix(const string &s)
+{
+       obj.out_suffixes.push_back(s);
+}
diff --git a/source/sourcegenerator.h b/source/sourcegenerator.h
new file mode 100644 (file)
index 0000000..b3c00e4
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef SOURCEGENERATOR_H_
+#define SOURCEGENERATOR_H_
+
+#include <msp/datafile/objectloader.h>
+#include "sourcepackage.h"
+#include "tool.h"
+
+class SourceGenerator: public Tool
+{
+public:
+       class Loader: public Msp::DataFile::ObjectLoader<SourceGenerator>
+       {
+       public:
+               Loader(SourceGenerator &);
+
+       private:
+               void command(const std::string &);
+               void in_suffix(const std::string &);
+               void out_suffix(const std::string &);
+       };
+
+private:
+       const SourcePackage &package;
+       std::list<std::string> out_suffixes;
+
+public:
+       SourceGenerator(Builder &, const SourcePackage &, const std::string &);
+
+       virtual Target *create_source(const Component &, const Msp::FS::Path &) const;
+       virtual Target *create_target(const std::list<Target *> &, const std::string &);
+
+private:
+       virtual void do_prepare();
+
+public:
+       virtual Task *run(const Target &) const;
+};
+
+#endif
index e3f11097bfd7693f8333c7c82eca5c227fc45832..e5a2fa70cdee47934441d4471335d4dbc9638901 100644 (file)
@@ -8,6 +8,7 @@
 #include "file.h"
 #include "pkgconfigfile.h"
 #include "tool.h"
+#include "sourcegenerator.h"
 #include "sourcepackage.h"
 
 using namespace std;
@@ -166,6 +167,7 @@ void SourcePackage::Loader::init(const Config::InputOptions *o)
        add("description", &SourcePackage::description);
        add("build_info",  &Loader::build_info);
        add("feature",     &Loader::feature);
+       add("generate",    &Loader::generate);
        add("if_feature",  &Loader::if_feature);
        add("program",     &Loader::component<Component::PROGRAM>);
        add("library",     &Loader::component<Component::LIBRARY>);
@@ -213,6 +215,13 @@ void SourcePackage::Loader::build_info()
        load_sub(obj.build_info);
 }
 
+void SourcePackage::Loader::generate(const string &tag)
+{
+       SourceGenerator *gen = new SourceGenerator(obj.builder, obj, tag);
+       load_sub(*gen);
+       obj.local_tools.add_tool(gen);
+}
+
 void SourcePackage::Loader::if_feature(const string &cond)
 {
        bool match = obj.match_feature(cond);
index 1e0e5f9cde5b76cff7a5c282e195e9e2dba879fb..1333bdb5ca536a75946a5a4108e4d6acf0fe9c8a 100644 (file)
@@ -9,6 +9,7 @@
 #include "config.h"
 #include "feature.h"
 #include "package.h"
+#include "toolchain.h"
 
 class Builder;
 class BuildType;
@@ -42,6 +43,7 @@ public:
                template<Component::Type>
                void component(const std::string &);
                void build_info();
+               void generate(const std::string &);
                void if_feature(const std::string &);
                void interface_version(const std::string &);
                void source_tarball();
@@ -61,6 +63,7 @@ private:
        FileTarget *build_file;
        Msp::FS::Path source_dir;
        const BuildType *build_type;
+       Toolchain local_tools;
        FeatureList features;
        BuildInfo build_info;
        ComponentList components;
@@ -80,6 +83,7 @@ public:
        Msp::FS::Path get_temp_directory() const;
        Msp::FS::Path get_output_directory() const;
 
+       const Toolchain &get_toolchain() const { return local_tools; }
        const ComponentList &get_components() const { return components; }
        const Config &get_config() const { return config; }
        bool match_feature(const std::string &) const;
diff --git a/source/templatefile.cpp b/source/templatefile.cpp
new file mode 100644 (file)
index 0000000..f5bfcb5
--- /dev/null
@@ -0,0 +1,7 @@
+#include "templatefile.h"
+
+using namespace Msp;
+
+TemplateFile::TemplateFile(Builder &b, const Component &c, const FS::Path &p):
+       SourceFile(b, c, p)
+{ }
diff --git a/source/templatefile.h b/source/templatefile.h
new file mode 100644 (file)
index 0000000..d65c8ea
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef TEMPLATEFILE_H_
+#define TEMPLATEFILE_H_
+
+#include "sourcefile.h"
+
+/**
+Input file for SourceGenerator.
+*/
+class TemplateFile: public SourceFile
+{
+public:
+       TemplateFile(Builder &, const Component &, const Msp::FS::Path &);
+
+       virtual const char *get_type() const { return "TemplateFile"; }
+};
+
+#endif