Integrate rdmd into compiler?
Dave
Dave_member at pathlink.com
Tue Apr 25 07:38:54 PDT 2006
Daniel Keep wrote:
> AFAIK it has been integrated; not sure when it happened. Try `dmd -run
> SCRIPT`. As for gdc, I have no idea.
>
> -- Daniel
>
Thanks - I realize that but didn't make clear what I was asking.. rdmd
adds a couple features that 'dmd -run' doesn't have:
- caching the executable
- passing in compiler options
I want to know the opinion of others of adding this to dmd itself and
also opinions on the source code below (e.g.: security holes that I may
be missing).
Thanks,
- Dave
> 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(...)
>> {
>> }
>> }
>
More information about the Digitalmars-d
mailing list