gcl-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gcl-devel] RE: Using maxima from a program


From: Mike Thomas
Subject: [Gcl-devel] RE: Using maxima from a program
Date: Tue, 24 Jun 2003 13:15:11 +1000

Hi Francesco.

I've CC'ed to the Maxima and GCL lists as this is probably of general
interest.

| Hi Mike,
| First of all, thanks for your answer.
| The thread I refer to is:
|
http://groups.google.com/groups?hl=it&lr=&ie=UTF-8&oe=UTF-8&threadm=whfisr8q
1n6.fsf%40invite02.labri.fr&rnum=9&prev=/groups%3Fq%3Dsymbolic%2Bcalculus%2B
library%2Bgroup:sci.math.symbolic%26hl%3Dit%26lr%3D%26ie%3DUTF-8%26oe%3DUTF-
8%26selm%3Dwhfisr8q1n6.fsf%2540invite02.labri.fr%26rnum%3D9
|
| (see Pericle Malnati? well, it's me)
|
| I don't know what I exactly have to do (otherwise I wouldn't ask...),
let's | say I want to include, in a program of mine, symbolic calculus
functions.
| That's my aim.
| Any suggestions (program to run, how to run it...) are welcome.
|
| Thanks again,
| Francesco

Aha!

OK, if you're looking for .net or ActiveX don't bother with the Windows
version of Maxima as compiled by GCL or CLISP - it won't work like that.  If
you can work out how to build Maxima with Corman Common Lisp then you may be
able to do this as it compiles everything into a COM object I believe.  I
don't know about ACL or LispWorks.  As mentioned earlier, maybe Yacas could
be a goer - I haven't tried this.

Putting that approach aside, what you can do is build and run the example
program listed at the bottom of this email to drive either a CVS or current
release Windows Maxima 5.9.0 executable as a separate process.  I can't
vouch that the environment variables are all correct, but it works as far as
it goes for me under Windows XP.  Compile the program with MinGW32 gcc:

   gcc runmaxima.c -o runmaxima.exe

Run it as:

   runmaxima

The plotting commands this program runs after some calculations probably
won't work for you unless you have taken the trouble to setup the plotting
correctly, I just threw them in to show-off.  There are emails from me about
how to set this up on the Maxima list I think.

I hope this gets you going with Maxima.

Mike Thomas.


----- Original Message -----
From: Mike Thomas
To: Francesco Malandrino
Sent: Monday, June 23, 2003 1:07 AM
Subject: RE: Using maxima from a program


Hi Francesco.

I just searched for your message in the newsgroup and couldn't find it so
I'm unclear about your aims.

Do you want to run Maxima as a separate process (that is how the GUI front
end XMaxima does it) or by linking your program directly into Maxima itself?

Do you specifically want to use Maxima, or would you be happy with some
other system (eg Yacas)?

Cheers

Mike Thomas.



