changeset 986:a8cb25d478c4

Use LLVM-style command line (instead of DMD-style) Note: For a backward compatible interface, use the new bin/ldmd script. It supports all old options while passing on anything it doesn't recognize. Some changes caused by this: * -debug and -version are now -d-debug and -d-version due to a conflict with standard LLVM options. * All "flag" options now allow an optional =true/=1/=false/=0 suffix. * Some "hidden debug switches" starting with "--" were renamed because LLVM doesn't care about the number of dashes, so they were conflicting with other options (such as -c). The new versions start with "-hidden-debug-" instead of "--" * --help works, but has a non-zero exit code. This breaks some Tango scripts which use it to test for compiler existence. See tango.patch. Some changes not (directly) caused by this; * (-enable/-disable)-FOO options are now available for pre- and postconditions. * -march is used instead of -m (like other LLVM programs), but -m is an alias for it. * -defaultlib, -debuglib, -d-debug and -d-version allow comma-separated values. The effect should be identical to specifying the same option multiple times. I decided against allowing these for some other options because paths might contain commas on some systems. * -fPIC is removed in favor of the standard LLVM option -relocation-model=pic Bug: * If -run is specified as the last argument in DFLAGS, no error is generated. (Not very serious IMHO)
author Frits van Bommel <fvbommel wxs.nl>
date Wed, 25 Feb 2009 17:34:51 +0100
parents bce024c60adc
children 73ff89728d85
files bin/ldmd dmd/attrib.c dmd/mars.c dmd/mars.h dmd/module.c gen/cl_helpers.cpp gen/cl_helpers.h gen/cl_options.cpp gen/cl_options.h gen/linker.cpp gen/linker.h gen/logger.cpp gen/runtime.cpp gen/toobj.cpp ldc-posix-tango ldc.conf.in tango.patch
diffstat 17 files changed, 910 insertions(+), 551 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/ldmd	Wed Feb 25 17:34:51 2009 +0100
@@ -0,0 +1,41 @@
+#! /usr/bin/env bash
+
+# Default to 'ldc' next to this file
+LDC=`basename "$0"`/ldc
+if [ ! -x "$LDC" ]; then
+    # If that doesn't work, assume this script was called via $PATH
+    # and do the same for ldc
+    if which ldc &> /dev/null; then
+        LDC=ldc
+    else
+        echo 'ldc not found, check your installation' >/dev/stderr
+        exit 1
+    fi
+fi
+
+declare -a ARGS
+SeenFile=0
+IDX=0
+for arg; do
+    case "$arg" in
+    -debug|-debug=*|-version=*)
+        arg="-d$arg"
+        ;;
+    -fPIC)
+        arg="-relocation-model=pic"
+        ;;
+    --a|--b|--c|--f|--r|--w|--x|--y)
+        # "Hidden debug switches"
+        # Are these ever used?
+        arg="-hidden-debug${arg:1}"
+        ;;
+    -*)
+        ;;
+    *)
+        SeenFile=1
+        ;;
+    esac
+    ARGS[IDX++]="$arg"
+done
+
+exec "$LDC" "${ARGS[@]}"
--- a/dmd/attrib.c	Thu Feb 19 13:51:44 2009 +0100
+++ b/dmd/attrib.c	Wed Feb 25 17:34:51 2009 +0100
@@ -33,6 +33,15 @@
 
 #include "../gen/enums.h"
 
+
+#include "llvm/Support/CommandLine.h"
+
+static llvm::cl::opt<bool> ignoreUnsupportedPragmas("ignore",
+    llvm::cl::desc("Ignore unsupported pragmas"),
+    llvm::cl::ZeroOrMore);
+
+
+
 extern void obj_includelib(const char *name);
 void obj_startaddress(Symbol *s);
 
@@ -962,7 +971,7 @@
 
 #endif // LDC
 
