Integrate rdmd into compiler?

Daniel Keep daniel.keep.lists at gmail.com
Tue Apr 25 06:43:21 PDT 2006


AFAIK it has been integrated; not sure when it happened.  Try `dmd -run
SCRIPT`.  As for gdc, I have no idea.

	-- Daniel

Dave wrote:
> 
> The DMD distro. comes with 'rdmd' which extends the idea of running
> 'she-bang' sh scripts by caching the executable and also allowing
> compiler flags in the interpreter command-line (like #!/usr/bin/rdmd -O
> -version=foo).
> 
> I find these two things pretty useful...
> 
> Assuming this would be pretty easy to integrate into the compiler itself
> and Walter wants to, how about it? That way we could just use g/dmd for
> 'scripts' too.
> 
> Opinions?
> 
> Thanks,
> 
> - Dave
> 
> P.S.: Attached is the source code - the things I think need critical
> judgement would be a big holes, non-POSIX like non-standard cache path,
> and not recompiling an exe when it should be (source or switch change).
> 
> 
> ------------------------------------------------------------------------
> 
> // rdmd - a program to compile, cache and execute D programming
> // language source files via either the command-line or as a
> // 'pseudo shell script' on POSIX conforming Linux systems.
> //
> // Written by Dave Fladebo and released into the public domain as
> // explained by http://creativecommons.org/licenses/publicdomain
> //
> // This software is provided "AS IS" and without any express or
> // implied warranties, including and without limitation to, any
> // warranty of merchantability or fitness for any purpose.
> //
> // Windows additions by Roberto Mariottini
> //
> // version 1.1
> 
> version (Windows)
> {
>   import std.c.windows.windows;
> 
>   char[] fileSeparator = "\\";
>   char[] pathSeparator = ";";
>   char[] objectExtension = ".obj";
>   char[] exeExtension = ".exe";
> }
> else
> {
>   import std.c.linux.linux;
> 
>   char[] fileSeparator = "/";
>   char[] pathSeparator = ":";
>   char[] objectExtension = ".o";
>   char[] exeExtension = "";
> }
> 
> bool verbose = false;
> 
> import std.c.stdlib, std.file, std.md5, std.process, std.stdio, std.string;
> 
> int main(char[][] args)
> {
>     int retval = -1;
>     bool havefile = false, force = false;
>     char[][] cmpv, argv;    // cmpv = compiler arguments, argv = program arguments
>     char[] exepath, dfilepath, compiler = "dmd", tmpdir = "/tmp";
> 
>     version (Windows)
>     {
>         tmpdir = toString(getenv("TEMP"));
>     }
> 
>     .myname = args[0];
> 
>     foreach(int i, char[] arg; args)
>     {
>         if(i == 0)
>             continue;
> 
>         if(find(arg,".d") >= 0  ||  find(arg,".ds") >= 0)
>         {
>             havefile = true;
>             dfilepath = arg;
>         }
>         else
>         {
>             if(havefile == false)
>             {
>                 bool skip = false;
>                 if(arg == "--help")
>                     usage;
>                 else if(arg == "--force")
>                     skip = force = true;
>                 else if(arg == "--verbose")
>                     skip = verbose = true;
>                 else
>                 {
>                     const char[] cs = "--compiler=";
>                     if(arg.length > cs.length && arg[0..cs.length] == cs)
>                     {
>                         compiler = split(arg,"=")[1];
>                         skip = true;
>                     }
>                     const char[] td = "--tmpdir=";
>                     if(arg.length > td.length && arg[0..td.length] == td)
>                     {
>                         tmpdir = split(arg,"=")[1];
>                         skip = true;
>                     }
>                 }
> 
>                 if(!skip)
>                     cmpv ~= arg;
>             }
>             else
>                 argv ~= arg;
>         }
>     }
> 
>     if(!havefile)
>         error("Couldn't find any D source code file to compile or execute.", retval);
> 
>     if(compile(tmpdir,compiler,force,dfilepath,cmpv,exepath))
>     {
>         char[][] exeargv;
>         exeargv ~= exepath;
>         foreach(char[] arg; argv) exeargv ~= arg;
> 
>         if(verbose)
>         {
>             fwritef(stderr,"running: ");
>             foreach(char[] arg; exeargv)
>             {
>                 fwritef(stderr,arg," ");
>             }
>             fwritefln(stderr);
>         }
> 
>         // execute
>         version (Windows)
>         {
>             retval = spawnvp(std.c.process._P_WAIT, exepath, exeargv);
>         }
>         else
>         {
>             retval = spawnapp(exepath,exeargv);
>         }
>     }
>     else
>     {
>         try { std.file.remove(exepath); } catch {}
>         error("Couldn't compile or execute " ~ dfilepath ~ ".", retval);
>     }
> 
>     return retval;
> }
> 
> char[] myname;
> void error(char[] errmsg, int errno)
> {
>     fwritefln(stderr,myname,": ",errmsg);
>     exit(errno);
> }
> 
> void usage()
> {
>     fwritefln(stderr,"Usage:");
>     fwritefln(stderr,"  ",myname," [D compiler arguments] [",myname," arguments] progfile.d [program arguments]");
>     fwritefln(stderr);
>     fwritefln(stderr,myname," arguments:");
>     fwritefln(stderr,"  --help\t\tThis message");
>     fwritefln(stderr,"  --force\t\tForce re-compilation of source code [default = do not force]");
>     fwritefln(stderr,"  --verbose\t\tShow detailed info of operations [default = do not show]");
>     fwritefln(stderr,"  --compiler=(dmd|gdmd)\tSpecify compiler [default = dmd]");
>     fwritefln(stderr,"  --tmpdir=tmp_dir_path\tSpecify directory to store cached program and other temporaries [default = /tmp]");
>     fwritefln(stderr);
>     fwritefln(stderr,"Notes:");
>     fwritefln(stderr,"  dmd or gdmd must be in the current user context $PATH");
>     fwritefln(stderr,"  ",myname," does not support execution of D source code via stdin");
>     fwritefln(stderr,"  ",myname," will only compile and execute files with a '.d' file extension");
>     exit(EXIT_SUCCESS);
> }
> 
> bool compile(char[] tmpdir, char[] compiler, bool force, char[] dfilepath, char[][] cmpv, inout char[] exepath)
> {
>     int retval = 0;
> 
>     struct_stat dfilestat;  // D source code file status info.
>     int filrv = stat(dfilepath,&dfilestat);
> 
>     char[][] pathcomps = split(dfilepath,fileSeparator);
>     char[] exefile = split(pathcomps[$-1],".")[0];
> 
>     char[] cmdline = compiler ~ " -quiet";
>     foreach(char[] str; cmpv)
>         if(str != "")
>             cmdline ~= " " ~ str;
> 
>     // MD5 sum of compiler arguments
>     ubyte[16] digest;
>     sum(digest,cast(void[])cmdline);
> 
>     // directory for temp. files
>     if(!tmpdir.length)
>         tmpdir = "/tmp/";
>     else
>         if(tmpdir[$-1] != fileSeparator[0])
>             tmpdir ~= fileSeparator;
> 
>     // exe filename format is basename-uid-filesysdev-inode-MD5
>     // append MD5 sum of the compiler arguments onto the file name to force recompile if they have changed
>     exepath = tmpdir ~ exefile ~ "-" ~ toString(getuid()) ~ "-" ~ toString(dfilestat.st_dev) ~ "-" ~ toString(dfilestat.st_ino) ~ "-" ~ digestToString(digest) ~ exeExtension;
> 
>     struct_stat exestat;    // temp. executable status info.
>     int exerv = stat(exepath,&exestat);
>     if(force ||                                 // force compilation
>        exerv ||                                 // stat returned an error (e.g.: no exefile)
>        dfilestat.st_mtime > exestat.st_mtime || // source code file is newer than executable
>        progstat(.myname).st_mtime > exestat.st_mtime || // this program is newer than executable
>        progstat(compiler).st_mtime > exestat.st_mtime)  // compiler is newer than executable
>     {
>         cmdline ~= " " ~ dfilepath ~ " -of" ~ exepath ~ " -od" ~ tmpdir;
>         if(verbose)
>         {
>             fwritefln(stderr,"running: ",cmdline);
>         }
>         retval = system(cmdline);   // compile
>         chmod(exepath,0700);
>     }
> 
>     // remove object file
>     try { std.file.remove(tmpdir ~ exefile ~ objectExtension); } catch {}
> 
>     return cast(bool)(retval == 0);
> }
> 
> struct_stat progstat(char[] program)
> {
>     struct_stat progstat;  // D source code file status info.
> 
>     try
>     {
>         int prgrv;
>         if(find(program,fileSeparator) >= 0)
>             prgrv = stat(program, &progstat);
>         else
>         {
>             // There's got to be a better way...
>             char[][] pathdirs = split(toString(getenv("PATH")),pathSeparator);
>             foreach(char[] dir; pathdirs)
>             {
>                 prgrv = stat(dir ~ fileSeparator ~ program, &progstat);
>                 if (prgrv == 0)
>                 {
>                     break;
>                 }
>             }
>         }
>     }
>     catch {}
> 
>     return progstat;
> }
> 
> version(linux)
> {
> int spawnapp(char[] pathname, char[][] argv)
> {
>     int retval = 0;
>     pid_t pid = fork();
> 
>     if(pid != -1)
>     {
>         if(pid == 0)
>         {
>             execv(pathname,argv);
>             goto Lerror;
>         }
> 
>         while(1)
>         {
>             int status;
>             pid_t wpid = waitpid(pid, &status, 0);
>             if(exited(status))
>             {
>                 retval = exitstatus(status);
>                 break;
>             }
>             else if(signaled(status))
>             {
>                 retval = -termsig(status);
>                 break;
>             }
>             else if(stopped(status)) // ptrace support
>                 continue;
>             else
>                 goto Lerror;
>         }
> 
>         return retval;
>     }
> 
> Lerror:
>     retval = getErrno;
>     error("Cannot spawn " ~ toString(pathname) ~ "; " ~ toString(strerror(retval)) ~ " [errno " ~ toString(retval) ~ "]", retval);
>     return retval;
> }
> 
> extern(C)
> {
>     char* strerror(int);
>     ushort getuid();
> }
> bool stopped(int status)    { return cast(bool)((status & 0xff) == 0x7f); }
> bool signaled(int status)   { return cast(bool)((cast(char)((status & 0x7f) + 1) >> 1) > 0); }
> int  termsig(int status)    { return status & 0x7f; }
> bool exited(int status)     { return cast(bool)((status & 0x7f) == 0); }
> int  exitstatus(int status) { return (status & 0xff00) >> 8; }
> 
> } // version(linux)
> 
> version (Windows)
> {
>   extern (Windows)
>   {
>     BOOL GetFileTime(HANDLE hFile, LPFILETIME lpCreationTime,
>                      LPFILETIME lpLastAccessTime, LPFILETIME lpLastWriteTime);
>     BOOL GetUserNameA(LPTSTR lpBuffer, LPDWORD nSize);
>   }
> 
>   // fake struct stat
>   struct struct_stat
>   {
>     ulong st_dev;
>     uint st_ino;
>     ulong st_mtime;
>   }
> 
>   // fake stat function
>   int stat(char* name, struct_stat* st)
>   {
>     int retval = -1;
>     HANDLE h = CreateFileA(name, FILE_GENERIC_READ, 0, null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, null);
>     if (h != INVALID_HANDLE_VALUE)
>     {
>       FILETIME lastWriteTime;
>       if (GetFileTime(h, null, null, &lastWriteTime))
>       {
>         st.st_mtime = lastWriteTime.dwHighDateTime;
>         st.st_mtime <<= 32;
>         st.st_mtime |= lastWriteTime.dwLowDateTime;
>         retval = 0;
>       }
>       CloseHandle(h);
>     }
>     if(verbose)
>     {
>       fwritefln(stderr,"stat: ",toString(name)," : ",retval);
>     }
>     return retval;
>   }
> 
>   // fake getuid function
>   char[] getuid()
>   {
>     char[] buffer;
>     DWORD size = buffer.length = 64;
>     if(GetUserNameA(buffer, &size))
>     {
>       buffer.length = size;
>       return buffer;
>     }
>     return "";
>   }
> 
>   // fake chmod function
>   void chmod(...)
>   {
>   }
> }

-- 

v1sw5+8Yhw5ln4+5pr6OFma8u6+7Lw4Tm6+7l6+7D
a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP    http://hackerkey.com/



More information about the Digitalmars-d mailing list