view installer-files/octave-launch.c @ 5955:f42752ce0ae3

new octave-launcher.exe program from John Donoghue * installer-files/octave-launch.c: New file. * binary-dist-rules.mk (octave-launch, installer-files/octave-launch.exe): New targets. (copy-windows-dist-files): Copy octave-launch.exe to $(OCTAVE_DIST_DIR). (installer-files/.dirstamp): New rule to ensure that installer-files directory is created if we are building outside the source tree.
author John W. Eaton <jwe@octave.org>
date Fri, 19 Nov 2021 06:52:00 -0500
parents
children b8e9589b7794
line wrap: on
line source

/*
 * Wrapper application to set octave env variables and then run octave
 * compile with gcc -o octave-launch octave-launch.c -Wl,--subsystem,windows -lshlwapi
 *
 * Copyright (C) 2020 John Donoghue <john.donoghue@ieee.org>
 *
 * This program 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.
 *
 * This program 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
 * this program; if not, see <http: *www.gnu.org/licenses/>.
*/

#include <windows.h>
#include <shlwapi.h>

static int ParentDir (char *dir)
{
  int len = strlen (dir);
  while (len > 0 && dir[len] != '\\')
    len --;
  dir[len] = 0;
  return len;
}

char * FilePart (char *dir)
{
  int len = strlen (dir);
  while (len > 0 && dir[len-1] != '\\')
    len --;
  return &dir[len];
}

// Set up environment and launch octave.exe with appropriate
// arguments.  NOTE: There are corresponding VBS and BAT script
// versions of this program so any changes here may need to be made in
// those scripts as well.

