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