-----Original Message-----
From: Francesco Malandrino [mailto:address@hidden
Sent: Friday, June 20, 2003 8:46 PM
To: address@hidden
Subject: Using maxima from a program


Hallo Mike (if you are not Mike Thomas, well, excuse me...),

I was suggested by Martin Rubey to ask you about a question I've posted on
sci.math.symbolic some days ago. My aim is to call Maxima's functions (e.g.
solve, integrate etc.) from a program (I develop in a Win32 environment -
that's why I was suggested to ask you).
I hope you'll help me.
Thanks
Francesco Malandrino



===========================================================================

/* Run Maxima as a separate process under Windows either from
 * a CVS build or the 5.9.0 release installation, using either
 * CreateProcess() to launch or spawnvp() and with or without
 * some debugging output from the reader threads.
 *
 * Before launching stdin/out/err are each redirected into pipes
 * so that Maxima can be fed commands and its output read from
 * those pipes.
 *
 * The system runs these commands:
 *
 *   1+2;
 *   integrate(x^2,x);
 *   plot3d(2^(x^2-y^2),[x,-1,1],[y,-2,2]);
 *   plot3d(2^(x^2-y^2),[x,-1,1],[y,-2,2],[plot_format,gnuplot]);
 *   quit();
 *
 * If you have plotting set up properly, you should see first
 * Schelter's plot window and then a GNUPlot window.
 *
 * Build with the command:
 *
 *    gcc runmaxima.c -o runmaxima.exe
 *
 * Mike Thomas 20030624 */

#include <windows.h>
#include <process.h>
#include <memory.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>

/* Use spawnvp() rather than CreateProcess() */
/*#define USE_SPAWN    1*/

/* Use a CVS build of Maxima rather than the standard release 5.9.0 */
/*#define USE_CVS_MAXIMA*/

/* Allow some debugging output from the IO threads */
/*#define DEBUG_OUT*/

#define   OUT_BUFF_SIZE 512
#define   READ_HANDLE 0
#define   WRITE_HANDLE 1

#ifdef USE_CVS_MAXIMA

#define MAXIMA_ROOT "c:/cvs/maxima"
char maxima_exe[] = MAXIMA_ROOT "/src/binary-gcl/maxima.exe";
char maxima_cmd[] = MAXIMA_ROOT "/src/binary-gcl/maxima.exe -eval (run)";
char ENV_MAXIMA_VERPKGDATADIR[] = "MAXIMA_VERPKGDATADIR=" MAXIMA_ROOT;
char ENV_MAXIMA_VERPKGLIBEXECDIR[] = "MAXIMA_VERPKGLIBEXECDIR=" MAXIMA_ROOT
"/lisp-utils";
char ENV_MAXIMA_VERPKGLIBDIR[] = "MAXIMA_VERPKGLIBDIR=" MAXIMA_ROOT "/src";
char ENV_MAXIMA_INFODIR[] = "MAXIMA_INFODIR=" MAXIMA_ROOT "/doc/info";
char ENV_MAXIMA_PLOTDIR[] = "MAXIMA_PLOTDIR=" MAXIMA_ROOT "/plotting";
char ENV_in_maxima_local[] = "in_maxima_local=true";

#else /* USE_CVS_MAXIMA */

#define MAXIMA_ROOT "c:/Progra~1/Maxima-5.9.0"
#define MAXIMA_SUBDIR "/maxima/5.9.0"
char maxima_exe[] = MAXIMA_ROOT "/lib" MAXIMA_SUBDIR
"/binary-gcl/maxima.exe";
char maxima_cmd[] = MAXIMA_ROOT "/lib" MAXIMA_SUBDIR
"/binary-gcl/maxima.exe -eval (run)";
char ENV_MAXIMA_VERPKGDATADIR[] = "MAXIMA_VERPKGDATADIR=" MAXIMA_ROOT;
char ENV_MAXIMA_VERPKGLIBEXECDIR[] = "MAXIMA_VERPKGLIBEXECDIR=" MAXIMA_ROOT
"/libexec" MAXIMA_SUBDIR;
char ENV_MAXIMA_VERPKGLIBDIR[] = "MAXIMA_VERPKGLIBDIR=" MAXIMA_ROOT "/share"
MAXIMA_SUBDIR "/src";
char ENV_MAXIMA_INFODIR[] = "MAXIMA_INFODIR=" MAXIMA_ROOT "/info";
char ENV_MAXIMA_PLOTDIR[] = "MAXIMA_PLOTDIR="  MAXIMA_ROOT "/libexec"
MAXIMA_SUBDIR;
char ENV_in_maxima_local[] = "in_maxima_local=true";

#endif /* USE_CVS_MAXIMA */


int fdStdOutPipe[2], fdStdInPipe[2], fdStdErrPipe[2];

HANDLE hProcess;
STARTUPINFO si;                 /* Only need to set si.cb */
PROCESS_INFORMATION pi;         /* Post launch child process information. */

unsigned __stdcall StdOutReadThread ( void* pArguments )
{
    int nExitCode = STILL_ACTIVE;
    int nRead;
    char szBuffer[OUT_BUFF_SIZE];

    GetExitCodeProcess ( hProcess, (unsigned long*) &nExitCode );

    while ( nExitCode == STILL_ACTIVE ) {
#ifdef DEBUG_OUT
        fprintf ( stderr, " - Stdout read loop\n" ); fflush ( stderr );
#endif /* DEBUG_OUT */
        nRead = _read ( fdStdOutPipe[READ_HANDLE], szBuffer,
OUT_BUFF_SIZE );
#ifdef DEBUG_OUT
        fprintf ( stderr, "After _read on stdoutpipe (%d bytes read)\n",
nRead ); fflush ( stderr );
#endif /* DEBUG_OUT */
        if ( nRead ) {
            fwrite(szBuffer, 1, nRead, stderr);
        }
        GetExitCodeProcess ( hProcess, (unsigned long*) &nExitCode );
    }
    _endthreadex(0);
}

unsigned __stdcall StdErrReadThread ( void* pArguments )
{
    int nExitCode = STILL_ACTIVE;
    int nRead;
    char szBuffer[OUT_BUFF_SIZE];

    GetExitCodeProcess ( hProcess, (unsigned long*) &nExitCode );

    while ( nExitCode == STILL_ACTIVE ) {
#ifdef DEBUG_OUT
        fprintf ( stderr, " - Stderr read loop\n" ); fflush ( stderr );
#endif /* DEBUG_OUT */
        nRead = _read ( fdStdErrPipe[READ_HANDLE], szBuffer,
OUT_BUFF_SIZE );
#ifdef DEBUG_OUT
        fprintf ( stderr, "After _read on stderrpipe (%d bytes read)\n",
nRead ); fflush ( stderr );
#endif /* DEBUG_OUT */
        if ( nRead ) {
            fwrite(szBuffer, 1, nRead, stderr);
        }
        GetExitCodeProcess ( hProcess, (unsigned long*) &nExitCode );
    }
    _endthreadex(0);
}

int main(int argc, char** argv)
{
    HANDLE hStdOutReadThread;
    int fdStdOut, fdStdIn;
    unsigned threadIDOut;
    HANDLE hStdErrReadThread;
    int fdStdErr;
    unsigned threadIDErr;
    int i;
    char *commands[6];


#ifdef USE_SPAWN
    char *args[3];
    args[0] = "-eval";
    args[1] = "(run)";
    args[2] = NULL;
#ifdef DEBUG_OUT
    fprintf ( stderr, "SPAWN: %s %s %s\n", maxima_exe, args[0], args[1] );
fflush ( stderr );
#endif /* DEBUG_OUT */
#else
#ifdef DEBUG_OUT
    fprintf ( stderr, "CREATE PROCESS: %s\n", maxima_cmd ); fflush (
stderr );
#endif /* DEBUG_OUT */
#endif

#ifdef DEBUG_OUT
    fprintf ( stderr, "Setting env var: %s\n", ENV_MAXIMA_VERPKGDATADIR );
    fprintf ( stderr, "Setting env var: %s\n",
ENV_MAXIMA_VERPKGLIBEXECDIR );
    fprintf ( stderr, "Setting env var: %s\n", ENV_MAXIMA_VERPKGLIBDIR );
    fprintf ( stderr, "Setting env var: %s\n", ENV_MAXIMA_INFODIR );
    fprintf ( stderr, "Setting env var: %s\n", ENV_MAXIMA_PLOTDIR );
    fprintf ( stderr, "Setting env var: %s\n", ENV_in_maxima_local );
#endif /* DEBUG_OUT */

    /* Make pipes to be passed to the spawned process as stdin/out/err */
    if ( _pipe ( fdStdOutPipe, 512, O_TEXT | O_NOINHERIT ) == -1 ) return
1;
    if ( _pipe ( fdStdInPipe,  512, O_TEXT | O_NOINHERIT ) == -1 ) return
1;
    if ( _pipe ( fdStdErrPipe, 512, O_TEXT | O_NOINHERIT ) == -1 ) return
1;

    /* Duplicate and save original stdin/out/err handles */
    fdStdOut = _dup ( _fileno(stdout) );
    fdStdIn  = _dup ( _fileno(stdin) );
    fdStdErr = _dup ( _fileno(stderr) );

    /* Duplicate write end of new pipes to current stdout/err handles,
     * read to stdin */
    if ( _dup2 ( fdStdOutPipe[WRITE_HANDLE], _fileno(stdout) ) != 0 ) return
2;
    if ( _dup2 ( fdStdInPipe[READ_HANDLE],   _fileno(stdin)  ) != 0 ) return
2;
    if ( _dup2 ( fdStdErrPipe[WRITE_HANDLE], _fileno(stderr) ) != 0 ) return
2;

    /* Close the duplicated handles to the new pipes */
    close ( fdStdOutPipe[WRITE_HANDLE] );
    close ( fdStdInPipe[READ_HANDLE] );
    close ( fdStdErrPipe[WRITE_HANDLE] );

    putenv ( ENV_MAXIMA_VERPKGDATADIR );
    putenv ( ENV_MAXIMA_VERPKGLIBEXECDIR );
    putenv ( ENV_MAXIMA_VERPKGLIBDIR );
    putenv ( ENV_MAXIMA_INFODIR );
    putenv ( ENV_MAXIMA_PLOTDIR );
    putenv ( ENV_in_maxima_local );

#ifdef USE_SPAWN
    /* Spawn process given on the command line*/
    hProcess = (HANDLE) spawnvp ( P_NOWAIT, maxima_exe, args );
#else
    /* Zero startup and process info structures, take care of Windows
     * startup info structure future proofing. */
    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );

    /* Start the child process.  */
    if ( !CreateProcess ( NULL, /* No module name (use command line). */
                          maxima_cmd, /* Command line. */
                          NULL, /* Process handle not inheritable. */
                          NULL, /* Thread handle not inheritable. */
                          TRUE, /* Allow handle inheritance. */
                          0,    /* No creation flags. */
                          NULL, /* Use parent's environment block. */
                          NULL, /* Use parent's starting directory. */
                          &si,  /* Pointer to STARTUPINFO structure.*/
                          &pi ) /* Pointer to PROCESS_INFORMATION structure.
*/ ) {
        fprintf ( stderr, "CreateProcess failed: %s\n", argv[1] ); fflush
( stderr );
        return -1;
    }
    hProcess = pi.hProcess;
#endif

    /* Now that the process is launched, replace the original stdin/out/err
handles */
    if ( _dup2 ( fdStdOut, _fileno ( stdout ) ) != 0 ) return 3;
    if ( _dup2 ( fdStdIn,  _fileno ( stdin  ) ) != 0 ) return 3;
    if ( _dup2 ( fdStdErr, _fileno ( stderr ) ) != 0 ) return 3;

    /* Close duplicates */
    close(fdStdOut);
    close(fdStdIn);
    close(fdStdErr);

    /* Create the stdout listening thread.*/
    hStdOutReadThread = (HANDLE)_beginthreadex( NULL, 0, &StdOutReadThread,
NULL, 0, &threadIDOut );
    if ( 0 == hStdOutReadThread ) return 5;
    /* Create the stderr listening thread.*/
    hStdErrReadThread = (HANDLE)_beginthreadex( NULL, 0, &StdErrReadThread,
NULL, 0, &threadIDErr );
    if ( 0 == hStdErrReadThread ) return 5;

    commands[0] = "1+2;";
    commands[1] = "integrate(x^2,x);";
    commands[2] = "plot3d(2^(x^2-y^2),[x,-1,1],[y,-2,2]);";
    commands[3] =
"plot3d(2^(x^2-y^2),[x,-1,1],[y,-2,2],[plot_format,gnuplot]);";
    commands[4] = "quit();";
    commands[5] = NULL;
    for ( i=0; commands[i] != NULL; i++ ) {
#ifdef DEBUG_OUT
        fprintf ( stderr, "Sending command: %s\n",  commands[i] ); fflush
( stderr );
#endif /* DEBUG_OUT */
        _write ( fdStdInPipe[WRITE_HANDLE], commands[i], strlen (
commands[i] ) );
        _write ( fdStdInPipe[WRITE_HANDLE], "\n", strlen ( "\n" ) );
    }

    WaitForSingleObject ( hStdErrReadThread, INFINITE );
    WaitForSingleObject ( hStdOutReadThread, INFINITE );

    /* Wait until child process exits to block the terminal. */
#ifdef USE_SPAWN
    WaitForSingleObject ( hProcess, INFINITE );
#else
    WaitForSingleObject( pi.hProcess, INFINITE );
#endif

#ifndef USE_SPAWN
    /* Once child process has returned, close the process and thread
handles,
     * free the commandline and exit without error. */
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );
#endif

    /* As we are using gebinthreadex/endthreadex,
     * we must close the thread handles. */
    CloseHandle ( hStdOutReadThread );
    CloseHandle ( hStdErrReadThread );
    return 0;
}






reply via email to

[Prev in Thread] Current Thread [Next in Thread]