/*

Copyright (C) 2008, 2009 Michael Goffioul

This file is part of Octave.

Octave is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.

Octave 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 GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with Octave; see the file COPYING.  If not, see
<http://www.gnu.org/licenses/>.

*/

#if defined (HAVE_CONFIG_H)
#include <config.h>
#endif

#include <string>
#include <map>
#include <list>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
#include <cstdlib>

#if defined (__WIN32__) && ! defined (_POSIX_VERSION)
#include <windows.h>
#ifdef _MSC_VER
#define popen _popen
#define pclose _pclose
#endif
#endif

using namespace std;

static bool initialized = false;
static map<string,string> vars;

static string OCTAVE_VERSION = %OCTAVE_CONF_VERSION%;

static std::string
substitute_prefix (const std::string& s, const std::string& prefix,
		   const std::string& new_prefix)
{
  std::string retval = s;

  if (!prefix.empty () && new_prefix != prefix)
    {
      int len = prefix.length ();
      if (retval.find (prefix) == 0)
	retval.replace (0, len, new_prefix);
    }

#if defined (__WIN32__) && ! defined (_POSIX_VERSION)
  std::replace (retval.begin (), retval.end (), '/', '\\');
#endif

  return retval;
}

static string
get_line (FILE *fp)
{
  static vector<char> buf (100);
  int idx = 0;
  char c;

  while (true)
    {
      c = static_cast<char> (fgetc (fp));
      if (c == '\n' || c == EOF)
	break;
      if (buf.size () <= idx)
	buf.resize (buf.size () + 100);
      buf[idx++] = c;
    }
  if (idx == 0)
    return string ("");
  else
    return string (&buf[0], idx);
}


static string
get_variable (const char *name, const string& defval)
{
  const char *val = getenv (name);
  if (val == NULL || val[0] == '\0')
    return defval;
  else
    return string (val);
}

static string
quote_path (const string& s)
{
  if (s.find (' ') != string::npos && s[0] != '"')
    return "\"" + s + "\"";
  else
    return s;
}