int main (int argc, char **argv)
{
  PROCESS_INFORMATION pi;

  // FIXME: There are currently have no checks to ensure that the
  // following fixed-size buffers are sufficiently large.  Maybe it
  // would be better if we used C++ and std::string objects?  For
  // buffers that are passed to Windows library functions to hold
  // output values, is 1024 the correct way to define the size of the
  // buffer?  Note that the use of sizeof(path)-1 below will fail if
  // we switch to using
  //
  //   char *path = (char *) malloc (...);
  //
  // instead of literal character arrays.

  char msyspath[1024];
  char rootpath[1024];
  char path[1024];
  char binpath[1024];

  int gui_arg_found = 0;
  int no_gui_arg_found = 0;
  int no_gui_libs = 0;
  int i;

  /* get path of us which we will assume is the root of the install */

  DWORD nSize = GetModuleFileName (NULL, path, sizeof(path)-1);
  if (nSize)
    {
      while (nSize > 0 && path[nSize] != '\\')
        nSize --;
      path[nSize] = '\0';
    }

  nSize = GetShortPathName (path, rootpath, sizeof(rootpath)-1);
  if (nSize == 0)
    StrCpy (rootpath, path);

  SetEnvironmentVariable ("MXE_ROOT", rootpath);

  /* get msys path and set env */

  StrCpy (msyspath, rootpath);

  StrCpy (path, rootpath);
  StrCat (path, "\\mingw64\\bin\\octave.exe");
  if (PathFileExists (path))
    {
      SetEnvironmentVariable ("MSYSTEM", "MINGW64");
      StrCat (msyspath, "\\usr");
      SetEnvironmentVariable ("MSYSPATH", msyspath);

      StrCat (msyspath, "\\bin");

      StrCpy (binpath, rootpath);
      StrCat (binpath, "\\mingw64\\bin");
    }
  else
    {
      StrCpy (path, rootpath);
      StrCat (path, "\\mingw32\\bin\\octave.exe");
      if (PathFileExists (path))
        {
          SetEnvironmentVariable ("MSYSTEM", "MINGW32");
          StrCat (msyspath, "\\usr");
          SetEnvironmentVariable ("MSYSPATH", msyspath);

          StrCat (msyspath, "\\bin");

          StrCpy (binpath, rootpath);
          StrCat (binpath, "\\mingw32\\bin");
        }
      else
        {
          SetEnvironmentVariable ("MSYSTEM", "MSYS");
          SetEnvironmentVariable ("MSYSPATH", msyspath);

          StrCat (msyspath, "\\bin");

          StrCpy (binpath, rootpath);
          StrCat (binpath, "\\bin");
        }
    }

  /* binpath is to the octave bin dir so get the parent */
  StrCpy (path, binpath);
  ParentDir (path);

 #ifdef SHOW_PATHS
  MessageBox (NULL, rootpath, "octroot", MB_OK);
  MessageBox (NULL, path, "octhome", MB_OK);
  MessageBox (NULL, binpath, "octbin", MB_OK);
  MessageBox (NULL, msyspath, "msysbin", MB_OK);
 #endif

  /* qt paths
   * either %OCT_HOME%\qt5\plugins
   * or %OCT_HOME\plugins
   */
  nSize = strlen (path);
  StrCat (path, "\\qt5\\plugins");
  SetEnvironmentVariable ("QT_PLUGIN_PATH", path);

  path[nSize] = '\0';

  /* exe paths */
  {
    char pathbuffer[8096];
    char newpathbuffer[8096];

    nSize = GetEnvironmentVariable ("PATH", pathbuffer, sizeof(pathbuffer)-1);
    pathbuffer[nSize] = '\0';

    /* set our paths first */
    StrCpy (newpathbuffer, binpath);
    StrCat (newpathbuffer, ";");
    StrCat (newpathbuffer, msyspath);
    StrCat (newpathbuffer, ";");
    StrCat (newpathbuffer, pathbuffer);

    SetEnvironmentVariable ("PATH", newpathbuffer);
  }

  /* other env */
  SetEnvironmentVariable ("TERM", "cygwin");
  SetEnvironmentVariable ("GNUTERM", "wxt");
  SetEnvironmentVariable ("GS", "gs.exe");

  /* home set */
  nSize = GetEnvironmentVariable ("HOME", path, sizeof(path)-1);
  if (nSize == 0 || path[0] == 0)
    {
      char newhome[1024];

      nSize = GetEnvironmentVariable ("USERPROFILE", path, sizeof(path)-1);
      if (nSize == 0 || path[0] == 0)
        {
          /* build dir from drive and path */
          char tmpbuff[1024];
          nSize = GetEnvironmentVariable ("HOMEDRIVE", tmpbuff, sizeof(tmpbuff)-1);
          if (nSize)
            StrCpy (path, tmpbuff);
          else
            path[0] = '\0';

          nSize = GetEnvironmentVariable ("HOMEPATH", tmpbuff, sizeof(tmpbuff)-1);
          if (nSize) StrCat (path, tmpbuff);
        }

      nSize = GetShortPathName (path, newhome, sizeof(newhome)-1);

      if (nSize == 0)
        {
          StrCpy (newhome, path);
        }

      SetEnvironmentVariable ("HOME", newhome);
    }

  /* check for gui mode */
  for (i = 1; i < argc; i++)
    {
      if (StrCmp (argv[i], "--no-gui-libs") == 0)
        {
          if (gui_arg_found)
            {
              /* Inconsistent options.  We can't start the GUI without gui libs.
                 How should we fail?   For now, --no-gui-libs will
                 override the other options.  */
            }

          no_gui_libs = 1;
        }
      else if (StrCmp (argv[i], "--gui") == 0
               || StrCmp (argv[i], "--force-gui") == 0)
        {
          if (no_gui_libs)
            {
              /* Inconsistent options.  We can't start the GUI without gui libs.
                 How should we fail?   For now, --no-gui-libs will
                 override the other options.  */
            }

          gui_arg_found = 1;
        }
      else if (StrCmp (argv[i], "--no-gui") == 0)
        no_gui_arg_found = 1;

      /* NOTE: specifying both --no-gui and --gui is also an
         inconsistent set of options but we leave it to octave.exe to
         detect that.  */
    }

  /* set up process args and start it */
  {
    STARTUPINFO si;
    char argbuffer[4096];

    ZeroMemory (&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory (&pi, sizeof(pi));

    StrCpy (path, binpath);

    StrCpy (argbuffer, "octave.exe ");
    StrCat (path, "\\octave.exe");

    if (! (no_gui_libs || no_gui_arg_found))
      {
        /* Unless --no-gui or --no-gui-libs is specified, we will use a GUI window.  */
        si.dwFlags = STARTF_USESHOWWINDOW;

        /* If none of the options --no-gui, --gui, or --force-gui
           were specified, then we'll add --gui to start the gui as
           most Windows users would expect.  */

        if (! gui_arg_found)
          StrCat (argbuffer, "--gui ");
      }

    /* quote and append each arg */
    for (i = 1; i < argc; i++)
      {
        StrCat (argbuffer, "\"");
        StrCat (argbuffer, argv[i]);
        StrCat (argbuffer, "\" ");
      }

    /* Start the child process */
    int status = CreateProcess (path,       // Module name
                                argbuffer,  // Command line
                                NULL,       // Process handle not inheritable
                                NULL,       // Thread handle not inheritable
                                FALSE,      // Set handle inheritance to FALSE
                                0,          // No creation flags
                                NULL,       // Use parent's environment block
                                NULL,       // Use parent's starting directory
                                &si,        // Pointer to STARTUPINFO
                                &pi);       // Pointer to PROCESS_INFORMATION

    if (! status)
      return 1;
  }

  /* Wait until child process exits. */
  WaitForSingleObject (pi.hProcess, INFINITE);

  /* Close process and thread handles */
  CloseHandle (pi.hProcess);
  CloseHandle (pi.hThread);

  return 0;
}