// Gestionnaire de compilation-linker C++ - R. Ansari 10/2000
// LAL (Orsay) / IN2P3-CNRS  DAPNIA/SPP (Saclay) / CEA

#include "cxxcmplnk.h"
#include <iostream.h>

/*!
  \class SOPHYA::CxxCompilerLinker
  \ingroup SysTools
  This classes handles the compilation of a C++ source code and 
  building of a shared library.
  The present version has been adapted for different compilers:
  g++ , Compaq/Digital cxx , SGI CC , KCC .
  \sa SOPHYA::PDynLinkMgr
  \code
  #include ""cxxcmplnk.h"
  CxxCompilerLinker cxx;
  string name = "toto.cc";
  string oname = "toto.o";
  string soname = "toto.so";
  int rc;
  // compiling file 
  rc = cxx.Compile(name, oname);
  // linking and building the shared object 
  rc = cxx.BuildSO(oname, soname);
  \endcode
*/

static char * gcxx_opt = 
"-O -Wall -Wpointer-arith -Wmissing-prototypes -Wsynth -fdollars-in-identifiers";
static char * KCC_opt = 
"-O --exceptions --rtti  --auto_instantiation --one_instantiation_per_object -D__KCC__";
static char * cxx_opt = 
"-O -no_implicit_include ";
static char * SGICC_opt =  "-O -prelink -D__SGICC__ ";

/* --Methode-- */
CxxCompilerLinker::CxxCompilerLinker()
  : verbose(false)
{
  
  string syscomp = "";

#if defined(OSF1) 
  cppFlags += "-DOSF1" ; 
  syscomp = "OSF1-";
#elif defined(Linux)
  cppFlags += "-DLinux" ;
  syscomp = "Linux-"; 
#elif defined(SunOS)
  cppFlags += "-DSunOS" ;
  syscomp = "SunOS-";  
#elif defined(IRIX64)
  cppFlags += "-DIRIX64" ;
  syscomp = "IRIX64-";  
#elif defined(AIX)
  cppFlags += "-DAIX" ;
  syscomp = "AIX-";  
#elif defined(HPUX)
  cppFlags += "-DHPUX" ;
  syscomp = "HPUX-";  
#endif


#if defined( __GNUG__ )
  compCmd = "g++ ";
  compOptions = gcxx_opt;
  linkOptions = "-O -shared";
  syscomp += "g++/"; 
#elif defined( __DECCXX )
  compCmd = "cxx ";
  compOptions = cxx_opt;
  linkOptions = compOptions + "-shared";
  syscomp += "cxx/"; 
#elif defined( __KCC__ )
  compCmd = "KCC ";
  compOptions = KCC_opt;
  linkOptions = KCC_opt;
  syscomp += "KCC/";  
#elif defined( __SGICC__ )
  compCmd = "CC ";
  compOptions = SGICC_opt;
  linkOptions = "-shared -O ";
  syscomp += "CC/";  
#ifdef SGI_ARCH64
  compOptions += " -64 -DSGI_ARCH64 ";
  linkOptions += " -64 "; 
#endif
#endif

  cppFlags += " -I. ";
  compOptions += " -c ";

  string dpcbase;
  char* varenv=NULL;
  varenv=getenv("DPCBASEREP");
  if (varenv) {
    dpcbase = varenv; 
    if (dpcbase[dpcbase.length()-1] != '/')  dpcbase += '/';
    cppFlags += ( " -I" + dpcbase + "Include/ ");
    linkOptions += " -L" + dpcbase + syscomp + "ShLibs/ -lextsophya -lsophya -lm "; 
  }

  string extlib;
  varenv=getenv("EXTLIBDIR");
  if (varenv) {
    extlib = varenv; 
    if (extlib[extlib.length()-1] != '/')  extlib += '/';
    cppFlags += ( " -I" + extlib +"Include/ ");
  }

  if ( (varenv=getenv("TMPDIR")) != NULL )  { 
    tmpDir = varenv; 
    if (tmpDir[tmpDir.length()-1] != '/') tmpDir += '/';
  }
}

/* --Methode-- */
CxxCompilerLinker::~CxxCompilerLinker()
{
}

/* --Methode-- */
int CxxCompilerLinker::Compile(string const & name, string & oname)
{
  if (oname.length() < 1) {
    size_t l,p,q;
    l = name.length();
    p = name.rfind('/');
    if (p >= l)  p = 0;
    else p++;
    q = name.find('.');
    if (q < l)  oname = tmpDir + name.substr(p, q-p) + ".o";
    else oname = tmpDir + name.substr(p) + ".o";
  }
  string cmd;
  cmd = compCmd + cppFlags + compOptions + "-o " + oname + " " + name ; 
  if (verbose)
    cout << "CxxCompilerLinker::Compile() - Executing \n" << cmd << endl; 
  int rc = system(cmd.c_str());
  if (rc != 0)   
    cerr << "CxxCompilerLinker::Compile() Error Rc(" << cmd <<")= "<< rc << endl; 
  
  return(rc);
}

/* --Methode-- */
int CxxCompilerLinker::BuildSO(string const & oname, string & soname)
{
  if (soname.length() < 1) {
    size_t l,p,q;
    l = oname.length();
    p = oname.rfind('/');
    if (p >= l)  p = 0;
    else p++;
    q = oname.find('.');
    if (q < l)  soname = tmpDir + oname.substr(p, q-p) + ".so";
    else soname = tmpDir + oname.substr(p) + ".so";
  }
  string cmd;
  cmd = compCmd + linkOptions + "-o " + soname + " " + oname ; 
  if (verbose)
    cout << "CxxCompilerLinker::BuildSO() - Executing \n" << cmd << endl; 
  int rc = system(cmd.c_str());
  if (rc != 0)   
    cerr << "CxxCompilerLinker::BuildSO() Error Rc(" << cmd <<")= "<< rc << endl; 
  
  return(rc);
}