static void
initialize (void)
{
  if (initialized)
    return;

  initialized = true;

  vars["OCTAVE_HOME"] = get_variable ("OCTAVE_HOME", "");

#if defined (__WIN32__) && ! defined (_POSIX_VERSION)
  int n = 1024;

  std::string bin_dir (n, '\0');

  while (true)
    {
      int status = GetModuleFileName (0, &bin_dir[0], n);

      if (status < n)
	{
	  bin_dir.resize (status);
	  break;
	}
      else
	{
	  n *= 2;
	  bin_dir.resize (n);
	}
    }

  if (! bin_dir.empty ())
    {
      size_t pos = bin_dir.rfind ("\\bin\\");

      if (pos != string::npos)
	vars["OCTAVE_HOME"] = bin_dir.substr (0, pos);
    }
#endif

  vars["SED"] = get_variable ("SED", %OCTAVE_CONF_SED%);

  vars["OCTAVE_PREFIX"] = %OCTAVE_CONF_PREFIX%;

  std::string DEFAULT_OCTINCLUDEDIR = %OCTAVE_CONF_OCTINCLUDEDIR%;
  std::string DEFAULT_INCLUDEDIR = %OCTAVE_CONF_INCLUDEDIR%;
  std::string DEFAULT_LIBDIR = %OCTAVE_CONF_LIBDIR%;
  std::string DEFAULT_OCTLIBDIR = %OCTAVE_CONF_OCTLIBDIR%;

  if (! vars["OCTAVE_HOME"].empty ())
    {
      DEFAULT_OCTINCLUDEDIR
	= substitute_prefix (DEFAULT_OCTINCLUDEDIR, vars["OCTAVE_PREFIX"],
			     vars["OCTAVE_HOME"]);

      DEFAULT_INCLUDEDIR
	= substitute_prefix (DEFAULT_INCLUDEDIR, vars["OCTAVE_PREFIX"],
			     vars["OCTAVE_HOME"]);

      DEFAULT_LIBDIR
	= substitute_prefix (DEFAULT_LIBDIR, vars["OCTAVE_PREFIX"],
			     vars["OCTAVE_HOME"]);

      DEFAULT_OCTLIBDIR
	= substitute_prefix (DEFAULT_OCTLIBDIR, vars["OCTAVE_PREFIX"],
			     vars["OCTAVE_HOME"]);
    }

  vars["OCTINCLUDEDIR"] = get_variable ("OCTINCLUDEDIR", DEFAULT_OCTINCLUDEDIR);
  vars["INCLUDEDIR"] = get_variable ("INCLUDEDIR", DEFAULT_INCLUDEDIR);
  vars["LIBDIR"] = get_variable ("LIBDIR", DEFAULT_LIBDIR);
  vars["OCTLIBDIR"] = get_variable ("OCTLIBDIR", DEFAULT_OCTLIBDIR);

#if defined (__WIN32__) && ! defined (_POSIX_VERSION)
  std::string DEFAULT_INCFLAGS = "-I" + quote_path (vars["OCTINCLUDEDIR"])
    + " -I" + quote_path (vars["OCTINCLUDEDIR"] + "\\octave");
#else
  std::string DEFAULT_INCFLAGS = "-I" + quote_path (vars["OCTINCLUDEDIR"])
 + " -I" + quote_path (vars["OCTINCLUDEDIR"] + "/octave");
#endif
  if (vars["INCLUDEDIR"] != "/usr/include")
    DEFAULT_INCFLAGS += " -I" + quote_path (vars["INCLUDEDIR"]);

  std::string DEFAULT_LFLAGS = "-L" + quote_path (vars["OCTLIBDIR"]);
  if (vars["LIBDIR"] != "/usr/lib")
    DEFAULT_LFLAGS += " -L" + quote_path (vars["LIBDIR"]);

  vars["CPPFLAGS"] = get_variable ("CPPFLAGS", %OCTAVE_CONF_CPPFLAGS%);
  vars["INCFLAGS"] = get_variable ("INCFLAGS", DEFAULT_INCFLAGS);
  vars["F77"] = get_variable ("F77", %OCTAVE_CONF_F77%);
  vars["FFLAGS"] = get_variable ("FFLAGS", %OCTAVE_CONF_FFLAGS%);
  vars["FPICFLAG"] = get_variable ("FPICFLAG", %OCTAVE_CONF_FPICFLAG%);
  vars["CC"] = get_variable ("CC", %OCTAVE_CONF_CC%);
  vars["CFLAGS"] = get_variable ("CFLAGS", %OCTAVE_CONF_CFLAGS%);
  vars["CPICFLAG"] = get_variable ("CPICFLAG", %OCTAVE_CONF_CPICFLAG%);
  vars["CXX"] = get_variable ("CXX", %OCTAVE_CONF_CXX%);
  vars["CXXFLAGS"] = get_variable ("CXXFLAGS", %OCTAVE_CONF_CXXFLAGS%);
  vars["CXXPICFLAG"] = get_variable ("CXXPICFLAG", %OCTAVE_CONF_CXXPICFLAG%);
  vars["XTRA_CFLAGS"] = get_variable ("XTRA_CFLAGS", %OCTAVE_CONF_XTRA_CFLAGS%);
  vars["XTRA_CXXFLAGS"] = get_variable ("XTRA_CXXFLAGS", %OCTAVE_CONF_XTRA_CXXFLAGS%);

  vars["DEPEND_FLAGS"] = get_variable ("DEPEND_FLAGS", %OCTAVE_CONF_DEPEND_FLAGS%);
  vars["DEPEND_EXTRA_SED_PATTERN"] = get_variable ("DEPEND_EXTRA_SED_PATTERN", %OCTAVE_CONF_DEPEND_EXTRA_SED_PATTERN%);

  vars["DL_LD"] = get_variable ("DL_LD", %OCTAVE_CONF_DL_LD%);
  vars["DL_LDFLAGS"] = get_variable ("DL_LDFLAGS", %OCTAVE_CONF_MKOCTFILE_DL_LDFLAGS%);

  vars["RLD_FLAG"] = get_variable ("RLD_FLAG", %OCTAVE_CONF_RLD_FLAG%);
  vars["RDYNAMIC_FLAG"] = get_variable ("RDYNAMIC_FLAG", %OCTAVE_CONF_RDYNAMIC_FLAG%);
  vars["LIBOCTAVE"] = "-loctave";
  vars["LIBOCTINTERP"] = "-loctinterp";
  vars["LIBREADLINE"] = "-lreadline";
  vars["LIBCRUFT"] = "-lcruft";
  vars["BLAS_LIBS"] = get_variable ("BLAS_LIBS", %OCTAVE_CONF_BLAS_LIBS%);
  vars["FFTW_LIBS"] = get_variable ("FFTW_LIBS", %OCTAVE_CONF_FFTW_LIBS%);
  vars["LIBS"] = get_variable ("LIBS", %OCTAVE_CONF_LIBS%);
  vars["FLIBS"] = get_variable ("FLIBS", %OCTAVE_CONF_FLIBS%);
  vars["LD_CXX"] = get_variable ("LD_CXX", %OCTAVE_CONF_LD_CXX%);
  vars["LDFLAGS"] = get_variable ("LDFLAGS", %OCTAVE_CONF_LDFLAGS%);
  vars["LD_STATIC_FLAG"] = get_variable ("LD_STATIC_FLAG", %OCTAVE_CONF_LD_STATIC_FLAG%);
  vars["LFLAGS"] = get_variable ("LFLAGS", DEFAULT_LFLAGS);

  vars["ALL_FFLAGS"] = vars["FFLAGS"];

  vars["ALL_CFLAGS"] = vars["INCFLAGS"] + " " + vars["XTRA_CFLAGS"]
    + " " + vars["CFLAGS"];

  vars["ALL_CXXFLAGS"] = vars["INCFLAGS"] + " " + vars["XTRA_CXXFLAGS"]
    + " " + vars["CXXFLAGS"];

  vars["ALL_LDFLAGS"] = vars["LD_STATIC_FLAG"] + " " + vars["CPICFLAG"]
    + " " + vars["LDFLAGS"];

  vars["OCTAVE_LIBS"] = vars["LIBOCTINTERP"] + " " + vars["LIBOCTAVE"]
    + " " + vars["SPECIAL_MATH_LIB"] + " " + vars["LIBCRUFT"];
}

