2005/5/9

     
 

PlattformSelectTask.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 

#include "PlattformSelectTask.h"
#include "LookupFileTask.h"
#include "ShellExecuteTask.h"

#include <acdk/lang/System.h>
#include <acdk/io/NullWriter.h>
#include <acdk/io/StringWriter.h>
#include <acdk/cfgscript/Script.h>


namespace acdk {
namespace make {

using namespace acdk::cfgscript;



RStringArray 
PlattformSelectTask::getAvailableTargets(IN(RProps) globals)
{
  initTargetProps(globals);
  return _targetProps->getKeys();
}


RProps 
PlattformSelectTask::getTargetSpecs(IN(RProps) globals, IN(RString) targetname)
{
  initTargetProps(globals);
  return _targetProps->getProps(targetname);
}

void _initTargetProps(IN(RProps) target, IN(RProps) source, IN(RProps) master)
{
  RStringArray keys = source->getKeys();
  
  if (source->hasValue("_parent") == true)
  {
    RStringArray p = source->getStringArrayVal("_parent");
    for (int j = 0; j < p->length(); ++j)
    {
      _initTargetProps(target, master->getProps(p[j]), master);
    }
  }
  for (int i = 0; i < keys->length(); ++i)
  {
    RString k = keys[i];
    if (k->equals("_parent") == false)
    {
      if (k->equals("AMAKE_TARGET") == true)
      {
        //master->appendStringArrayVal("AMAKE_TARGET_TAGS", source->getStringVal(k), PropsNoStringDups | PropsNoParentWrite);
        target->appendStringArrayVal("AMAKE_TARGET_TAGS", source->getStringVal(k), PropsNoStringDups | PropsNoParentWrite | PropsNoWarnRead);
      }
      //if (source != target && target->hasValue(k) == false)
      /*if (k->equals("AMAKE_TARGET_TAGS") == true)
      {
        source->dump();
      } 
      else*/
        target->set(k, source->get(k), PropsNoParentWrite);
    }
  }
  
}

void
PlattformSelectTask::initTargetProps(IN(RProps) props)
{
  if (_targetProps != Nil)
    return;
  RProps platform = props->getProps("AMAKE_TARGET_PROPS", PropsParentRead | PropsNoWarnRead);
  RString cfgfile = "compile_specs.csf";
  Script script(cfgfile);
  
  script.currentProps = new Props("AMAKE_TARGET_PROPS", PropsParentRead | PropsNoParentWrite, props);

  script.include(cfgfile);
  RProps sourcespecs = props->getProps("AMAKE_TARGET_PROPS");
  RProps targetspecs = new Props("AMAKE_TARGET_PROPS", PropsParentRead | PropsNoParentWrite);
  RStringArray targets = sourcespecs->getKeys(PropsNoParentRead);
  for (int i = 0; i < targets->length(); ++i)
  {
    RString t = targets[i];
    RProps source = sourcespecs->getProps(t);
    RProps target = new Props(t);
    //source->dump();
    _initTargetProps(target, source, sourcespecs);
    //System::out->println("\n\n\n" + t + ":\n");
    //target->dump();
    targetspecs->setProps(t, target);
  }
  props->setProps("AMAKE_TARGET_PROPS", targetspecs);
  _targetProps = targetspecs;
}




bool
determinePlatform(IN(RProps) props)
{
  RString osstr = System::getProperties()->getProperty("OSTYPE");
  if (osstr == Nil && props->hasValue("OSTYPE", PropsParentRead) == true)
    osstr = props->getStringVal("OSTYPE", PropsParentRead);

  if (osstr == Nil)
  {
#if defined(ACDK_OS_BSD)
    osstr = "freebsd";
#elif defined(ACDK_OS_LINUX)
    osstr = "linux";
#else
/FONT>
    osstr = Nil;
#endif
/FONT>
  }
  //System::out->println("OSTYPE: " + osstr);
  /*
    if (osstr == Nil)
  {
    const char* ptr = getenv("OSTYPE");
    std::cout << "OSTYPE: " << ptr << std::endl;
    osstr = new String(ptr, String::Normal);
  }
  */
  if (osstr != Nil && (osstr->equalsIgnoreCase("linux") || 
		       osstr->equalsIgnoreCase("gnu-linux") ||
		       osstr->equalsIgnoreCase("linux-gnu")))
  {
    ACDK_NLOG("acdk.make", Info, "Select platform linux");
    props->setStringVal("OS", "linux", PropsNoFlags);
    return true;
  } 
  else if (osstr != Nil && 
	   (osstr->startsWith("freebsd") == true || 
	    osstr->startsWith("FreeBSD") == true))
  {
    ACDK_NLOG("acdk.make", Info, "Select platform bsd");
    props->setStringVal("OS", "bsd", PropsNoFlags);
    return true;
  }
  else if (osstr != Nil && osstr->startsWith("solaris") == true)
  {
    ACDK_NLOG("acdk.make", Info, "Select platform solaris");
    props->setStringVal("OS", "solaris", PropsNoFlags);
    return true;
  }
  else 
  {
    osstr = System::getProperties()->getProperty("OS");
    if (osstr != Nil && osstr->equals("Windows_NT"))
    {
      props->setStringVal("OS", "nt", PropsNoFlags);
      return true;
    } else {
      ACDK_NLOG("acdk.make", Error, 
		"Cannot determine Platform. Try to set env varialbe AMAKE_TARGET");
      return false;
    }
  }
  return false;
}



bool
locateTargetElement(IN(RProps) props, IN(RString) el)
{
  if (props->hasValue(el, PropsParentRead) == true)
    return true;
  //props->dump(0);
  RString compilername = props->getStringVal(el + "_BASENAME", PropsParentRead);
  LookupFileTask lft(compilername, Executable);
  /*
  if (props->hasValue(el + "_SPATHS") == true)
  {
  }*/
  if (lft.execute("locate", props) == false)
    return false;
  props->setStringVal(el, lft.foundPath(), PropsNoFlags);
  return true;
}

struct ParentOnStack
{
  RProps _props;
  RProps _parent;
  ParentOnStack(IN(RProps) props, IN(RProps) parent)
  : _props(props)
  , _parent(parent)
  {
    props->addParentProps(parent);
  }
  ~ParentOnStack()
  {
    _props->removeParentProps(_parent);
  }
};

RProps
locateTarget(IN(RProps) props, IN(RString) tag, bool warn = false)
{
  RProps platforms = props->getProps("AMAKE_TARGET_PROPS", PropsParentRead);
  RProps pp = platforms->getProps(tag, PropsParentRead);
  ParentOnStack _pos(pp, props);
  if (pp == Nil)
  {
    if (warn) 
      ACDK_NLOG("acdk.make", Error, "No target settings for " + tag);
    return Nil;
  }
  if (locateTargetElement(pp, "CCC_COMPILER") == false)
  {
    if (warn) 
      ACDK_NLOG("acdk.make", Error, "Cannot locate Compiler: "  + pp->getStringVal("CCC_COMPILER_BASENAME", PropsParentRead));
    return Nil;
  }
  if (locateTargetElement(pp, "CCC_LINKER") == false)
  {
    if (warn) 
      ACDK_NLOG("acdk.make", Error, "Cannot locate Linker: "  + pp->getStringVal("CCC_LINKER_BASENAME", PropsParentRead));
    return Nil;
  }
  if (locateTargetElement(pp, "CCC_AR") == false)
  {
    if (warn) 
      ACDK_NLOG("acdk.make", Error, "Cannot locate Linker: "  + pp->getStringVal("CCC_AR_BASENAME", PropsParentRead));
    return Nil;
  }
  if (locateTargetElement(pp, "SHELL") == false)
  {
    if (warn) 
      ACDK_NLOG("acdk.make", Error, "Cannot locate Shell: " + pp->getStringVal("SHELL_BASENAME", PropsParentRead));
    return Nil;
  }
  return pp;
}

bool
determineCompiler(IN(RProps) props)
{
  RString os = props->getStringVal("OS", PropsParentRead);
  RString ostype = props->getStringVal("OSTYPE", PropsParentRead);
  RProps cfgprops;
  
  if (os->equals("nt") == true)
  {
    cfgprops = locateTarget(props, "vc");
    if (cfgprops != Nil)
    {
      RShellExecuteTask sh = new ShellExecuteTask("cl", "gather version info", cfgprops->getQuotedStringVal("CCC_COMPILER", PropsParentRead), 0);
      sh->setErrWriter(new acdk::io::StringWriter());
      sh->setOutWriter(new acdk::io::StringWriter());
      sh->execute("",cfgprops);
      RString str = sh->getErrString();
      if (str->indexOf("Version 13.") != -1)
      {
        cfgprops = locateTarget(props, "vc7");
      }
      else if (str->indexOf("Version 12.") != -1)
      {
        // nothing
      } 
      else
      {
        ACDK_NLOG("acdk.make", Error, "Unknown/Unsupported MSC version: " + str);
      }
      props->merge(cfgprops, PropsMergeOverWrite);
      return true;
    }
    cfgprops = locateTarget(props, "bcc");
    if (cfgprops != Nil)
    {
      props->merge(cfgprops, PropsMergeOverWrite);
      return true;
    }
  } 
  else if (os->equals("solaris") == true || ostype->startsWith("solaris") == true)
  {
    cfgprops = locateTarget(props, "sungcc");
    if (cfgprops != Nil)
    {
      props->merge(cfgprops, PropsMergeOverWrite);
      return true;
    }
  }
  else if (os->equals("linux") == true || os->equals("bsd") == true)
  {
    cfgprops = locateTarget(props, os);
    if (cfgprops != Nil)
    {
      props->merge(cfgprops, PropsMergeOverWrite);
      return true;
    }
  }
  ACDK_NLOG("acdk.make", Error, "Cannot determine Compiler");
  return false;
}

bool
determineAcdkMc(IN(RProps) props)
{
  if (props->hasValue("ACDKMC", PropsParentRead) == true)
    return true;
  if (LookupFileTask("acdkmc", AcdkExecutable).execute(Nil, props) == false)
  {
    ACDK_NLOG("acdk.make", Warn, "Cannot find acdkmc");
    return false;
  }
  props->setStringVal("ACDKMC", props->getStringVal("_located", PropsNoFlags), PropsNoFlags);
  return true;
}


//virtual 
bool 
PlattformSelectTask::execute(IN(RString) exec, IN(RProps) props)
{
  //props->dump();
  //System::in->readLine();
  initTargetProps(props);
  //props->dump();
  RString acdkhome = props->getAcdkHome();
  props->setStringVal("ACDK_HOME", acdkhome, PropsNoFlags);
  props->setStringVal("ACDK_TOOLS_HOME", props->getAcdkToolsHome());

  if (determinePlatform(props) == false)
    return false;
  if (props->hasValue("AMAKE_TARGET", PropsParentRead) == false)
  {
    ACDK_NLOG("acdk.make", Trace, "AMAKE_TARGET not defined. Try to determine compiler");
    if (determineCompiler(props) == false)
      return false;
  } else  {
    ACDK_NLOG("acdk.make", Trace, "AMAKE_TARGET defined: " + props->getStringVal("AMAKE_TARGET", PropsParentRead));
    RProps cfgprops = locateTarget(props, props->getStringVal("AMAKE_TARGET", PropsParentRead), true);
    if (cfgprops == Nil)
      return false;
    props->merge(cfgprops, PropsMergeOverWrite);
  }
  RStringArray ptags = props->getStringArrayVal("AMAKE_TARGET_TAGS", PropsParentRead);
  ACDK_NLOG("acdk.make", Info, "Select target Tags: " + ptags->toString());

  RProps cfgprops = props->getProps("AMAKE_TARGET_PROPS", PropsParentRead)->getProps(props->getStringVal("AMAKE_TARGET", PropsParentRead), PropsParentRead);
  //RStringArray platformtags = cfgprops->getAllStringVals("AMAKE_TARGET");
  //props->setStringArrayVal("AMAKE_TARGET_TAGS", platformtags);
  props->setQuotedStringVal("CCC_COMPILER", props->getStringVal("CCC_COMPILER", PropsParentRead), PropsNoFlags);
  props->setQuotedStringVal("CCC_LINKER", props->getStringVal("CCC_LINKER", PropsParentRead), PropsNoFlags);
  props->setQuotedStringVal("CCC_AR", props->getStringVal("CCC_AR", PropsParentRead), PropsNoFlags);
  props->setQuotedStringVal("SHELL", props->getStringVal("SHELL", PropsParentRead), PropsNoFlags);
  
  determineAcdkMc(props);
  return true;
}



} // namespace make
} // namespace acdk