-    else if (global.params.ignoreUnsupportedPragmas)
+    else if (ignoreUnsupportedPragmas)
     {
 	if (global.params.verbose)
 	{
--- a/dmd/mars.c	Thu Feb 19 13:51:44 2009 +0100
+++ b/dmd/mars.c	Wed Feb 25 17:34:51 2009 +0100
@@ -40,6 +40,42 @@
 #include "gen/linker.h"
 #include "revisions.h"
 
+#include "gen/cl_options.h"
+#include "gen/cl_helpers.h"
+using namespace opts;
+
+
+static cl::opt<bool> forceBE("forcebe",
+    cl::desc("Force big-endian"),
+    cl::Hidden,
+    cl::ZeroOrMore);
+
+static cl::opt<bool> noDefaultLib("nodefaultlib",
+    cl::desc("Don't add a default library for linking implicitly"),
+    cl::ZeroOrMore);
+
+static ArrayAdapter impPathsStore("I", global.params.imppath);
+static cl::list<std::string, ArrayAdapter> importPaths("I",
+    cl::desc("Where to look for imports"),
+    cl::value_desc("path"),
+    cl::location(impPathsStore),
+    cl::Prefix);
+
+static ArrayAdapter defaultLibStore("defaultlib", global.params.defaultlibnames);
+static cl::list<std::string, ArrayAdapter> defaultlibs("defaultlib",
+    cl::desc("Set default libraries for non-debug build"),
+    cl::value_desc("lib,..."),
+    cl::location(defaultLibStore),
+    cl::CommaSeparated);
+
+static ArrayAdapter debugLibStore("debuglib", global.params.debuglibnames);
+static cl::list<std::string, ArrayAdapter> debuglibs("debuglib",
+    cl::desc("Set default libraries for debug build"),
+    cl::value_desc("lib,..."),
+    cl::location(debugLibStore),
+    cl::CommaSeparated);
+
+
 void getenv_setargv(const char *envvar, int *pargc, char** *pargv);
 
 Global global;
@@ -68,13 +104,17 @@
     llvm_version = LLVM_REV;
     global.structalign = 8;
 
-    memset(&params, 0, sizeof(Param));
+    // This should only be used as a global, so the other fields are
+    // automatically initialized to zero when the program is loaded.
+    // In particular, DO NOT zero-initialize .params here (like DMD
+    // does) because command-line options initialize some of those
+    // fields to non-zero defaults, and do so from constructors that
+    // may run before this one.
 }
 
 char *Loc::toChars() const
 {
     OutBuffer buf;
-    char *p;
 
     if (filename)
     {
@@ -150,98 +190,49 @@
 extern void backend_init();
 extern void backend_term();
 
-void usage()
-{
+void printVersion() {
     printf("LLVM D Compiler %s\nbased on DMD %s and %s\n%s\n%s\n",
     global.ldc_version, global.version, global.llvm_version, global.copyright, global.written);
-    printf("\
-D Language Documentation: http://www.digitalmars.com/d/1.0/index.html\n\
-LDC Homepage: http://www.dsource.org/projects/ldc\n\
-Usage:\n\
-  ldc files.d ... { -switch }\n\
-\n\
-  files.d        D source files\n%s\
-  -o-            do not write object file\n\
-  -od<objdir>    write object files to directory <objdir>\n\
-  -op            do not strip paths from source file\n\
-  -oq            write object files with fully qualified names\n\
-  -of<filename>  name output file to <filename>\n\
-                 if -c and extension of <filename> is known, it determines the output type\n\
-\n\
-  -output-ll     write LLVM IR\n\
-  -output-bc     write LLVM bitcode\n\
-  -output-s      write native assembly\n\
-  -output-o      write native object (default if no -output switch passed)\n\
-\n\
-  -c             do not link\n\
-  -L<linkerflag> pass <linkerflag> to linker\n\
-\n\
-  -w             enable warnings\n\
-\n\
-  -H             generate 'header' file\n\
-  -Hd<hdrdir>    write 'header' file to <hdrdir> directory\n\
-  -Hf<filename>  write 'header' file to <filename>\n\
-\n\
-  -D             generate documentation\n\
-  -Dd<docdir>    write documentation file to <docdir> directory\n\
-  -Df<filename>  write documentation file to <filename>\n\
-\n\
-Codegen control:\n\
-  -m<arch>       emit code specific to <arch> being one of:\n\
-                 x86 x86-64 ppc32 ppc64 arm thumb\n\
-  -t<os>         emit code specific to <os> being one of:\n\
-                 Linux, Windows, MacOSX, FreeBSD, Solaris\n\
-\n\
-  -g, -gc        add symbolic debug info\n\
-\n\
-  -O             optimize, same as -O2\n\
-  -O<n>          optimize at level <n> (0-5)\n\
-  -inline        do function inlining\n\
-\n\
-  -debug         enables asserts, invariants, contracts, boundscheck\n\
-                 and sets debug=1\n\
-  -release       disables asserts, invariants, contracts, boundscheck\n\
-\n\
-  -enable-<feature>    and\n\
-  -disable-<feature>   where <feature> is one of\n\
-    asserts      assert statements (default: on)\n\
-    invariants   class and struct invariants (default: on)\n\
-    contracts    function contracts (default: on)\n\
-    boundscheck  array bounds checking (default: on)\n\
-  -debug=level   compile in debug stmts <= level (default: 0)\n\
-  -debug=ident   compile in debug stmts identified by ident\n\
-  -version=level compile in version code >= level\n\
-  -version=ident compile in version code identified by ident\n\
-\n\
-  -noasm         do not allow use of inline asm\n\
-  -noruntime     do not allow code that generates implicit runtime calls\n\
-  -noverify      do not run the validation pass before writing bitcode\n\
-  -unittest      compile in unit tests\n\
-  -d             allow deprecated features\n\
-\n\
-  -annotate      annotate the bitcode with human readable source code\n\
-  -ignore        ignore unsupported pragmas\n\
-\n\
-Path options:\n\
-  -I<path>       where to look for imports\n\
-  -J<path>       where to look for string imports\n\
-  -defaultlib=name  set default library for non-debug build\n\
-  -debuglib=name    set default library for debug build\n\
-  -nodefaultlib  don't add a default library for linking implicitly\n\
-\n\
-Misc options:\n\
-  -v             verbose\n\
-  -vv            very verbose (does not include -v)\n\
-  -quiet         suppress unnecessary messages\n\
-  -run srcfile args...   run resulting program, passing args\n\
-  --help         print help\n\
-",
-#if WIN32
-"  @cmdfile       read arguments from cmdfile\n"
-#else
-""
-#endif
-);
+    printf("D Language Documentation: http://www.digitalmars.com/d/1.0/index.html\n"
+           "LDC Homepage: http://www.dsource.org/projects/ldc\n");
+}
+
+// Helper function to handle -d-debug=* and -d-version=*
+static void processVersions(std::vector<std::string>& list, char* type,
+        void (*setLevel)(unsigned), void (*addIdent)(char*)) {
+    typedef std::vector<std::string>::iterator It;
+
+    for(It I = list.begin(), E = list.end(); I != E; ++I) {
+        const char* value = I->c_str();
+        if (isdigit(value[0])) {
+            errno = 0;
+            char* end;
+            long level = strtol(value, &end, 10);
+            if (*end || errno || level > INT_MAX) {
+                error("Invalid %s level: %s", type, I->c_str());
+            } else {
+                setLevel((unsigned)level);
+            }
+        } else {
+            char* cstr = mem.strdup(value);
+            if (Lexer::isValidIdentifier(cstr)) {
+                addIdent(cstr);
+                continue;
+            } else {
+                error("Invalid %s identifier or level: '%s'", type, I->c_str());
+            }
+        }
+    }
+}
+
+// Helper function to handle -of, -od, etc.
+static void initFromString(char*& dest, const cl::opt<std::string>& src) {
+    dest = 0;
+    if (src.getNumOccurrences() != 0) {
+        if (src.empty())
+            error("Expected argument to '-%s'", src.ArgStr);
+        dest = mem.strdup(src.c_str());
+    }
 }
 
 int main(int argc, char *argv[])
@@ -251,28 +242,6 @@
     char *p, *ext;
     Module *m;
     int status = EXIT_SUCCESS;
-    int argcstart = argc;
-    bool very_verbose = false;
-
-    // Check for malformed input
-    if (argc < 1 || !argv)
-    {
-      Largs:
-	error("missing or null command line arguments");
-	fatal();
-    }
-    for (i = 0; i < argc; i++)
-    {
-	if (!argv[i])
-	    goto Largs;
-    }
-
-#if __DMC__	// DMC unique support for response files
-    if (response_expand(&argc,&argv))	// expand response files
-	error("can't open response file");
-#endif
-
-    files.reserve(argc - 1);
 
     // Set default values
 #if _WIN32
@@ -282,20 +251,7 @@
 #else
     global.params.argv0 = argv[0];
 #endif
-    global.params.link = 1;
-    global.params.useAssert = 1;
-    global.params.useInvariants = 1;
-    global.params.useIn = 1;
-    global.params.useOut = 1;
-    global.params.useArrayBounds = 1;
     global.params.useSwitchError = 1;
-    global.params.useInline = 0; // this one messes things up to a point where codegen breaks
-    global.params.llvmInline = 0; // use this one instead to know if inline passes should be run
-    global.params.obj = 1;
-    global.params.Dversion = 2;
-    global.params.quiet = 1;
-
-    global.params.output_o = OUTPUTFLAGdefault;
 
     global.params.linkswitches = new Array();
     global.params.libfiles = new Array();
@@ -315,14 +271,6 @@
         fatal();
     }
 
-    global.params.llvmArch = 0;
-    global.params.forceBE = 0;
-    global.params.noruntime = 0;
-    global.params.novalidate = 0;
-    global.params.optimizeLevel = -1;
-    global.params.runtimeImppath = 0;
-    global.params.useInlineAsm = 1;
-
     // Predefine version identifiers
 #if IN_LLVM
     VersionCondition::addPredefinedGlobalIdent("LLVM");
@@ -365,362 +313,81 @@
     }
 #endif
 
-    for (i = 1; i < argc; i++)
-    {
-	p = argv[i];
-	if (*p == '-')
-	{
-	    if (strcmp(p + 1, "d") == 0)
-		global.params.useDeprecated = 1;
-	    else if (strcmp(p + 1, "c") == 0)
-		global.params.link = 0;
-	    else if (strcmp(p + 1, "fPIC") == 0)
-		global.params.pic = 1;
-	    else if (strcmp(p + 1, "g") == 0)
-		global.params.symdebug = 1;
-        else if (strcmp(p + 1, "gc") == 0)
-        global.params.symdebug = 2;
-	    else if (strcmp(p + 1, "v") == 0)
-		global.params.verbose = 1;
-		else if (strcmp(p + 1, "vv") == 0) {
-    		Logger::enable();
-    		very_verbose = true;
-		}
-	    else if (strcmp(p + 1, "v1") == 0)
-		global.params.Dversion = 1;
-	    else if (strcmp(p + 1, "w") == 0)
-		global.params.warnings = 1;
-	    else if (p[1] == 'O')
-        {
-            global.params.optimize = 1;
-            global.params.optimizeLevel = 2;
-            if (p[2] != 0) {
-                int optlevel = atoi(p+2);
-                if (optlevel < 0 || optlevel > 5) {
-                    error("Optimization level must be between 0 and 5. Using default (%d)",
-                    global.params.optimizeLevel);
-                }
-                else {
-                    global.params.optimizeLevel = optlevel;
-                }
-            }
-        }
-        else if (strcmp(p + 1, "forcebe") == 0)
-            global.params.forceBE = 1;
-        else if (strcmp(p + 1, "noruntime") == 0)
-            global.params.noruntime = 1;
-        else if (strcmp(p + 1, "noverify") == 0)
-            global.params.novalidate = 1;
-        else if (strcmp(p + 1, "annotate") == 0)
-            global.params.llvmAnnotate = 1;
-        else if (strncmp(p + 1, "enable-", 7) == 0 ||
-                 strncmp(p + 1, "disable-", 8) == 0)
-        {
-            bool enable = (p[1] == 'e');
-            char* feature = p + 1 + (enable ? 7 : 8);
-            if (strcmp(feature, "asserts") == 0)
-                global.params.useAssert = enable;
-            else if (strcmp(feature, "boundscheck") == 0)
-                global.params.useArrayBounds = enable;
-            else if (strcmp(feature, "contracts") == 0)
-            {
-                global.params.useIn = enable;
-                global.params.useOut = enable;
-            }
-            else if (strcmp(feature, "invariants") == 0)
-                global.params.useInvariants = enable;
-            else
-                error("unrecognized feature '%s'", feature);
-        }
-        else if (strcmp(p + 1, "noasm") == 0)
-            global.params.useInlineAsm = 0;
-        else if (strcmp(p + 1, "nodefaultlib") == 0)
-            global.params.noDefaultLib = 1;
-	    else if (p[1] == 'o')
-	    {
-		switch (p[2])
-		{
-		    case '-':
-			global.params.obj = 0;
-			break;
+    cl::SetVersionPrinter(&printVersion);
+    cl::ParseCommandLineOptions(argc, argv, "LLVM-based D Compiler\n");
+
+    global.params.optimize = (global.params.optimizeLevel >= 0);
 
-		    case 'd':
-			if (!p[3])
-			    goto Lnoarg;
-			global.params.objdir = p + 3;
-			break;
+    // Negated options
+    global.params.link = !compileOnly;
+    global.params.obj = !dontWriteObj;
+    global.params.useInlineAsm = !noAsm;
 
-		    case 'f':
-			if (!p[3])
-			    goto Lnoarg;
-			global.params.objname = p + 3;
-			break;
-
-		    case 'p':
-			if (p[3])
-			    goto Lerror;
-			global.params.preservePaths = 1;
-			break;
-
-		    case 'q':
-			if (p[3])
-			    goto Lerror;
-			global.params.fqnNames = 1;
-			break;
-
-		    case 'u':
-			if (strncmp(p+1, "output-", 7) != 0)
-			    goto Lerror;
-
-			// remove default output
-			if (global.params.output_o == OUTPUTFLAGdefault)
-			    global.params.output_o = OUTPUTFLAGno;
-
-			if (strcmp(p+8, global.ll_ext) == 0)
-			    global.params.output_ll = OUTPUTFLAGset;
-			else if (strcmp(p+8, global.bc_ext) == 0)
-			    global.params.output_bc = OUTPUTFLAGset;
-			else if (strcmp(p+8, global.s_ext) == 0)
-			    global.params.output_s = OUTPUTFLAGset;
-			else if (strcmp(p+8, global.obj_ext) == 0)
-			    global.params.output_o = OUTPUTFLAGset;
-			else
-			    goto Lerror;
-
-			break;
-
-		    case 0:
-			error("-o no longer supported, use -of or -od");
-			break;
+    // String options: std::string --> char*
+    initFromString(global.params.objname, objectFile);
+    initFromString(global.params.objdir, objectDir);
+    
+    initFromString(global.params.docdir, ddocDir);
+    initFromString(global.params.docname, ddocFile);
+    global.params.doDocComments |=
+        global.params.docdir || global.params.docname;
+    
+#ifdef _DH
+    initFromString(global.params.hdrdir, hdrDir);
+    initFromString(global.params.hdrname, hdrFile);
+    global.params.doHdrGeneration |=
+        global.params.hdrdir || global.params.hdrname;
+#endif
 
-		    default:
-			goto Lerror;
-		}
-	    }
-	    else if (p[1] == 'D')
-	    {	global.params.doDocComments = 1;
-		switch (p[2])
-		{
-		    case 'd':
-			if (!p[3])
-			    goto Lnoarg;
-			global.params.docdir = p + 3;
-			break;
-		    case 'f':
-			if (!p[3])
-			    goto Lnoarg;
-			global.params.docname = p + 3;
-			break;
-
-		    case 0:
-			break;
-
-		    default:
-			goto Lerror;
-		}
-	    }
-#ifdef _DH
-	    else if (p[1] == 'H')
-	    {	global.params.doHdrGeneration = 1;
-		switch (p[2])
-		{
-		    case 'd':
-			if (!p[3])
-			    goto Lnoarg;
-			global.params.hdrdir = p + 3;
-			break;
-
-		    case 'f':
-			if (!p[3])
-			    goto Lnoarg;
-			global.params.hdrname = p + 3;
-			break;
-
-		    case 0:
-			break;
+    processVersions(debugArgs, "debug",
+        DebugCondition::setGlobalLevel,
+        DebugCondition::addGlobalIdent);
+    processVersions(versions, "version",
+        VersionCondition::setGlobalLevel,
+        VersionCondition::addGlobalIdent);
 
-		    default:
-			goto Lerror;
-		}
-	    }
-#endif
-	    else if (strcmp(p + 1, "ignore") == 0)
-		global.params.ignoreUnsupportedPragmas = 1;
-	    else if (strcmp(p + 1, "inline") == 0) {
-            // TODO
-            // the ast rewrites dmd does for inlining messes up the ast.
-            // someday maybe we can support it, for now llvm does an excellent job at inlining
-            global.params.useInline = 0; //1
-            global.params.llvmInline = 1;
-        }
-	    else if (strcmp(p + 1, "quiet") == 0)
-		global.params.quiet = 1;
-	    else if (strcmp(p + 1, "release") == 0)
-	    {
-		global.params.useInvariants = 0;
-		global.params.useIn = 0;
-		global.params.useOut = 0;
-		global.params.useAssert = 0;
-		global.params.useArrayBounds = 0;
-	    }
-	    else if (strcmp(p + 1, "unittest") == 0)
-		global.params.useUnitTests = 1;
-	    else if (p[1] == 'I')
-	    {
-		if (!global.params.imppath)
-		    global.params.imppath = new Array();
-		global.params.imppath->push(p + 2);
-	    }
-	    else if (p[1] == 'J')
-	    {
-		if (!global.params.fileImppath)
-		    global.params.fileImppath = new Array();
-		global.params.fileImppath->push(p + 2);
-	    }
-	    else if (memcmp(p + 1, "debug", 5) == 0 && p[6] != 'l')
-	    {
-		// Parse:
-		//	-debug
-		//	-debug=number
-		//	-debug=identifier
-		if (p[6] == '=')
-		{
-		    if (isdigit(p[7]))
-		    {	long level;
-
-			errno = 0;
-			level = strtol(p + 7, &p, 10);
-			if (*p || errno || level > INT_MAX)
-			    goto Lerror;
-			DebugCondition::setGlobalLevel((int)level);
-		    }
-		    else if (Lexer::isValidIdentifier(p + 7))
-			DebugCondition::addGlobalIdent(p + 7);
-		    else
-			goto Lerror;
-		}
-		else if (p[6])
-		    goto Lerror;
-		else
-		{
-		    global.params.useInvariants = 1;
-		    global.params.useIn = 1;
-		    global.params.useOut = 1;
-		    global.params.useAssert = 1;
-		    global.params.useArrayBounds = 1;
-		    global.params.debuglevel = 1;
-		}
-	    }
-	    else if (memcmp(p + 1, "version", 5) == 0)
-	    {
-		// Parse:
-		//	-version=number
-		//	-version=identifier
-		if (p[8] == '=')
-		{
-		    if (isdigit(p[9]))
-		    {	long level;
+    global.params.output_o =
+        opts::output_o == cl::BOU_UNSET
+        ? OUTPUTFLAGdefault
+        : opts::output_o == cl::BOU_TRUE
+            ? OUTPUTFLAGset
+            : OUTPUTFLAGno;
+    global.params.output_bc = opts::output_bc ? OUTPUTFLAGset : OUTPUTFLAGno;
+    global.params.output_ll = opts::output_ll ? OUTPUTFLAGset : OUTPUTFLAGno;
+    global.params.output_s  = opts::output_s  ? OUTPUTFLAGset : OUTPUTFLAGno;
 
-			errno = 0;
-			level = strtol(p + 9, &p, 10);
-			if (*p || errno || level > INT_MAX)
-			    goto Lerror;
-			VersionCondition::setGlobalLevel((int)level);
-		    }
-		    else if (Lexer::isValidIdentifier(p + 9))
-			VersionCondition::addGlobalIdent(p + 9);
-		    else
-			goto Lerror;
-		}
-		else
-		    goto Lerror;
-	    }
-	    else if (strcmp(p + 1, "-b") == 0)
-		global.params.debugb = 1;
-	    else if (strcmp(p + 1, "-c") == 0)
-		global.params.debugc = 1;
-	    else if (strcmp(p + 1, "-f") == 0)
-		global.params.debugf = 1;
-	    else if (strcmp(p + 1, "-help") == 0)
-	    {	usage();
-		exit(EXIT_SUCCESS);
-	    }
-	    else if (strcmp(p + 1, "-r") == 0)
-		global.params.debugr = 1;
-	    else if (strcmp(p + 1, "-x") == 0)
-		global.params.debugx = 1;
-	    else if (strcmp(p + 1, "-y") == 0)
-		global.params.debugy = 1;
-	    else if (p[1] == 'L')
-	    {
-		global.params.linkswitches->push(p + 2);
-	    }
-	    else if (memcmp(p + 1, "defaultlib=", 11) == 0)
-	    {
-		if(!global.params.defaultlibnames)
-		    global.params.defaultlibnames = new Array();
-		global.params.defaultlibnames->push(p + 1 + 11);
-	    }
-	    else if (memcmp(p + 1, "debuglib=", 9) == 0)
-	    {
-		if(!global.params.debuglibnames)
-		    global.params.debuglibnames = new Array();
-		global.params.debuglibnames->push(p + 1 + 9);
-	    }
-	    else if (strcmp(p + 1, "run") == 0)
-	    {	global.params.run = 1;
-		global.params.runargs_length = ((i >= argcstart) ? argc : argcstart) - i - 1;
-		if (global.params.runargs_length)
-		{
-		    files.push(argv[i + 1]);
-		    global.params.runargs = &argv[i + 2];
-		    i += global.params.runargs_length;
-		    global.params.runargs_length--;
-		}
-		else
-		{   global.params.run = 0;
-		    goto Lnoarg;
-		}
-	    }
-        else if (p[1] == 'm')
-        {
-            global.params.llvmArch = p+2;
+    if (global.params.run || !runargs.empty()) {
+        // FIXME: how to properly detect the presence of a PositionalEatsArgs
+        // option without parameters? We want to emit an error in that case...
+        // You'd think getNumOccurrences would do it, but it just returns the
+        // number of parameters)
+        // NOTE: Hacked around it by detecting -run in getenv_setargv(), where
+        // we're looking for it anyway, and pre-setting the flag...
+        global.params.run = true;
+        if (!runargs.empty()) {
+            files.push(mem.strdup(runargs[0].c_str()));
+        } else {
+            global.params.run = false;
+            error("Expected at least one argument to '-run'\n");
         }
-        else if (p[1] == 't')
-        {
-            if(strcmp(p + 2, "Linux") == 0)
-                global.params.os = OSLinux;
-            else if(strcmp(p + 2, "Windows") == 0)
-                global.params.os = OSWindows;
-            else if(strcmp(p + 2, "MacOSX") == 0)
-                global.params.os = OSMacOSX;
-            else if(strcmp(p + 2, "FreeBSD") == 0)
-                global.params.os = OSFreeBSD;
-            else if(strcmp(p + 2, "Solaris") == 0)
-                global.params.os = OSSolaris;
-            else
-                error("unrecognized target os '%s'", p + 2);
-        }
-	    else
-	    {
-	     Lerror:
-		error("unrecognized switch '%s'", argv[i]);
-		continue;
+    }
+
+    if (mArch)
+        global.params.llvmArch = mArch->Name;
 
-	     Lnoarg:
-		error("argument expected for switch '%s'", argv[i]);
-		continue;
-	    }
-	}
-	else
-	    files.push(p);
-    }
+    files.reserve(fileList.size());
+    typedef std::vector<std::string>::iterator It;
+    for(It I = fileList.begin(), E = fileList.end(); I != E; ++I)
+        if (!I->empty())
+            files.push(mem.strdup(I->c_str()));
+
     if (global.errors)
     {
 	fatal();
     }
     if (files.dim == 0)
-    {	usage();
+    {
+        cl::PrintHelpMessage();
 	return EXIT_FAILURE;
     }
 
@@ -740,7 +407,7 @@
 	    global.params.linkswitches->push(arg);
 	}
     }
-    else if (!global.params.noDefaultLib)
+    else if (!noDefaultLib)
     {
 	char *arg;
 	arg = (char *)mem.malloc(64);
@@ -760,7 +427,7 @@
     }
 
     if (global.params.run)
-	global.params.quiet = 1;
+        quiet = 1;
 
     if (global.params.useUnitTests)
 	global.params.useAssert = 1;
@@ -893,7 +560,7 @@
 
     assert(global.params.cpu != ARCHinvalid);
 
-    if (allowForceEndianness && global.params.forceBE) {
+    if (allowForceEndianness && forceBE) {
         VersionCondition::addPredefinedGlobalIdent("BigEndian");
         global.params.isLE = false;
     }
@@ -1306,8 +973,24 @@
     argv = new Array();
     argv->setDim(argc);
 
-    for (int i = 0; i < argc; i++)
-	argv->data[i] = (void *)(*pargv)[i];
+    int argc_left = 0;
+    for (int i = 0; i < argc; i++) {
+        if (!strcmp((*pargv)[i], "-run") || !strcmp((*pargv)[i], "--run")) {
+            // HACK: set flag to indicate we saw '-run' here
+            global.params.run = true;
+            // Don't eat -run yet so the program arguments don't get changed
+            argc_left = argc - i;
+            argc = i;
+            *pargv = &(*pargv)[i];
+            argv->setDim(i);
+            break;
+        } else {
+            argv->data[i] = (void *)(*pargv)[i];
+        }
+    }
+    // HACK to stop required values from command line being drawn from DFLAGS
+    argv->push((char*)"");
+    argc++;
 
     j = 1;			// leave argv[0] alone
     while (1)
@@ -1382,6 +1065,11 @@
     }
 
 Ldone:
+    assert(argc == argv->dim);
+    argv->reserve(argc_left);
+    for (int i = 0; i < argc_left; i++)
+        argv->data[argc++] = (void *)(*pargv)[i];
+
     *pargc = argc;
     *pargv = (char **)argv->data;
 }
--- a/dmd/mars.h	Thu Feb 19 13:51:44 2009 +0100
+++ b/dmd/mars.h	Wed Feb 25 17:34:51 2009 +0100
@@ -17,6 +17,7 @@
 
 #include <stdint.h>
 #include <stdarg.h>
+#include <stddef.h>
 #define __STDC_FORMAT_MACROS 1
 #include <inttypes.h>
 #include <stdarg.h>
@@ -72,48 +73,40 @@
 // Put command line switches in here
 struct Param
 {
-    char obj;		// write object file
-    char link;		// perform link
-    char quiet;		// suppress non-error messages
-    char verbose;	// verbose compile
+    bool obj;           // write object file
+    bool link;          // perform link
+    bool verbose;       // verbose compile
     char symdebug;	// insert debug symbolic information
-    char optimize;	// run optimizer
+    bool optimize;      // run optimizer
     char optimizeLevel; // optimization level
     ARCH cpu;		// target CPU
     OS   os;		// target OS
-    char is64bit;	// generate 64 bit code
-    char isLE;      // generate little endian code
-    char scheduler;	// which scheduler to use
-    char useDeprecated;	// allow use of deprecated features
-    char useAssert;	// generate runtime code for assert()'s
-    char useInvariants;	// generate class invariant checks
-    char useIn;		// generate precondition checks
-    char useOut;	// generate postcondition checks
-    char useArrayBounds; // generate array bounds checks
-    char useSwitchError; // check for switches without a default
-    char useUnitTests;	// generate unittest code
-    char useInline;	// inline expand functions
-    char preservePaths;	// !=0 means don't strip path from source file
-    char warnings;	// enable warnings
-    char pic;		// generate position-independent-code for shared libs
-    char noruntime;	// code is not allowed to make implicit calls to the runtime
-    char novalidate;// no bitcode validation
+    bool is64bit;       // generate 64 bit code
+    bool isLE;          // generate little endian code
+    bool useDeprecated; // allow use of deprecated features
+    bool useAssert;     // generate runtime code for assert()'s
+    bool useInvariants; // generate class invariant checks
+    bool useIn;         // generate precondition checks
+    bool useOut;        // generate postcondition checks
+    bool useArrayBounds; // generate array bounds checks
+    bool useSwitchError; // check for switches without a default
+    bool useUnitTests;  // generate unittest code
+    bool useInline;     // inline expand functions
+    bool warnings;      // enable warnings
     char Dversion;	// D version number
-    char ignoreUnsupportedPragmas;	// rather than error on them
 
     char *argv0;	// program name
     Array *imppath;	// array of char*'s of where to look for import modules
     Array *fileImppath;	// array of char*'s of where to look for file import modules
-    char *runtimeImppath; // char* of where to look for the core runtime
     char *objdir;	// .obj file output directory
     char *objname;	// .obj file output name
 
-    char doDocComments;	// process embedded documentation comments
+    bool doDocComments; // process embedded documentation comments
     char *docdir;	// write documentation file to docdir directory
     char *docname;	// write documentation file to docname
     Array *ddocfiles;	// macro include files for Ddoc
 
-    char doHdrGeneration;	// process embedded documentation comments
+    bool doHdrGeneration;       // process embedded documentation comments
     char *hdrdir;		// write 'header' file to docdir directory
     char *hdrname;		// write 'header' file to docname
 
@@ -131,18 +124,16 @@
     char *xmlname;		// filename for XML output
 
     // Hidden debug switches
-    char debuga;
-    char debugb;
-    char debugc;
-    char debugf;
-    char debugr;
-    char debugw;
-    char debugx;
-    char debugy;
+    bool debuga;
+    bool debugb;
+    bool debugc;
+    bool debugf;
+    bool debugr;
+    bool debugw;
+    bool debugx;
+    bool debugy;
 
-    char run;		// run resulting executable
-    size_t runargs_length;
-    char** runargs;	// arguments for executable
+    bool run;           // run resulting executable
 
     // Linker stuff
     Array *objfiles;
@@ -153,17 +144,14 @@
     char *exefile;
 
     // LDC stuff
-    char *llvmArch;
-    char forceBE;
-    char output_ll;
-    char output_bc;
-    char output_s;
-    char output_o;
-    char llvmInline;
-    char llvmAnnotate;
-    char useInlineAsm;
-    char fqnNames; // use fully qualified object names
-    char noDefaultLib;
+    const char *llvmArch;
+    OUTPUTFLAG output_ll;
+    OUTPUTFLAG output_bc;
+    OUTPUTFLAG output_s;
+    OUTPUTFLAG output_o;
+    bool llvmInline;
+    bool llvmAnnotate;
+    bool useInlineAsm;
 
     // target stuff
     char *targetTriple;
--- a/dmd/module.c	Thu Feb 19 13:51:44 2009 +0100
+++ b/dmd/module.c	Wed Feb 25 17:34:51 2009 +0100
@@ -44,6 +44,19 @@
 #include "d-dmd-gcc.h"
 #endif
 
+
+#include "llvm/Support/CommandLine.h"
+
+static llvm::cl::opt<bool> preservePaths("op",
+    llvm::cl::desc("Do not strip paths from source file"),
+    llvm::cl::ZeroOrMore);
+
+static llvm::cl::opt<bool> fqnNames("oq",
+    llvm::cl::desc("Write object files with fully qualified names"),
+    llvm::cl::ZeroOrMore);
+
+
+
 ClassDeclaration *Module::moduleinfo;
 
 Module *Module::rootModule;
@@ -139,12 +152,12 @@
 	argobj = forcename;
     else
     {
-	if (global.params.preservePaths)
+	if (preservePaths)
 	    argobj = (char*)this->arg;
 	else
 	    argobj = FileName::name((char*)this->arg);
 
-	if (global.params.fqnNames)
+	if (fqnNames)
 	{
 	    if(md)
 		argobj = FileName::replaceName(argobj, md->toChars());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/cl_helpers.cpp	Wed Feb 25 17:34:51 2009 +0100
@@ -0,0 +1,81 @@
+#include "gen/cl_helpers.h"
+
+#include "dmd/root.h"
+#include "dmd/mem.h"
+
+#include <cctype>       // isupper, tolower
+#include <algorithm>
+#include <utility>
+#include <stdarg.h>
+
+namespace opts {
+
+// Helper function
+static char toLower(char c) {
+    if (isupper(c))
+        return tolower(c);
+    return c;
+}
+
+bool FlagParser::parse(cl::Option &O, const char *ArgName, const std::string &Arg, bool &Val) {
+    // Make a std::string out of it to make comparisons easier
+    // (and avoid repeated conversion)
+    std::string argname = ArgName;
+    
+    typedef std::vector<std::pair<std::string, bool> >::iterator It;
+    for (It I = switches.begin(), E = switches.end(); I != E; ++I) {
+        std::string name = I->first;
+        if (name == argname
+                || (name.length() < argname.length()
+                    && argname.substr(0, name.length()) == name
+                    && argname[name.length()] == '=')) {
+            
+            if (!cl::parser<bool>::parse(O, ArgName, Arg, Val)) {
+                Val = (Val == I->second);
+                return false;
+            }
+            // Invalid option value
+            break;
+        }
+    }
+    return true;
+}
+
+void FlagParser::getExtraOptionNames(std::vector<const char*> &Names) {
+    typedef std::vector<std::pair<std::string, bool> >::iterator It;
+    for (It I = switches.begin() + 1, E = switches.end(); I != E; ++I) {
+        Names.push_back(I->first.c_str());
+    }
+}
+
+
+MultiSetter::MultiSetter(bool invert, bool* p, ...) {
+    this->invert = invert;
+    if (p) {
+        locations.push_back(p);
+        va_list va;
+        va_start(va, p);
+        while (p = va_arg(va, bool*)) {
+            locations.push_back(p);
+        }
+    }
+}
+        
+void MultiSetter::operator=(bool val) {
+    typedef std::vector<bool*>::iterator It;
+    for (It I = locations.begin(), E = locations.end(); I != E; ++I) {
+        **I = (val != invert);
+    }
+}
+
+
+void ArrayAdapter::push_back(const char* cstr) {
+    if (!cstr || !*cstr)
+        error("Expected argument to '-%s'", name);
+    
+    if (!*arrp)
+        *arrp = new Array;
+    (*arrp)->push(mem.strdup(cstr));
+}
+
+} // namespace opts
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/cl_helpers.h	Wed Feb 25 17:34:51 2009 +0100
@@ -0,0 +1,68 @@
+#ifndef LDC_CL_HELPERS_H
+#define LDC_CL_HELPERS_H
+
+#include <string>
+
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compiler.h"
+
+struct Array;
+
+namespace opts {
+    namespace cl = llvm::cl;
+    
+    /// Helper class for fancier options
+    class FlagParser : public cl::parser<bool> {
+        std::vector<std::pair<std::string, bool> > switches;
+    public:
+        template <class Opt>
+        void initialize(Opt &O) {
+            assert(!(O.getMiscFlags() & cl::AllowInverse)
+                && "FlagParser doesn't support redundant AllowInverse flag");
+            
+            std::string Name = O.ArgStr;
+            switches.push_back(make_pair("enable-" + Name, true));
+            switches.push_back(make_pair("disable-" + Name, false));
+            // Replace <foo> with -enable-<foo>
+            O.ArgStr = switches[0].first.c_str();
+        }
+        
+        bool parse(cl::Option &O, const char *ArgName, const std::string &ArgValue, bool &Val);
+        
+        void getExtraOptionNames(std::vector<const char*> &Names);
+    };
+    
+    /// Helper class for options that set multiple flags
+    class MultiSetter {
+        std::vector<bool*> locations;
+        bool invert;
+        MultiSetter(bool); //not implemented, disable auto-conversion
+    public:
+        MultiSetter(bool invert, bool* p, ...) END_WITH_NULL;
+        
+        void operator=(bool val);
+    };
+    
+    /// Helper class to fill Array with char* when given strings
+    /// (Errors on empty strings)
+    class ArrayAdapter {
+        const char* name;
+        Array** arrp;
+    public:
+        ArrayAdapter(const char* name_, Array*& arr) {
+            name = name_;
+            arrp = &arr;
+            assert(name);
+            assert(arrp);
+        }
+        
+        void push_back(const char* cstr);
+        
+        void push_back(const std::string& str) {
+            push_back(str.c_str());
+        }
+    };
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/cl_options.cpp	Wed Feb 25 17:34:51 2009 +0100
@@ -0,0 +1,337 @@
+#include "gen/cl_options.h"
+#include "gen/cl_helpers.h"
+
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetData.h"
+
+#include "gen/logger.h"
+
+#include "llvm/Support/CommandLine.h"
+
+namespace opts {
+
+// Positional options first, in order:
+cl::list<std::string> fileList(
+    cl::Positional, cl::desc("files"));
+
+cl::list<std::string> runargs("run",
+    cl::desc("program args..."),
+    cl::Positional,
+    cl::PositionalEatsArgs);
+
+
+
+// TODO: Replace this with a proper PassNameParser-based solution
+static cl::opt<bool, true> doInline("inline",
+    cl::desc("Do function inlining"),
+    cl::location(global.params.llvmInline),
+    cl::ZeroOrMore,
+    cl::init(false));
+
+
+
+static cl::opt<bool, true> useDeprecated("d",
+    cl::desc("Allow deprecated language features"),
+    cl::ZeroOrMore,
+    cl::location(global.params.useDeprecated));
+
+static cl::opt<char, true> useDv1(
+    cl::desc("Force language version:"),
+    cl::ZeroOrMore,
+    cl::values(
+        clEnumValN(1, "v1", "D language version 1.00"),
+        clEnumValEnd),
+    cl::location(global.params.Dversion),
+    cl::init(2),
+    cl::Hidden);
+
+cl::opt<bool> compileOnly("c",
+    cl::desc("Do not link"),
+    cl::ZeroOrMore);
+
+static cl::opt<bool, true> verbose("v",
+    cl::desc("Verbose"),
+    cl::ZeroOrMore,
+    cl::location(global.params.verbose));
+
+static cl::opt<bool, true> warnings("w",
+    cl::desc("Enable warnings"),
+    cl::ZeroOrMore,
+    cl::location(global.params.warnings));
+
+
+static cl::opt<char, true> optimizeLevel(
+    cl::desc("Setting the optimization level:"),
+    cl::ZeroOrMore,
+    cl::values(
+        clEnumValN(2, "O",  "Equivalent to -O2"),
+        clEnumValN(0, "O0", "Trivial optimizations only"),
+        clEnumValN(1, "O1", "Simple optimizations"),
+        clEnumValN(2, "O2", "Good optimizations"),
+        clEnumValN(3, "O3", "Aggressive optimizations"),
+        clEnumValN(4, "O4", "Link-time optimization"), //  not implemented?
+        clEnumValN(5, "O5", "Link-time optimization"), //  not implemented?
+        clEnumValEnd),
+    cl::location(global.params.optimizeLevel),
+    cl::init(-1));
+
+static cl::opt<char, true> debugInfo(
+    cl::desc("Generating debug information:"),
+    cl::ZeroOrMore,
+    cl::values(
+        clEnumValN(1, "g",  "Generate debug information"),
+        clEnumValN(2, "gc", "Same as -g, but pretend to be C"),
+        clEnumValEnd),
+    cl::location(global.params.symdebug),
+    cl::init(0));
+
+
+static cl::opt<bool, true> annotate("annotate",
+    cl::desc("Annotate the bitcode with human readable source code"),
+    cl::location(global.params.llvmAnnotate));
+
+cl::opt<bool> noAsm("noasm",
+    cl::desc("Disallow use of inline assembler"));
+
+// Output file options
+cl::opt<bool> dontWriteObj("o-",
+    cl::desc("Do not write object file"));
+
+cl::opt<std::string> objectFile("of",
+    cl::value_desc("filename"),
+    cl::Prefix,
+    cl::desc("Use <filename> as output file name"));
+
+cl::opt<std::string> objectDir("od",
+    cl::value_desc("objdir"),
+    cl::Prefix,
+    cl::desc("Write object files to directory <objdir>"));
+
+
+// Output format options
+cl::opt<bool> output_bc("output-bc",
+    cl::desc("Write LLVM bitcode"));
+
+cl::opt<bool> output_ll("output-ll",
+    cl::desc("Write LLVM IR"));
+
+cl::opt<bool> output_s("output-s",
+    cl::desc("Write native assembly"));
+
+cl::opt<cl::boolOrDefault> output_o("output-o",
+    cl::desc("Write native object"));
+
+
+// DDoc options
+static cl::opt<bool, true> doDdoc("D",
+    cl::desc("Generate documentation"),
+    cl::location(global.params.doDocComments));
+
+cl::opt<std::string> ddocDir("Dd",
+    cl::desc("Write documentation file to <docdir> directory"),
+    cl::value_desc("docdir"),
+    cl::Prefix);
+
+cl::opt<std::string> ddocFile("Df",
+    cl::desc("Write documentation file to <filename>"),
+    cl::value_desc("filename"),
+    cl::Prefix);
+
+
+// Header generation options
+#ifdef _DH
+static cl::opt<bool, true> doHdrGen("H",
+    cl::desc("Generate 'header' file"),
+    cl::location(global.params.doHdrGeneration));
+
+cl::opt<std::string> hdrDir("Hd",
+    cl::desc("Write 'header' file to <hdrdir> directory"),
+    cl::value_desc("hdrdir"),
+    cl::Prefix);
+
+cl::opt<std::string> hdrFile("Hf",
+    cl::desc("Write 'header' file to <filename>"),
+    cl::value_desc("filename"),
+    cl::Prefix);
+#endif
+
+
+
+static cl::opt<bool, true> unittest("unittest",
+    cl::desc("Compile in unit tests"),
+    cl::location(global.params.useUnitTests));
+
+
+static ArrayAdapter strImpPathStore("J", global.params.fileImppath);
+static cl::list<std::string, ArrayAdapter> stringImportPaths("J",
+    cl::desc("Where to look for string imports"),
+    cl::value_desc("path"),
+    cl::location(strImpPathStore),
+    cl::Prefix);
+
+
+
+// -d-debug is a bit messy, it has 3 modes:
+// -d-debug=ident, -d-debug=level and -d-debug (without argument)
+// That last of these must be acted upon immediately to ensure proper
+// interaction with other options, so it needs some special handling:
+std::vector<std::string> debugArgs;
+
+struct D_DebugStorage {
+    void push_back(const std::string& str) {
+        if (str.empty()) {
+            // Bare "-d-debug" has a special meaning.
+            global.params.useAssert = true;
+            global.params.useArrayBounds = true;
+            global.params.useInvariants = true;
+            global.params.useIn = true;
+            global.params.useOut = true;
+            debugArgs.push_back("1");
+        } else {
+            debugArgs.push_back(str);
+        }
+    }
+};
+
+static D_DebugStorage dds;
+
+// -debug is already declared in LLVM (at least, in debug builds),
+// so we need to be a bit more verbose.
+static cl::list<std::string, D_DebugStorage> debugVersionsOption("d-debug",
+    cl::desc("Compile in debug code >= <level> or identified by <idents>."),
+    cl::value_desc("level/idents"),
+    cl::location(dds),
+    cl::CommaSeparated,
+    cl::ValueOptional);
+
+
+
+// -version is also declared in LLVM, so again we need to be a bit more verbose.
+cl::list<std::string> versions("d-version",
+    cl::desc("Compile in version code >= <level> or identified by <idents>"),
+    cl::value_desc("level/idents"),
+    cl::CommaSeparated);
+
+
+static ArrayAdapter linkSwitchStore("L", global.params.linkswitches);
+static cl::list<std::string, ArrayAdapter> linkerSwitches("L",
+    cl::desc("Pass <linkerflag> to the linker"),
+    cl::value_desc("linkerflag"),
+    cl::location(linkSwitchStore),
+    cl::Prefix);
+
+
+cl::opt<const llvm::TargetMachineRegistry::entry*, false,
+        llvm::RegistryParser<llvm::TargetMachine> > mArch("march",
+    cl::desc("Architecture to generate code for:"));
+
+static cl::alias m("m",
+    cl::desc("Alias for '-march' for backwards compatibility"),
+    cl::Prefix,
+    cl::aliasopt(mArch));
+
+
+static cl::opt<OS, true> os("t",
+    cl::desc("Emit code for the specified OS:"),
+    cl::values(
+#define ENUMVAL_N(Name, Desc) clEnumValN(OS##Name, #Name, Desc)
+#define ENUMVAL(Name) ENUMVAL_N(Name, #Name)
+        ENUMVAL(Linux),
+        ENUMVAL(Windows),
+        ENUMVAL_N(MacOSX, "Mac OS X"),
+        ENUMVAL(FreeBSD),
+        ENUMVAL(Solaris),
+#undef ENUMVAL
+#undef ENUMVAL_N
+        clEnumValEnd),
+    cl::Prefix,
+    cl::location(global.params.os));
+
+
+// "Hidden debug switches"
+// Are these ever used?
+static cl::opt<bool, true> debuga("hidden-debug--a",
+    cl::desc("Hidden debug option A"),
+    cl::ReallyHidden,
+    cl::location(global.params.debuga));
+static cl::opt<bool, true> debugb("hidden-debug-b",
+    cl::desc("Hidden debug option B"),
+    cl::ReallyHidden,
+    cl::location(global.params.debugb));
+static cl::opt<bool, true> debugc("hidden-debug-c",
+    cl::desc("Hidden debug option C"),
+    cl::ReallyHidden,
+    cl::location(global.params.debugc));
+static cl::opt<bool, true> debugf("hidden-debug-f",
+    cl::desc("Hidden debug option F"),
+    cl::ReallyHidden,
+    cl::location(global.params.debugf));
+static cl::opt<bool, true> debugr("hidden-debug-r",
+    cl::desc("Hidden debug option R"),
+    cl::ReallyHidden,
+    cl::location(global.params.debugr));
+static cl::opt<bool, true> debugw("hidden-debug-w",
+    cl::desc("Hidden debug option W"),
+    cl::ReallyHidden,
+    cl::location(global.params.debugw));
+static cl::opt<bool, true> debugx("hidden-debug-x",
+    cl::desc("Hidden debug option X"),
+    cl::ReallyHidden,
+    cl::location(global.params.debugx));
+static cl::opt<bool, true> debugy("hidden-debug-y",
+    cl::desc("Hidden debug option Y"),
+    cl::ReallyHidden,
+    cl::location(global.params.debugy));
+
+
+static cl::opt<bool, true, FlagParser> asserts("asserts",
+    cl::desc("(*) Enable assertions"),
+    cl::value_desc("bool"),
+    cl::location(global.params.useAssert),
+    cl::init(true));
+
+static cl::opt<bool, true, FlagParser> boundsChecks("boundscheck",
+    cl::desc("(*) Enable array bounds checks"),
+    cl::value_desc("bool"),
+    cl::location(global.params.useArrayBounds),
+    cl::init(true));
+
+static cl::opt<bool, true, FlagParser> invariants("invariants",
+    cl::desc("(*) Enable invariants"),
+    cl::location(global.params.useInvariants),
+    cl::init(true));
+
+static cl::opt<bool, true, FlagParser> preconditions("preconditions",
+    cl::desc("(*) Enable function preconditions"),
+    cl::location(global.params.useIn),
+    cl::init(true));
+
+static cl::opt<bool, true, FlagParser> postconditions("postconditions",
+    cl::desc("(*) Enable function postconditions"),
+    cl::location(global.params.useOut),
+    cl::init(true));
+
+
+static MultiSetter ContractsSetter(false, 
+    &global.params.useIn, &global.params.useOut, NULL);
+static cl::opt<MultiSetter, true, FlagParser> contracts("contracts",
+    cl::desc("(*) Enable function pre- and post-conditions"),
+    cl::location(ContractsSetter));
+
+static MultiSetter ReleaseSetter(true, &global.params.useAssert,
+    &global.params.useArrayBounds, &global.params.useInvariants,
+    &global.params.useOut, &global.params.useIn, NULL);
+static cl::opt<MultiSetter, true, cl::parser<bool> > release("release",
+    cl::desc("Disables asserts, invariants, contracts and boundscheck"),
+    cl::location(ReleaseSetter),
+    cl::ValueDisallowed);
+
+
+static cl::extrahelp footer("\n"
+"-d-debug can also be specified without options, in which case it enables all\n"
+"debug checks (i.e. (asserts, boundchecks, contracts and invariants) as well\n"
+"as acting as -d-debug=1\n\n"
+"Options marked with (*) also have a -disable-FOO variant with inverted\n"
+"meaning.\n");
+
+} // namespace opts
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/cl_options.h	Wed Feb 25 17:34:51 2009 +0100
@@ -0,0 +1,46 @@
+#ifndef LDC_CL_OPTIONS_H
+#define LDC_CL_OPTIONS_H
+
+#include "mars.h"
+
+#include <deque>
+#include <vector>
+
+#include "llvm/Support/RegistryParser.h"
+#include "llvm/Target/TargetMachineRegistry.h"
+#include "llvm/Support/CommandLine.h"
+
+namespace opts {
+    namespace cl = llvm::cl;
+
+    /* Mostly generated with the following command:
+       egrep -e '^(cl::|#if|#e)' gen/cl_options.cpp \
+        | sed -re 's/^(cl::.*)\(.*$/    extern \1;/'
+     */
+    extern cl::list<std::string> fileList;
+    extern cl::list<std::string> runargs;
+    extern cl::opt<bool> compileOnly;
+    extern cl::opt<bool> noAsm;
+    extern cl::opt<bool> dontWriteObj;
+    extern cl::opt<std::string> objectFile;
+    extern cl::opt<std::string> objectDir;
+    extern cl::opt<bool> output_bc;
+    extern cl::opt<bool> output_ll;
+    extern cl::opt<bool> output_s;
+    extern cl::opt<cl::boolOrDefault> output_o;
+    extern cl::opt<std::string> ddocDir;
+    extern cl::opt<std::string> ddocFile;
+#ifdef _DH
+    extern cl::opt<std::string> hdrDir;
+    extern cl::opt<std::string> hdrFile;
+#endif
+    extern cl::list<std::string> versions;
+
+    extern cl::opt<const llvm::TargetMachineRegistry::entry*, false,
+                    llvm::RegistryParser<llvm::TargetMachine> > mArch;
+    
+    // Arguments to -d-debug
+    extern std::vector<std::string> debugArgs;
+    // Arguments to -run
+}
+#endif
--- a/gen/linker.cpp	Thu Feb 19 13:51:44 2009 +0100
+++ b/gen/linker.cpp	Wed Feb 25 17:34:51 2009 +0100
@@ -1,3 +1,4 @@
+#include "gen/linker.h"
 #include "gen/llvm.h"
 #include "llvm/Linker.h"
 #include "llvm/System/Program.h"
@@ -11,6 +12,16 @@
 
 #define NO_COUT_LOGGER
 #include "gen/logger.h"
+#include "gen/cl_options.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Is this useful?
+llvm::cl::opt<bool> quiet("quiet",
+    llvm::cl::desc("Suppress output of link command (unless -v is also passed)"),
+    llvm::cl::Hidden,
+    llvm::cl::ZeroOrMore,
+    llvm::cl::init(true));
 
 //////////////////////////////////////////////////////////////////////////////
 
@@ -173,7 +184,7 @@
     }
 
     // print link command?
-    if (!global.params.quiet || global.params.verbose)
+    if (!quiet || global.params.verbose)
     {
         // Print it
         for (int i = 0; i < args.size(); i++)
@@ -311,7 +322,7 @@
         args.push_back("-m64");
 
     // print link command?
-    if (!global.params.quiet || global.params.verbose)
+    if (!quiet || global.params.verbose)
     {
         // Print it
         for (int i = 0; i < args.size(); i++)
@@ -363,10 +374,12 @@
 
     // build arguments
     std::vector<const char*> args;
-    for (size_t i = 0; i < global.params.runargs_length; i++)
+    // args[0] should be the name of the executable
+    args.push_back(gExePath.toString().c_str());
+    // Skip first argument to -run; it's a D source file.
+    for (size_t i = 1, length = opts::runargs.size(); i < length; i++)
     {
-        char *a = global.params.runargs[i];
-        args.push_back(a);
+        args.push_back(opts::runargs[i].c_str());
     }
     // terminate args list
     args.push_back(NULL);
--- a/gen/linker.h	Thu Feb 19 13:51:44 2009 +0100
+++ b/gen/linker.h	Wed Feb 25 17:34:51 2009 +0100
@@ -1,8 +1,11 @@
 #ifndef LDC_GEN_LINKER_H
 #define LDC_GEN_LINKER_H
 
+#include "llvm/Support/CommandLine.h"
 #include <vector>
 
+extern llvm::cl::opt<bool> quiet;
+
 namespace llvm
 {
     class Module;
--- a/gen/logger.cpp	Thu Feb 19 13:51:44 2009 +0100
+++ b/gen/logger.cpp	Wed Feb 25 17:34:51 2009 +0100
@@ -8,6 +8,7 @@
 
 #include "mars.h"
 
+#include "llvm/Support/CommandLine.h"
 #include "gen/logger.h"
 
 namespace Logger
@@ -15,7 +16,10 @@
     static std::string indent_str;
     static std::ofstream null_out("/dev/null");
 
-    static bool _enabled = false;
+    llvm::cl::opt<bool> _enabled("vv",
+        llvm::cl::desc("Very verbose"),
+        llvm::cl::ZeroOrMore);
+
     void indent()
     {
         if (_enabled) {
--- a/gen/runtime.cpp	Thu Feb 19 13:51:44 2009 +0100
+++ b/gen/runtime.cpp	Wed Feb 25 17:34:51 2009 +0100
@@ -2,6 +2,7 @@
 #include "llvm/Module.h"
 #include "llvm/Bitcode/ReaderWriter.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/CommandLine.h"
 
 #include "root.h"
 #include "mars.h"
@@ -15,6 +16,14 @@
 #include "gen/tollvm.h"
 #include "gen/irstate.h"
 
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+static llvm::cl::opt<bool> noruntime("noruntime",
+    llvm::cl::desc("Do not allow code that generates implicit runtime calls"),
+    llvm::cl::ZeroOrMore);
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
 static llvm::Module* M = NULL;
 static bool runtime_failed = false;
 
@@ -44,7 +53,7 @@
 
 llvm::Function* LLVM_D_GetRuntimeFunction(llvm::Module* target, const char* name)
 {
-    if (global.params.noruntime) {
+    if (noruntime) {
         error("No implicit runtime calls allowed with -noruntime option enabled");
         fatal();
     }
@@ -80,7 +89,7 @@
         return gv;
     }
 
-    if (global.params.noruntime) {
+    if (noruntime) {
         error("No implicit runtime calls allowed with -noruntime option enabled");
         fatal();
     }
--- a/gen/toobj.cpp	Thu Feb 19 13:51:44 2009 +0100
+++ b/gen/toobj.cpp	Wed Feb 25 17:34:51 2009 +0100
@@ -24,6 +24,7 @@
 #include "llvm/System/Program.h"
 #include "llvm/System/Path.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/CommandLine.h"
 
 #include "mars.h"
 #include "module.h"
@@ -55,6 +56,12 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
+static llvm::cl::opt<bool> noVerify("noverify",
+    llvm::cl::desc("Do not run the validation pass before writing bitcode"),
+    llvm::cl::ZeroOrMore);
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
 // in gen/optimize.cpp
 void ldc_optimize_module(llvm::Module* m, char lvl, bool doinline);
 
@@ -124,10 +131,6 @@
 //    for (unsigned i = 0; i != MAttrs.size(); ++i)
 //      Features.AddFeature(MAttrs[i]);
 
-    // only generate PIC code when -fPIC switch is used
-    if (global.params.pic)
-        llvm::TargetMachine::setRelocationModel(llvm::Reloc::PIC_);
-
     // allocate the target machine
     std::auto_ptr<llvm::TargetMachine> target(MArch->CtorFn(*ir.module, Features.getString()));
     assert(target.get() && "Could not allocate target machine!");
@@ -182,7 +185,7 @@
     }
 
     // verify the llvm
-    if (!global.params.novalidate) {
+    if (!noVerify) {
         std::string verifyErr;
         Logger::println("Verifying module...");
         LOG_SCOPE;
@@ -200,7 +203,7 @@
     ldc_optimize_module(ir.module, global.params.optimizeLevel, global.params.llvmInline);
 
     // verify the llvm
-    if (!global.params.novalidate && (global.params.optimizeLevel >= 0 || global.params.llvmInline)) {
+    if (!noVerify && (global.params.optimizeLevel >= 0 || global.params.llvmInline)) {
         std::string verifyErr;
         Logger::println("Verifying module... again...");
         LOG_SCOPE;
--- a/ldc-posix-tango	Thu Feb 19 13:51:44 2009 +0100
+++ b/ldc-posix-tango	Wed Feb 25 17:34:51 2009 +0100
@@ -38,7 +38,7 @@
 
 [compile]
 oneatatime=yes
-cmd=ldc -c $i
+cmd=ldmd -c $i
 
 flag=$i
 incdir=-I$i
--- a/ldc.conf.in	Thu Feb 19 13:51:44 2009 +0100
+++ b/ldc.conf.in	Wed Feb 25 17:34:51 2009 +0100
@@ -1,2 +1,2 @@
 [Environment]
-DFLAGS=-I@RUNTIME_DIR@ -I@RUNTIME_DIR@/lib/common -L-L%@P%/../lib -version=Tango -defaultlib=@RUNTIME_AIO@ -debuglib=@RUNTIME_AIO@
+DFLAGS=-I@RUNTIME_DIR@ -I@RUNTIME_DIR@/lib/common -L-L%@P%/../lib -d-version=Tango -defaultlib=@RUNTIME_AIO@ -debuglib=@RUNTIME_AIO@
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tango.patch	Wed Feb 25 17:34:51 2009 +0100
@@ -0,0 +1,56 @@
+Index: lib/unittest.sh
+===================================================================
+--- lib/unittest.sh	(revision 4330)
++++ lib/unittest.sh	(working copy)
+@@ -15,14 +15,14 @@
+ usage() {
+     echo 'Usage: ./unittest.sh [otions ...]
+ Options:
+-  --help: This message
++  --help:    This message
+   --run-all: Reports result instead of breaking. Do not use this if you want to
+-         run unittest runner through a debugger.
+-  dmd:    Builds unittests for dmd
+-  gdc:    Builds unittests for gdc
+-  ldc: Builds unittests for ldc
++             run unittest runner through a debugger.
++  dmd:       Builds unittests for dmd
++  gdc:       Builds unittests for gdc
++  ldc:       Builds unittests for ldc
+ 
+-  <none>: Builds unittests for all known compilers.'
++  <none>:    Builds unittests for all known compilers.'
+   exit 0
+ }
+ 
+@@ -37,7 +37,7 @@
+ 
+     rebuild --help >& /dev/null || die "rebuild required, aborting" 1
+ 
+-    if ! $DC --help >& /dev/null
++    if ! which $DC >& /dev/null
+     then
+         echo "$DC not found on your \$PATH!"
+     else
+Index: lib/build-tango.sh
+===================================================================
+--- lib/build-tango.sh	(revision 4330)
++++ lib/build-tango.sh	(working copy)
+@@ -131,7 +131,7 @@
+     DC=$1
+     LIB=$2
+ 
+-    if ! $DC --help >& /dev/null
++    if ! which "$DC" >& /dev/null
+     then
+         echo "$DC not found on your \$PATH!"
+         return
+@@ -203,7 +203,7 @@
+             build gdmd libgtango.a libgphobos.a
+             ;;
+         ldc)
+-            build ldc libtango-user-ldc.a build-tango.sh
++            build ldmd libtango-user-ldc.a build-tango.sh
+             ;;
+         mac)
+             POSIXFLAG="-version=Posix"