static string usage_msg = "usage: mkoctfile [options] file ...";
static string version_msg = "mkoctfile, version " + OCTAVE_VERSION;
static bool debug = false;
static string help_msg =
"\n"
"Options:\n"
"\n"
"  -h, -?, --help          Print this message.\n"
"\n"
"  -IDIR                   Add -IDIR to compile commands.\n"
"\n"
"  -idirafter DIR          Add -idirafter DIR to compile commands.\n"
"\n"
"  -DDEF                   Add -DDEF to compile commands.\n"
"\n"
"  -lLIB                   Add library LIB to link command.\n"
"\n"
"  -LDIR                   Add -LDIR to link command.\n"
"\n"
"  -M, --depend            Generate dependency files (.d) for C and C++\n"
"                          source files.\n"
"\n"
"  -RDIR                   Add -RDIR to link command.\n"
"\n"
"  -Wl,...                 Pass flags though the linker like -Wl,-rpath=...\n"
"\n"
"  -W...                   Pass flags though the compiler like -Wa,OPTION.\n"
"\n"
"  -c, --compile           Compile, but do not link.\n"
"\n"
"  -o FILE, --output FILE  Output file name.  Default extension is .oct\n"
"                          (or .mex if --mex is specified) unless linking\n"
"                          a stand-alone executable.\n"
"\n"
"  -g                      Enable debugging options for compilers.\n"
"\n"
"  -p VAR, --print VAR     Print configuration variable VAR.  Recognized\n"
"                          variables are:\n"
"\n"
"			    ALL_CFLAGS                FLIBS\n"
"			    ALL_CXXFLAGS              FPICFLAG\n"
"			    ALL_FFLAGS                INCFLAGS\n"
"			    ALL_LDFLAGS               LDFLAGS\n"
"			    BLAS_LIBS                 LD_CXX\n"
"			    CC                        LD_STATIC_FLAG\n"
"			    CFLAGS                    LFLAGS\n"
"			    CPICFLAG                  LIBCRUFT\n"
"			    CPPFLAGS                  LIBOCTAVE\n"
"			    CXX                       LIBOCTINTERP\n"
"			    CXXFLAGS                  LIBREADLINE\n"
"			    CXXPICFLAG                LIBS\n"
"			    DEPEND_EXTRA_SED_PATTERN  OCTAVE_LIBS\n"
"			    DEPEND_FLAGS              RDYNAMIC_FLAG\n"
"			    DL_LD                     RLD_FLAG\n"
"			    DL_LDFLAGS                SED\n"
"			    F77                       XTRA_CFLAGS\n"
"			    FFLAGS                    XTRA_CXXFLAGS\n"
"			    FFTW_LIBS\n"
"\n"
"  --link-stand-alone      Link a stand-alone executable file.\n"
"\n"
"  --mex                   Assume we are creating a MEX file.  Set the\n"
"                          default output extension to \".mex\".\n"
"\n"
"  -s, --strip             Strip output file.\n"
"\n"
"  -v, --verbose           Echo commands as they are executed.\n"
"\n"
"  FILE                    Compile or link FILE.  Recognized file types are:\n"
"\n"
"                            .c    C source\n"
"                            .cc   C++ source\n"
"                            .C    C++ source\n"
"                            .cpp  C++ source\n"
"                            .f    Fortran source (fixed form)\n"
"                            .F    Fortran source (fixed form)\n"
"                            .f90  Fortran source (free form)\n"
"                            .F90  Fortran source (free form)\n"
"                            .o    object file\n"
"                            .a    library file\n"
#ifdef _MSC_VER
"                            .lib  library file\n"
#endif
"\n";

