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)
This commit is contained in:
Frits van Bommel 2009-02-25 17:34:51 +01:00
parent 6a02292c10
commit b3d87205ad
17 changed files with 908 additions and 549 deletions

41
bin/ldmd Executable file
View file

@ -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[@]}"

View file

@ -33,6 +33,15 @@
#include "../gen/enums.h" #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); extern void obj_includelib(const char *name);
void obj_startaddress(Symbol *s); void obj_startaddress(Symbol *s);
@ -962,7 +971,7 @@ void PragmaDeclaration::semantic(Scope *sc)
#endif // LDC #endif // LDC
else if (global.params.ignoreUnsupportedPragmas) else if (ignoreUnsupportedPragmas)
{ {
if (global.params.verbose) if (global.params.verbose)
{ {

View file

@ -40,6 +40,42 @@
#include "gen/linker.h" #include "gen/linker.h"
#include "revisions.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); void getenv_setargv(const char *envvar, int *pargc, char** *pargv);
Global global; Global global;
@ -68,13 +104,17 @@ Global::Global()
llvm_version = LLVM_REV; llvm_version = LLVM_REV;
global.structalign = 8; 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 char *Loc::toChars() const
{ {
OutBuffer buf; OutBuffer buf;
char *p;
if (filename) if (filename)
{ {
@ -150,98 +190,49 @@ void halt()
extern void backend_init(); extern void backend_init();
extern void backend_term(); extern void backend_term();
void usage() void printVersion() {
{
printf("LLVM D Compiler %s\nbased on DMD %s and %s\n%s\n%s\n", 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); global.ldc_version, global.version, global.llvm_version, global.copyright, global.written);
printf("\ printf("D Language Documentation: http://www.digitalmars.com/d/1.0/index.html\n"
D Language Documentation: http://www.digitalmars.com/d/1.0/index.html\n\ "LDC Homepage: http://www.dsource.org/projects/ldc\n");
LDC Homepage: http://www.dsource.org/projects/ldc\n\ }
Usage:\n\
ldc files.d ... { -switch }\n\ // Helper function to handle -d-debug=* and -d-version=*
\n\ static void processVersions(std::vector<std::string>& list, char* type,
files.d D source files\n%s\ void (*setLevel)(unsigned), void (*addIdent)(char*)) {
-o- do not write object file\n\ typedef std::vector<std::string>::iterator It;
-od<objdir> write object files to directory <objdir>\n\
-op do not strip paths from source file\n\ for(It I = list.begin(), E = list.end(); I != E; ++I) {
-oq write object files with fully qualified names\n\ const char* value = I->c_str();
-of<filename> name output file to <filename>\n\ if (isdigit(value[0])) {
if -c and extension of <filename> is known, it determines the output type\n\ errno = 0;
\n\ char* end;
-output-ll write LLVM IR\n\ long level = strtol(value, &end, 10);
-output-bc write LLVM bitcode\n\ if (*end || errno || level > INT_MAX) {
-output-s write native assembly\n\ error("Invalid %s level: %s", type, I->c_str());
-output-o write native object (default if no -output switch passed)\n\ } else {
\n\ setLevel((unsigned)level);
-c do not link\n\ }
-L<linkerflag> pass <linkerflag> to linker\n\ } else {
\n\ char* cstr = mem.strdup(value);
-w enable warnings\n\ if (Lexer::isValidIdentifier(cstr)) {
\n\ addIdent(cstr);
-H generate 'header' file\n\ continue;
-Hd<hdrdir> write 'header' file to <hdrdir> directory\n\ } else {
-Hf<filename> write 'header' file to <filename>\n\ error("Invalid %s identifier or level: '%s'", type, I->c_str());
\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\ // Helper function to handle -of, -od, etc.
-m<arch> emit code specific to <arch> being one of:\n\ static void initFromString(char*& dest, const cl::opt<std::string>& src) {
x86 x86-64 ppc32 ppc64 arm thumb\n\ dest = 0;
-t<os> emit code specific to <os> being one of:\n\ if (src.getNumOccurrences() != 0) {
Linux, Windows, MacOSX, FreeBSD, Solaris\n\ if (src.empty())
\n\ error("Expected argument to '-%s'", src.ArgStr);
-g, -gc add symbolic debug info\n\ dest = mem.strdup(src.c_str());
\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
);
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -251,28 +242,6 @@ int main(int argc, char *argv[])
char *p, *ext; char *p, *ext;
Module *m; Module *m;
int status = EXIT_SUCCESS; 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 // Set default values
#if _WIN32 #if _WIN32
@ -282,20 +251,7 @@ int main(int argc, char *argv[])
#else #else
global.params.argv0 = argv[0]; global.params.argv0 = argv[0];
#endif #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.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.linkswitches = new Array();
global.params.libfiles = new Array(); global.params.libfiles = new Array();
@ -315,14 +271,6 @@ int main(int argc, char *argv[])
fatal(); 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 // Predefine version identifiers
#if IN_LLVM #if IN_LLVM
VersionCondition::addPredefinedGlobalIdent("LLVM"); VersionCondition::addPredefinedGlobalIdent("LLVM");
@ -365,362 +313,81 @@ int main(int argc, char *argv[])
} }
#endif #endif
for (i = 1; i < argc; i++) cl::SetVersionPrinter(&printVersion);
{ cl::ParseCommandLineOptions(argc, argv, "LLVM-based D Compiler\n");
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;
case 'd': global.params.optimize = (global.params.optimizeLevel >= 0);
if (!p[3])
goto Lnoarg;
global.params.objdir = p + 3;
break;
case 'f': // Negated options
if (!p[3]) global.params.link = !compileOnly;
goto Lnoarg; global.params.obj = !dontWriteObj;
global.params.objname = p + 3; global.params.useInlineAsm = !noAsm;
break;
case 'p': // String options: std::string --> char*
if (p[3]) initFromString(global.params.objname, objectFile);
goto Lerror; initFromString(global.params.objdir, objectDir);
global.params.preservePaths = 1;
break; initFromString(global.params.docdir, ddocDir);
initFromString(global.params.docname, ddocFile);
case 'q': global.params.doDocComments |=
if (p[3]) global.params.docdir || global.params.docname;
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;
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 #ifdef _DH
else if (p[1] == 'H') initFromString(global.params.hdrdir, hdrDir);
{ global.params.doHdrGeneration = 1; initFromString(global.params.hdrname, hdrFile);
switch (p[2]) global.params.doHdrGeneration |=
{ global.params.hdrdir || global.params.hdrname;
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;
default:
goto Lerror;
}
}
#endif #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; processVersions(debugArgs, "debug",
level = strtol(p + 7, &p, 10); DebugCondition::setGlobalLevel,
if (*p || errno || level > INT_MAX) DebugCondition::addGlobalIdent);
goto Lerror; processVersions(versions, "version",
DebugCondition::setGlobalLevel((int)level); VersionCondition::setGlobalLevel,
} VersionCondition::addGlobalIdent);
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;
errno = 0; global.params.output_o =
level = strtol(p + 9, &p, 10); opts::output_o == cl::BOU_UNSET
if (*p || errno || level > INT_MAX) ? OUTPUTFLAGdefault
goto Lerror; : opts::output_o == cl::BOU_TRUE
VersionCondition::setGlobalLevel((int)level); ? OUTPUTFLAGset
} : OUTPUTFLAGno;
else if (Lexer::isValidIdentifier(p + 9)) global.params.output_bc = opts::output_bc ? OUTPUTFLAGset : OUTPUTFLAGno;
VersionCondition::addGlobalIdent(p + 9); global.params.output_ll = opts::output_ll ? OUTPUTFLAGset : OUTPUTFLAGno;
else global.params.output_s = opts::output_s ? OUTPUTFLAGset : OUTPUTFLAGno;
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;
}
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;
Lnoarg: if (global.params.run || !runargs.empty()) {
error("argument expected for switch '%s'", argv[i]); // FIXME: how to properly detect the presence of a PositionalEatsArgs
continue; // 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)
else // NOTE: Hacked around it by detecting -run in getenv_setargv(), where
files.push(p); // 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");
}
} }
if (mArch)
global.params.llvmArch = mArch->Name;
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) if (global.errors)
{ {
fatal(); fatal();
} }
if (files.dim == 0) if (files.dim == 0)
{ usage(); {
cl::PrintHelpMessage();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -740,7 +407,7 @@ int main(int argc, char *argv[])
global.params.linkswitches->push(arg); global.params.linkswitches->push(arg);
} }
} }
else if (!global.params.noDefaultLib) else if (!noDefaultLib)
{ {
char *arg; char *arg;
arg = (char *)mem.malloc(64); arg = (char *)mem.malloc(64);
@ -760,7 +427,7 @@ int main(int argc, char *argv[])
} }
if (global.params.run) if (global.params.run)
global.params.quiet = 1; quiet = 1;
if (global.params.useUnitTests) if (global.params.useUnitTests)
global.params.useAssert = 1; global.params.useAssert = 1;
@ -893,7 +560,7 @@ int main(int argc, char *argv[])
assert(global.params.cpu != ARCHinvalid); assert(global.params.cpu != ARCHinvalid);
if (allowForceEndianness && global.params.forceBE) { if (allowForceEndianness && forceBE) {
VersionCondition::addPredefinedGlobalIdent("BigEndian"); VersionCondition::addPredefinedGlobalIdent("BigEndian");
global.params.isLE = false; global.params.isLE = false;
} }
@ -1306,8 +973,24 @@ void getenv_setargv(const char *envvar, int *pargc, char** *pargv)
argv = new Array(); argv = new Array();
argv->setDim(argc); argv->setDim(argc);
for (int i = 0; i < argc; i++) int argc_left = 0;
argv->data[i] = (void *)(*pargv)[i]; 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 j = 1; // leave argv[0] alone
while (1) while (1)
@ -1382,6 +1065,11 @@ void getenv_setargv(const char *envvar, int *pargc, char** *pargv)
} }
Ldone: 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; *pargc = argc;
*pargv = (char **)argv->data; *pargv = (char **)argv->data;
} }

View file

@ -17,6 +17,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdarg.h> #include <stdarg.h>
#include <stddef.h>
#define __STDC_FORMAT_MACROS 1 #define __STDC_FORMAT_MACROS 1
#include <inttypes.h> #include <inttypes.h>
#include <stdarg.h> #include <stdarg.h>
@ -72,48 +73,40 @@ enum OS
// Put command line switches in here // Put command line switches in here
struct Param struct Param
{ {
char obj; // write object file bool obj; // write object file
char link; // perform link bool link; // perform link
char quiet; // suppress non-error messages bool verbose; // verbose compile
char verbose; // verbose compile
char symdebug; // insert debug symbolic information char symdebug; // insert debug symbolic information
char optimize; // run optimizer bool optimize; // run optimizer
char optimizeLevel; // optimization level char optimizeLevel; // optimization level
ARCH cpu; // target CPU ARCH cpu; // target CPU
OS os; // target OS OS os; // target OS
char is64bit; // generate 64 bit code bool is64bit; // generate 64 bit code
char isLE; // generate little endian code bool isLE; // generate little endian code
char scheduler; // which scheduler to use bool useDeprecated; // allow use of deprecated features
char useDeprecated; // allow use of deprecated features bool useAssert; // generate runtime code for assert()'s
char useAssert; // generate runtime code for assert()'s bool useInvariants; // generate class invariant checks
char useInvariants; // generate class invariant checks bool useIn; // generate precondition checks
char useIn; // generate precondition checks bool useOut; // generate postcondition checks
char useOut; // generate postcondition checks bool useArrayBounds; // generate array bounds checks
char useArrayBounds; // generate array bounds checks bool useSwitchError; // check for switches without a default
char useSwitchError; // check for switches without a default bool useUnitTests; // generate unittest code
char useUnitTests; // generate unittest code bool useInline; // inline expand functions
char useInline; // inline expand functions bool warnings; // enable warnings
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
char Dversion; // D version number char Dversion; // D version number
char ignoreUnsupportedPragmas; // rather than error on them
char *argv0; // program name char *argv0; // program name
Array *imppath; // array of char*'s of where to look for import modules 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 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 *objdir; // .obj file output directory
char *objname; // .obj file output name 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 *docdir; // write documentation file to docdir directory
char *docname; // write documentation file to docname char *docname; // write documentation file to docname
Array *ddocfiles; // macro include files for Ddoc 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 *hdrdir; // write 'header' file to docdir directory
char *hdrname; // write 'header' file to docname char *hdrname; // write 'header' file to docname
@ -131,18 +124,16 @@ struct Param
char *xmlname; // filename for XML output char *xmlname; // filename for XML output
// Hidden debug switches // Hidden debug switches
char debuga; bool debuga;
char debugb; bool debugb;
char debugc; bool debugc;
char debugf; bool debugf;
char debugr; bool debugr;
char debugw; bool debugw;
char debugx; bool debugx;
char debugy; bool debugy;
char run; // run resulting executable bool run; // run resulting executable
size_t runargs_length;
char** runargs; // arguments for executable
// Linker stuff // Linker stuff
Array *objfiles; Array *objfiles;
@ -153,17 +144,14 @@ struct Param
char *exefile; char *exefile;
// LDC stuff // LDC stuff
char *llvmArch; const char *llvmArch;
char forceBE; OUTPUTFLAG output_ll;
char output_ll; OUTPUTFLAG output_bc;
char output_bc; OUTPUTFLAG output_s;
char output_s; OUTPUTFLAG output_o;
char output_o; bool llvmInline;
char llvmInline; bool llvmAnnotate;
char llvmAnnotate; bool useInlineAsm;
char useInlineAsm;
char fqnNames; // use fully qualified object names
char noDefaultLib;
// target stuff // target stuff
char *targetTriple; char *targetTriple;

View file

@ -44,6 +44,19 @@
#include "d-dmd-gcc.h" #include "d-dmd-gcc.h"
#endif #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; ClassDeclaration *Module::moduleinfo;
Module *Module::rootModule; Module *Module::rootModule;
@ -139,12 +152,12 @@ File* Module::buildFilePath(char* forcename, char* path, char* ext)
argobj = forcename; argobj = forcename;
else else
{ {
if (global.params.preservePaths) if (preservePaths)
argobj = (char*)this->arg; argobj = (char*)this->arg;
else else
argobj = FileName::name((char*)this->arg); argobj = FileName::name((char*)this->arg);
if (global.params.fqnNames) if (fqnNames)
{ {
if(md) if(md)
argobj = FileName::replaceName(argobj, md->toChars()); argobj = FileName::replaceName(argobj, md->toChars());

81
gen/cl_helpers.cpp Normal file
View file

@ -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

68
gen/cl_helpers.h Normal file
View file

@ -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

337
gen/cl_options.cpp Normal file
View file

@ -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

46
gen/cl_options.h Normal file
View file

@ -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

View file

@ -1,3 +1,4 @@
#include "gen/linker.h"
#include "gen/llvm.h" #include "gen/llvm.h"
#include "llvm/Linker.h" #include "llvm/Linker.h"
#include "llvm/System/Program.h" #include "llvm/System/Program.h"
@ -11,6 +12,16 @@
#define NO_COUT_LOGGER #define NO_COUT_LOGGER
#include "gen/logger.h" #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 @@ int linkExecutable(const char* argv0)
} }
// print link command? // print link command?
if (!global.params.quiet || global.params.verbose) if (!quiet || global.params.verbose)
{ {
// Print it // Print it
for (int i = 0; i < args.size(); i++) for (int i = 0; i < args.size(); i++)
@ -311,7 +322,7 @@ int linkObjToExecutable(const char* argv0)
args.push_back("-m64"); args.push_back("-m64");
// print link command? // print link command?
if (!global.params.quiet || global.params.verbose) if (!quiet || global.params.verbose)
{ {
// Print it // Print it
for (int i = 0; i < args.size(); i++) for (int i = 0; i < args.size(); i++)
@ -363,10 +374,12 @@ int runExectuable()
// build arguments // build arguments
std::vector<const char*> args; 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(opts::runargs[i].c_str());
args.push_back(a);
} }
// terminate args list // terminate args list
args.push_back(NULL); args.push_back(NULL);

View file

@ -1,8 +1,11 @@
#ifndef LDC_GEN_LINKER_H #ifndef LDC_GEN_LINKER_H
#define LDC_GEN_LINKER_H #define LDC_GEN_LINKER_H
#include "llvm/Support/CommandLine.h"
#include <vector> #include <vector>
extern llvm::cl::opt<bool> quiet;
namespace llvm namespace llvm
{ {
class Module; class Module;

View file

@ -8,6 +8,7 @@
#include "mars.h" #include "mars.h"
#include "llvm/Support/CommandLine.h"
#include "gen/logger.h" #include "gen/logger.h"
namespace Logger namespace Logger
@ -15,7 +16,10 @@ namespace Logger
static std::string indent_str; static std::string indent_str;
static std::ofstream null_out("/dev/null"); 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() void indent()
{ {
if (_enabled) { if (_enabled) {

View file

@ -2,6 +2,7 @@
#include "llvm/Module.h" #include "llvm/Module.h"
#include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/CommandLine.h"
#include "root.h" #include "root.h"
#include "mars.h" #include "mars.h"
@ -15,6 +16,14 @@
#include "gen/tollvm.h" #include "gen/tollvm.h"
#include "gen/irstate.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 llvm::Module* M = NULL;
static bool runtime_failed = false; static bool runtime_failed = false;
@ -44,7 +53,7 @@ void LLVM_D_FreeRuntime()
llvm::Function* LLVM_D_GetRuntimeFunction(llvm::Module* target, const char* name) 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"); error("No implicit runtime calls allowed with -noruntime option enabled");
fatal(); fatal();
} }
@ -80,7 +89,7 @@ llvm::GlobalVariable* LLVM_D_GetRuntimeGlobal(llvm::Module* target, const char*
return gv; return gv;
} }
if (global.params.noruntime) { if (noruntime) {
error("No implicit runtime calls allowed with -noruntime option enabled"); error("No implicit runtime calls allowed with -noruntime option enabled");
fatal(); fatal();
} }

View file

@ -24,6 +24,7 @@
#include "llvm/System/Program.h" #include "llvm/System/Program.h"
#include "llvm/System/Path.h" #include "llvm/System/Path.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
#include "mars.h" #include "mars.h"
#include "module.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 // in gen/optimize.cpp
void ldc_optimize_module(llvm::Module* m, char lvl, bool doinline); void ldc_optimize_module(llvm::Module* m, char lvl, bool doinline);
@ -124,10 +131,6 @@ void Module::genobjfile(int multiobj)
// for (unsigned i = 0; i != MAttrs.size(); ++i) // for (unsigned i = 0; i != MAttrs.size(); ++i)
// Features.AddFeature(MAttrs[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 // allocate the target machine
std::auto_ptr<llvm::TargetMachine> target(MArch->CtorFn(*ir.module, Features.getString())); std::auto_ptr<llvm::TargetMachine> target(MArch->CtorFn(*ir.module, Features.getString()));
assert(target.get() && "Could not allocate target machine!"); assert(target.get() && "Could not allocate target machine!");
@ -182,7 +185,7 @@ void Module::genobjfile(int multiobj)
} }
// verify the llvm // verify the llvm
if (!global.params.novalidate) { if (!noVerify) {
std::string verifyErr; std::string verifyErr;
Logger::println("Verifying module..."); Logger::println("Verifying module...");
LOG_SCOPE; LOG_SCOPE;
@ -200,7 +203,7 @@ void Module::genobjfile(int multiobj)
ldc_optimize_module(ir.module, global.params.optimizeLevel, global.params.llvmInline); ldc_optimize_module(ir.module, global.params.optimizeLevel, global.params.llvmInline);
// verify the llvm // 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; std::string verifyErr;
Logger::println("Verifying module... again..."); Logger::println("Verifying module... again...");
LOG_SCOPE; LOG_SCOPE;

View file

@ -38,7 +38,7 @@ testversion=PIC
[compile] [compile]
oneatatime=yes oneatatime=yes
cmd=ldc -c $i cmd=ldmd -c $i
flag=$i flag=$i
incdir=-I$i incdir=-I$i

View file

@ -1,2 +1,2 @@
[Environment] [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@

56
tango.patch Normal file
View file

@ -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"