perl problems (using ActiveState's perl from CYGWIN)

Geoff Hart
Tue Aug 17 14:29:00 GMT 1999

In case anyone is interested in using Activestate's Perl distribution with
CYGWIN, I have made a small tool that seems to work.  It's a "perl.exe"
executable, which translates the command line arguments from Cygwin to
then invokes the perl interpreter *directly* from the Activestate .dll (I
didn't want to spawn a subprocess).

Of course, this doesn't fix any file name translation *within* the running
script, so if you need that, this won't work.  For example, if your script
accepts file names as input, those paths would need to be Win32 valid.  But
it handles \ or / just fine.

It's not the most efficient, because I couldn't figure out a way to call
CYGWIN's "cygwin_conv_to_full_win32_path" from a Windows application - so
I end up calling "cygpath".  Also, I don't believe signal handling works
quite the same for these non-CYGWIN apps.  So, Ctrl-C will kill the top
level process fine, but spawned processes seem to be somewhat insulated.
I don't know of a clean way to deal with this.

I would like to put this new perl.exe on an ftp server, if someone is
to host it.  It's 49k big.

Here's the source and nmakefile (unfortunately, to build it you'll need to
install the Activestate Perl source, and make Dynaloader.c):


    1) include perlhost.h. This header defines all the
       OS Interfaces that are used by the PERL_OBJECT.
    2) define the host data structure 'CPerlHost'
    3) call the CPerlHost member function PerlCreate,
       which calls perl_alloc and perl_construct
    4) call the CPerlHost member function PerlParse
    5) call the CPerlHost member function PerlRun
    6) when done, call the CPerlHost member function PerlDestroy,
       which calls perl_destruct and perl_free

    Including XSUB.h brings in the files that have macros to redefine
    the perl_* functions, to work with PERL_OBJECT. Note that these
    macros may cause problems when there are name collisions. A common
    problem is having a local variable that has the same name as a Perl
    function. To track down these name collisions compile using '/P'
    option with VC++ so that you can see what the preprocessor has done.

#include <EXTERN.h>
#include <perl.h>
#define NO_XSLOCKS

// Bring in the macros that redefine perl_* functions to work with
#include <XSUB.h>

/* for Win32 */
#include "win32iop.h"
#include <fcntl.h>
#include <perlhost.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <process.h>

// DynaLoader stuff.
char *staticlinkmodules[] = {

// More DynaLoader stuff.
EXTERN_C void boot_DynaLoader _((CV* cv _CPERLarg));

static void
    char *file = __FILE__;
    newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);

CPerlObj *pPerl;  // The Perl object used by the host.

int main (int argc, char **argv, char **env)
  struct _stat stbuf;

  {for (char** pp = argv; *pp; pp++) {
    printf ("%s\n", *pp);
  char* name = argv[0];
  for (char* pp = argv[0]; *pp; pp++) {
    if (*pp == '\\' || *pp == '/') name = ++pp;

  char cmd[2048] = "";

    /* Find the *real* version of this command (argv[0]) */

    char path[2048];
    strcpy (path, getenv("PATH"));
    char* path_end = path + strlen (path);
    {for (char* pp = path; pp < path_end; pp++) {
      if (*pp == ';') {*pp = 0;}

    char pathext[2048] = ";", *pPATHEXT = getenv("PATHEXT");
    strcpy (pathext+1, pPATHEXT ? pPATHEXT : ".EXE;.COM;.BAT");
    char* pathext_end = pathext + 1 + strlen (pathext+1);
    {for (char* ppe = pathext; ppe < pathext_end; ppe++) {
      if (*ppe == ';') {*ppe = 0;}

    int my_size = -1;
    {for (char* ppe = pathext; ppe < pathext_end; ppe += strlen (ppe) + 1) {
      sprintf (cmd, "%s%s", argv[0], ppe);
      if (!_stat (cmd, &stbuf)) {
        my_size = stbuf.st_size;
    {for (char* pp = path; pp < path_end; pp += strlen (pp) + 1) {
      for (char* ppe = pathext; ppe < pathext_end; ppe += strlen (ppe) + 1)
        sprintf (cmd, "%s\\%s%s", pp, name, ppe);
        if (!_stat (cmd, &stbuf)) {
          if (my_size == -1) {
            my_size = 0;
          } else if (stbuf.st_size != my_size) {
            goto FOUND;
    printf ("Could not find command: %s!  Aborting!!\n", name);
    exit (1);

  // Now translate command line arguments to native Win32.

  char* cmd_args[256], args_storage[2048], *pas = cmd + strlen(cmd);
  int iarg = 0;
  cmd_args[iarg++] = cmd;
  for (int i = 1; i < argc; i++) {
    char cmd[256];
    *pas++ = 0;
    cmd_args[iarg++] = pas;
    if (*argv[i] == '-') goto NOT_FILE;
    {for (char* pc = argv[i]; *pc; pc++) {
      if (*pc == ' ' || *pc == ';' || *pc == '\'' || *pc == '"') {
        goto NOT_FILE;
    sprintf (cmd, "cygpath -w %s 2>nul", argv[i]);
    if( (CYGPATH = _popen(cmd, "rb" )) == NULL )
      exit( 1 );

    if ((1 == fscanf (CYGPATH, "%s", pas)) && !_stat (pas, &stbuf)) {
      pas += strlen(pas);
      goto NEXT_ARG;
    strcpy (pas, argv[i]);
    pas += strlen(pas);
  cmd_args[iarg] = 0;

  CPerlHost host;     // The Perl host
  host.PerlCreate();  // Create an instance of the Perl Interpreter

  host.PerlParse(xs_init, argc, cmd_args, NULL);

  host.PerlRun();      // Run the interpreter.
  host.PerlDestroy();  // Destroy the interpreter.
  return 0;

LIBDIR = C:\Perl\lib\CORE
SRCDIR = C:\Perl\src

LIBS = oldnames.lib kernel32.lib user32.lib winspool.lib advapi32.lib \
       shell32.lib ole32.lib  oleaut32.lib netapi32.lib uuid.lib \
       wsock32.lib version.lib \
       $(LIBDIR)\PerlCRT.lib $(LIBDIR)\PerlCore.lib \

CCDYNA = $(CCFLAGS) -I$(SRCDIR)\ext\DynaLoader

 cl.exe $(CCFLAGS) -Fo.\perl.obj perl.cpp
 cl.exe $(CCFLAGS) -Fo.\win32.obj $(SRCDIR)\win32\win32.c
 cl.exe $(CCFLAGS) -Fo.\win32sck.obj $(SRCDIR)\win32\win32sck.c
 cl.exe $(CCFLAGS) -Fo.\DynaLoader.obj \
 link.exe -nologo -nodefaultlib -release -machine:x86 $(LIBS) \
            -subsystem:console perl.obj win32.obj win32sck.obj \
            DynaLoader.obj setargv.obj

Want to unsubscribe from this list?
Send a message to

More information about the Cygwin mailing list