Logo Search packages:      
Sourcecode: dammit version File versions  Download package

gnu_toolchain.cpp

/* Copyright 2008 Simon Richter <Simon.Richter@hogyros.de>
 *
 * Released under the GNU General Public Licence version 3.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "gnu_toolchain.hpp"

#include "parallel_node.hpp"
#include "project_node.hpp"
#include "configuration_node.hpp"
#include "input_node.hpp"
#include "temporary_node.hpp"
#include "output_node.hpp"
#include "tool_node.hpp"
#include "environment_node.hpp"
#include "action_node.hpp"

#include "const_visitor.hpp"

#include "exceptions.hpp"

namespace dammit {

namespace {

enum preferred_type
{
      static_link
};

path get_filename(node const &, configuration_node const &, preferred_type);

}

intrusive_ptr<node> gnu_toolchain::visit(parallel_node &n)
{
      for(parallel_node::node_iterator i = n.nodes.begin();
                  i != n.nodes.end();)
      {
            if(*i = (**i).apply(*this))
                  ++i;
            else
                  i = n.nodes.erase(i);
      }

      return &n;
}

intrusive_ptr<node> gnu_toolchain::visit(project_node &n)
{
      gnu_toolchain tc;

      for(project_node::node_iterator i = n.nodes.begin();
                  i != n.nodes.end();)
      {
            if(*i = (**i).apply(tc))
                  ++i;
            else
                  i = n.nodes.erase(i);
      }

      return &n;
}

intrusive_ptr<node> gnu_toolchain::visit(configuration_node &n)
{
      gnu_toolchain tc;
      tc.configuration = &n;

      for(configuration_node::node_iterator i = n.nodes.begin();
                  i != n.nodes.end();)
      {
            if(*i = (**i).apply(tc))
                  ++i;
            else
                  i = n.nodes.erase(i);
      }

      return &n;
}

intrusive_ptr<node> gnu_toolchain::visit(input_node &n)
{
      if(!configuration)
            return &n;

      path::string_type basename = boost::filesystem::basename(n.filename);
      path::string_type extension = boost::filesystem::extension(n.filename);
      if((extension == ".cc") || (extension == ".cpp"))
      {
            intrusive_ptr<action_node> action(new action_node);
            action->inputs.push_back(&n);
            intrusive_ptr<temporary_node> temporary(new temporary_node);
            temporary->directory = configuration->temporary_dir;
            temporary->filename = basename + ".o";
            temporary->action = action;
            action->cmd.executable = "g++";
            action->cmd.workingdir = configuration->temporary_dir;
            action->cmd.arguments.push_back("-W");
            action->cmd.arguments.push_back("-Wall");
            action->cmd.arguments.push_back("-g");
            action->cmd.arguments.push_back("-o");
            action->cmd.arguments.push_back(temporary->filename.string());
            action->cmd.arguments.push_back("-c");
            action->cmd.arguments.push_back((n.directory / n.filename).string());
            return temporary;
      }
      else if((extension == ".h") || (extension == ".hh") || (extension == ".hpp"))
            return 0;
      else
            return 0;
      return &n;
}

intrusive_ptr<node> gnu_toolchain::visit(temporary_node &n)
{
      return &n;
}

intrusive_ptr<node> gnu_toolchain::visit(output_node &n)
{
      if(!configuration)
            throw invalid_tree_state("output seen, but no configuration");

      if(n.action)
            return &n;

      intrusive_ptr<action_node> action(new action_node);

      switch(n.filetype)
      {
      case output_node::executable:
            action->cmd.workingdir = configuration->output_dir;
            action->cmd.executable = "g++";
            action->cmd.arguments.push_back("-W");
            action->cmd.arguments.push_back("-Wall");
            action->cmd.arguments.push_back("-g");
            action->cmd.arguments.push_back("-o");
            action->cmd.arguments.push_back(n.filename.string());
            break;
      case output_node::static_library:
            action->cmd.workingdir = configuration->output_dir;
            action->cmd.executable = "ar";
            action->cmd.arguments.push_back("-cru");
            action->cmd.arguments.push_back(n.filename.string());
            break;
      }

      for(output_node::input_iterator i = n.inputs.begin();
                  i != n.inputs.end(); ++i)
      {
            intrusive_ptr<node> input = (**i).apply(*this);
            if(input)
            {
                  action->inputs.push_back(input);
                  action->cmd.arguments.push_back(get_filename(*input, *configuration, static_link).string());
            }
      }
      n.inputs.clear();
      n.action = action;
      return &n;
}

intrusive_ptr<node> gnu_toolchain::visit(tool_node &n)
{
      return &n;
}

intrusive_ptr<node> gnu_toolchain::visit(environment_node &n)
{
      return &n;
}

intrusive_ptr<node> gnu_toolchain::visit(action_node &n)
{
      // Stop traversing when we see an action node -- everything below here
      // is already done.
      return &n;
}

namespace {

class filename_getter :
      public const_visitor
{
public:
      filename_getter(configuration_node const &current_config,
                  preferred_type preferred) :
            current_config(current_config),
            preferred(preferred),
            looking_for_output(false)
      {
            return;
      }

      virtual ~filename_getter(void) throw() { }

      virtual void visit(parallel_node const &);
      virtual void visit(project_node const &);
      virtual void visit(configuration_node const &);
      virtual void visit(input_node const &);
      virtual void visit(temporary_node const &);
      virtual void visit(output_node const &);
      virtual void visit(tool_node const &);
      virtual void visit(environment_node const &);
      virtual void visit(action_node const &);

      configuration_node const &current_config;

      path filename;
      preferred_type preferred;
      bool looking_for_output;
};

void filename_getter::visit(parallel_node const &)
{
      throw invalid_tree_state("no filename here (parallel)");
}

void filename_getter::visit(project_node const &n)
{
      for(project_node::node_const_iterator i = n.nodes.begin();
                  i != n.nodes.end(); ++i)
      {
            (**i).apply(*this);
            if(!filename.empty())
                  break;
      }
}

void filename_getter::visit(configuration_node const &n)
{
      if(current_config != n)
            return;

      looking_for_output = true;

      for(configuration_node::node_const_iterator i = n.nodes.begin();
                  i != n.nodes.end(); ++i)
      {
            (**i).apply(*this);
            if(!filename.empty())
                  break;
      }
}

void filename_getter::visit(input_node const &n)
{
      if(!looking_for_output)
            filename = n.directory / n.filename;
}

void filename_getter::visit(temporary_node const &n)
{
      if(!looking_for_output)
            filename = n.directory / n.filename;
}

void filename_getter::visit(output_node const &n)
{
      filename = n.filename;
}

void filename_getter::visit(tool_node const &)
{
      throw invalid_tree_state("no filename here (tool)");
}

void filename_getter::visit(environment_node const &)
{
      throw invalid_tree_state("no filename here (environment)");
}

void filename_getter::visit(action_node const &)
{
      throw invalid_tree_state("no filename here (action)");
}

path get_filename(node const &n, configuration_node const &current_config, preferred_type preferred)
{
      filename_getter getter(current_config, preferred);
      n.apply(getter);
      return getter.filename;
}

}

}

Generated by  Doxygen 1.6.0   Back to index