static string
basename (const string& s, bool strip_path = false)
{
  size_t pos = s.rfind ('.');
  string retval;

  if (pos == string::npos)
    retval = s;
  else
    retval = s.substr (0, pos);
  if (strip_path)
    {
      size_t p1 = retval.rfind ('/'), p2 = retval.rfind ('\\');
      pos = (p1 != string::npos && p2 != string::npos
	     ? max (p1, p2) : (p2 != string::npos ? p2 : p1));
      if (pos != string::npos)
	retval = retval.substr (0, pos);
    }
  return retval;
}

inline bool
starts_with (const string& s, const string& prefix)
{
  return (s.length () >= prefix.length () && s.find (prefix) == 0);
}

inline bool
ends_with (const string& s, const string& suffix)
{
  return (s.length () >= suffix.length ()
	  && s.rfind (suffix) == s.length () - suffix.length ());
}

static int
run_command (const string& cmd)
{
  if (debug)
    cout << cmd << endl;
  return system (cmd.c_str ());
}

int
main (int argc, char **argv)
{
  initialize ();

  string file, output_option;
  list<string> cfiles, ccfiles, f77files;
  int result = 0;

  string objfiles = "";
  string libfiles = "";
  string octfile = "";
  string outputfile = "";
  string incflags = "";
  string defs = "";
  string ldflags = "";
  string pass_on_options = "";
  bool strip = false;
  bool no_oct_file_strip_on_this_platform = %NO_OCT_FILE_STRIP%;
  bool link = true;
  bool link_stand_alone = false;
  string output_ext = ".oct";
  bool depend = false;
  bool compile = true;

  if (argc == 1)
    {
      cout << usage_msg << endl;
      return 1;
    }

  if (argc == 2 && (!strcmp (argv[1], "-v") || !strcmp (argv[1], "--version")))
    {
      cout << version_msg << endl;
      return 0;
    }

  for (int i = 1; i < argc; i++)
    {
      string arg = argv[i];
      size_t len = arg.length ();

      if (ends_with (arg, ".c"))
	{
	  file = arg;
	  cfiles.push_back (file);
	}
      else if (ends_with (arg, ".cc") || ends_with (arg, ".C")
	       || ends_with (arg, ".cpp"))
	{
	  file = arg;
	  ccfiles.push_back (file);
	}
      else if (ends_with (arg, ".f") || ends_with (arg, ".F")
	       || ends_with (arg, "f90") || ends_with (arg, ".F90"))
	{
	  file = arg;
	  f77files.push_back (file);
	}
      else if (ends_with (arg, ".o") || ends_with (arg, ".obj"))
	{
	  file = arg;
	  objfiles += (" " + quote_path (arg));
	}
      else if (ends_with (arg, ".lib") || ends_with (arg, ".a"))
	{
	  file = arg;
	  libfiles += (" " + quote_path (arg));
	}
      else if (arg == "-d" || arg == "--debug" || arg == "-v"
	       || arg == "--verbose")
	{
	  debug = true;
	  if (vars["CC"] == "cc-msvc")
	    vars["CC"] += " -d";
	  if (vars["CXX"] == "cc-msvc")
	    vars["CXX"] += " -d";
	  if (vars["DL_LD"] == "cc-msvc")
	    vars["DL_LD"] += " -d";
	}
      else if (arg == "-h" || arg == "-?" || arg == "--help")
	{
	  cout << usage_msg << endl;
	  cout << help_msg << endl;
	  return 0;
	}
      else if (starts_with (arg, "-I"))
	{
	  incflags += (" " + quote_path (arg));
	}
      else if (arg == "-idirafter")
	{
	  if (i < argc-1)
	    {
	      arg = argv[++i];
	      incflags += (" -idirafter " + arg);
	    }
	  else
	    cerr << "mkoctfile: include directory name missing" << endl;
	}
      else if (starts_with (arg, "-D"))
	{
	  defs += (" " + arg);
	}
      else if (starts_with (arg, "-Wl,") || starts_with (arg, "-l")
	       || starts_with (arg, "-L") || starts_with (arg, "-R"))
	{
	  ldflags += (" " + arg);
	}
      else if (arg == "-M" || arg == "--depend")
	{
	  depend = true;
	  compile = false;
	}
      else if (arg == "-o" || arg == "--output")
	{
	  if (i < argc-1)
	    {
	      arg = argv[++i];
	      outputfile = arg;
	    }
	  else
	    cerr << "mkoctfile: output file name missing" << endl;
	}
      else if (arg == "-p" || arg == "--print")
	{
	  if (i < argc-1)
	    {
	      arg = argv[++i];
	      cout << vars[arg] << endl;
	      return 0;
	    }
	  else
	    cerr << "mkoctfile: --print requires argument" << endl;
	}
      else if (arg == "-s" || arg == "--strip")
	{
	  if (no_oct_file_strip_on_this_platform)
	    cerr << "mkoctfile: stripping disabled on this platform" << endl;
	  else
	    strip = true;
	}
      else if (arg == "-c" || arg == "--compile")
	{
	  link = false;
	}
      else if (arg == "-g")
	{
	  vars["ALL_CFLAGS"] += " -g";
	  vars["ALL_CXXFLAGS"] += " -g";
	  vars["ALL_FFLAGS"] += " -g";
	}
      else if (arg == "--link-stand-alone")
	{
	  link_stand_alone = true;
	}
      else if (arg == "--mex")
	{
	  incflags += " -I.";
#ifdef _MSC_VER
	  ldflags += " -Wl,-export:mexFunction";
#endif
	  output_ext = ".mex";
	}
      else if (starts_with (arg, "-W"))
	{
	  pass_on_options += (" " + arg);
	}
      else
	{
	  cerr << "mkoctfile: unrecognized argument " << arg;
	  return 1;
	}

      if (!file.empty () && octfile.empty ())
	octfile = file;
    }

  if (link_stand_alone)
    {
      if (!outputfile.empty ())
	output_option = "-o " + outputfile;
    }
  else
    {
      if (!outputfile.empty ())
	octfile = outputfile;
      else
	octfile = basename (octfile, true) + output_ext;
    }

  list<string>::const_iterator it;

  if (depend)
    {
      for (it = cfiles.begin (); it != cfiles.end (); ++it)
	{
	  string f = *it, dfile = basename (f) + ".d", line;

	  unlink (dfile.c_str ());
	  string cmd = vars["CC"] + " " + vars["DEPEND_FLAGS"] + " "
	    + vars["CPPFLAGS"] + " " + vars["ALL_CFLAGS"] + " "
	    + incflags  + " " + defs + " " + quote_path (f);

	  FILE *fd = popen (cmd.c_str (), "r");
	  ofstream fo (dfile.c_str ());
	  int pos;
	  while (!feof (fd))
	    {
	      line = get_line (fd);
	      if ((pos = line.rfind (".o:")) != string::npos)
		{
		  int spos = line.rfind ('/', pos);
		  string ofile = (spos == string::npos ? line.substr (0, pos+2) : line.substr (spos+1, pos-spos+1));
		  fo << "pic/" << ofile << " " << ofile << " " << dfile << line.substr (pos) << endl;
		}
	      else
		fo << line << endl;
	    }
	  pclose (fd);
	  fo.close ();
	}

      for (it = ccfiles.begin (); it != ccfiles.end (); ++it)
	{
	  string f = *it, dfile = basename (f) + ".d", line;

	  unlink (dfile.c_str ());
	  string cmd = vars["CC"] + " " + vars["DEPEND_FLAGS"] + " "
	    + vars["CPPFLAGS"] + " " + vars["ALL_CXXFLAGS"] + " "
	    + incflags  + " " + defs + " " + quote_path (f);

	  FILE *fd = popen (cmd.c_str (), "r");
	  ofstream fo (dfile.c_str ());
	  int pos;
	  while (!feof (fd))
	    {
	      line = get_line (fd);
	      if ((pos = line.rfind (".o:")) != string::npos)
		{
		  int spos = line.rfind ('/', pos);
		  string ofile = (spos == string::npos ? line.substr (0, pos+2) : line.substr (spos+1, pos-spos+1));
		  fo << "pic/" << ofile << " " << ofile << " " << dfile << line.substr (pos+2) << endl;
		}
	      else
		fo << line << endl;
	    }
	  pclose (fd);
	  fo.close ();
	}

      return 0;
    }

  for (it = f77files.begin (); it != f77files.end (); ++it)
    {
      string f = *it, b = basename (f);
      if (!vars["F77"].empty ())
	{
	  string o;
	  if (!outputfile.empty ())
	    {
	      if (link)
		o = b + ".o";
	      else
		o = outputfile;
	    }
	  else
	    o = b + ".o";
	  objfiles += (" " + o);
	  string cmd = vars["F77"] + " -c " + vars["FPICFLAG"] + " "
	    + vars["ALL_FFLAGS"] + " " + incflags + " " + defs + " "
	    + pass_on_options + " " + f + " -o " + o;
	  result = run_command (cmd);
	}
      else
	{
	  cerr << "mkoctfile: no way to compile Fortran file " << f << endl;
	  return 1;
	}
    }

  for (it = cfiles.begin (); it != cfiles.end (); ++it)
    {
      string f = *it;
      if (!vars["CC"].empty ())
	{
	  string b = basename (f), o;
	  if (!outputfile.empty ())
	    {
	      if (link)
		o = b + ".o";
	      else
		o = outputfile;
	    }
	  else
	    o = b + ".o";
	  objfiles += (" " + o);
	  string cmd = vars["CC"] + " -c " + vars["CPPFLAGS"] + " "
	    + vars["CPICFLAG"] + " " + vars["ALL_CFLAGS"] + " "
	    + pass_on_options + " " + incflags + " " + defs + " "
	    + quote_path (f) + " -o " + quote_path (o);
	  result = run_command (cmd);
	}
      else
	{
	  cerr << "mkoctfile: no way to compile C file " << f << endl;
	  return 1;
	}
    }
	
  for (it = ccfiles.begin (); it != ccfiles.end (); ++it)
    {
      string f = *it;
      if (!vars["CXX"].empty ())
	{
	  string b = basename (f), o;
	  if (!outputfile.empty ())
	    {
	      if (link)
		o = b + ".o";
	      else
		o = outputfile;
	    }
	  else
	    o = b + ".o";
	  objfiles += (" " + o);
	  string cmd = vars["CXX"] + " -c " + vars["CPPFLAGS"] + " "
	    + vars["CXXPICFLAG"] + " " + vars["ALL_CXXFLAGS"] + " "
	    + pass_on_options + " " + incflags + " " + defs + " "
	    + quote_path (f) + " -o " + quote_path (o);
	  result = run_command (cmd);
	}
      else
	{
	  cerr << "mkoctfile: no way to compile C++ file " << f << endl;
	  return 1;
	}
    }

  if (link && !objfiles.empty ())
    {
      if (link_stand_alone)
	{
	  if (!vars["LD_CXX"].empty ())
	    {
	      string cmd = vars["LD_CXX"] + " " + vars["CPPFLAGS"] + " "
		+ vars["ALL_CXXFLAGS"] + " " + vars["RDYNAMIC_FLAG"]
		+ " " + vars["ALL_LDFLAGS"] + " " +  pass_on_options
		+ " " + output_option + " " + objfiles + " " + libfiles
		+ " " + ldflags + " " + vars["LFLAGS"] + " "
		+ vars["RLD_FLAG"] + " " + vars["OCTAVE_LIBS"] + " "
		+ vars["BLAS_LIBS"] + " " + vars["FFTW_LIBS"] + " "
		+ vars["LIBREADLINE"] + " " + vars["LIBS"] + " "
		+ vars["FLIBS"];
	      result = run_command (cmd);
	    }
	  else
	    {
	      cerr << "mkoctfile: no way to link stand-alone executable file"
		   << endl;
	      return 1;
	    }
	}
      else
	{
	  string LINK_DEPS = vars["LFLAGS"] + " " + vars["OCTAVE_LIBS"]
	    + " " + vars["LDFLAGS"] + " " + vars["BLAS_LIBS"] + " "
	    + vars["FFTW_LIBS"] + " " + vars["LIBS"] + " " + vars["FLIBS"];
	  string cmd = vars["DL_LD"] + " " + vars["DL_LDFLAGS"] + " "
	    + pass_on_options + " -o " + octfile + " " + objfiles + " "
	    + libfiles + " " + ldflags + " " + LINK_DEPS;
	  result = run_command (cmd);
	}

      if (strip)
	{
	  string cmd = "strip " + octfile;
	  result = run_command (cmd);
	}
    }

  return result;
}
