# HG changeset patch # User John W. Eaton # Date 1637322720 18000 # Node ID f42752ce0ae3ea453cfb8da4d471769a30a9e456 # Parent 90a4202652e76b06de779a2d57bdfb29500710ab 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. diff -r 90a4202652e7 -r f42752ce0ae3 binary-dist-rules.mk --- a/binary-dist-rules.mk Wed Nov 17 15:09:42 2021 +0100 +++ b/binary-dist-rules.mk Fri Nov 19 06:52:00 2021 -0500 @@ -25,7 +25,9 @@ ifeq ($(MXE_WINDOWS_BUILD),yes) TAR_H_OPTION := -h WINDOWS_BINARY_DIST_DEPS := \ - win7appid blas_switch + octave-launch \ + win7appid \ + blas_switch ifeq ($(USE_MSYS2),yes) WINDOWS_BINARY_DIST_DEPS += \ @@ -84,6 +86,21 @@ fi endef +## FIXME: Maybe we should have a uniform way of dealing with the +## creation of build-tree directories like this? +installer-files/.dirstamp: + @mkdir -p installer-files + @: > installer-files/.dirstamp + +ifeq ($(MXE_WINDOWS_BUILD),yes) +.PHONY: octave-launch +octave-launch: installer-files/octave-launch.exe + +## FIXME: We aren't using VPATH? +installer-files/octave-launch.exe: $(TOP_DIR)/installer-files/octave-launch.c | installer-files/.dirstamp + $(MXE_CC) $< -o $@ -Wl,--subsystem,windows -lshlwapi +endif + ifeq ($(MXE_WINDOWS_BUILD),yes) ifeq ($(MXE_NATIVE_BUILD),no) define copy-windows-dist-files @@ -110,6 +127,8 @@ cp $(TOP_DIR)/installer-files/README.html $(OCTAVE_DIST_DIR)/ echo " refblas..." cp $(OCTAVE_DIST_DIR)$(OCTAVE_ADD_PATH)/bin/libblas.dll $(OCTAVE_DIST_DIR)$(OCTAVE_ADD_PATH)/bin/librefblas.dll + echo " installing octave-launch.exe..." + cp $(TOP_BUILD_DIR)/installer-files/octave-launch.exe $(OCTAVE_DIST_DIR)/ echo " octave.vbs..." cp $(TOP_DIR)/installer-files/octave.vbs $(OCTAVE_DIST_DIR)/ cp $(TOP_DIR)/installer-files/octave-firsttime.vbs $(OCTAVE_DIST_DIR)/ @@ -158,6 +177,8 @@ cp $(TOP_DIR)/installer-files/README.html $(OCTAVE_DIST_DIR)/ echo " refblas..." cp $(OCTAVE_DIST_DIR)/bin/libblas.dll $(OCTAVE_DIST_DIR)/bin/librefblas.dll + echo " installing octave-launch.exe..." + cp $(TOP_BUILD_DIR)/installer-files/octave-launch.exe $(OCTAVE_DIST_DIR)/ echo " octave.vbs..." cp $(TOP_DIR)/installer-files/octave.vbs $(OCTAVE_DIST_DIR)/ cp $(TOP_DIR)/installer-files/octave-firsttime.vbs $(OCTAVE_DIST_DIR)/ diff -r 90a4202652e7 -r f42752ce0ae3 installer-files/octave-launch.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/installer-files/octave-launch.c Fri Nov 19 06:52:00 2021 -0500 @@ -0,0 +1,300 @@ +/* + * 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 + * + * 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 . +*/ + +#include +#include + +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; +}