annotate gen/main.cpp @ 1635:601d3eea4a68

Make -nodefaultlib override -de{fault,bug}lib=foo instead of vice versa.
author Matti Niemenmaa <matti.niemenmaa+hg@iki.fi>
date Fri, 05 Mar 2010 21:40:51 +0200
parents def7a1d494fd
children 9176437d98be
rev   line source
tomas@989 1 // Pulled out of dmd/mars.c
tomas@989 2
tomas@989 3 // some things are taken from llvm's llc tool
tomas@989 4 // which uses the llvm license
tomas@989 5
tomas@989 6 #include "gen/llvm.h"
kamm@1518 7 #include "gen/llvm-version.h"
tomas@1149 8 #include "llvm/LinkAllVMCore.h"
kamm@1052 9 #include "llvm/Linker.h"
benny@1535 10 #include "llvm/LLVMContext.h"
tomas@1149 11 #include "llvm/System/Signals.h"
tomas@989 12 #include "llvm/Target/SubtargetFeature.h"
tomas@989 13 #include "llvm/Target/TargetMachine.h"
kamm@1199 14 #include "llvm/Target/TargetOptions.h"
benny@1544 15 #include "llvm/Target/TargetRegistry.h"
kamm@1518 16 #include "llvm/Target/TargetSelect.h"
tomas@989 17
tomas@989 18 #include <stdio.h>
tomas@989 19 #include <stdlib.h>
tomas@989 20 #include <assert.h>
tomas@989 21 #include <limits.h>
tomas@989 22
tomas@989 23 #if POSIX
tomas@989 24 #include <errno.h>
tomas@989 25 #elif _WIN32
tomas@989 26 #include <windows.h>
tomas@989 27 #endif
tomas@989 28
tomas@1103 29 #include "rmem.h"
tomas@989 30 #include "root.h"
tomas@989 31
tomas@989 32 #include "mars.h"
tomas@989 33 #include "module.h"
tomas@989 34 #include "mtype.h"
tomas@989 35 #include "id.h"
tomas@989 36 #include "cond.h"
tomas@989 37
tomas@989 38 #include "gen/logger.h"
tomas@989 39 #include "gen/linker.h"
tomas@989 40 #include "gen/irstate.h"
fvbommel@1482 41 #include "gen/optimizer.h"
kamm@1052 42 #include "gen/toobj.h"
fvbommel@1390 43 #include "gen/metadata.h"
kamm@1324 44 #include "gen/passes/Passes.h"
tomas@989 45
tomas@989 46 #include "gen/cl_options.h"
tomas@989 47 #include "gen/cl_helpers.h"
tomas@989 48 using namespace opts;
tomas@989 49
tomas@1103 50 #include "gen/configfile.h"
tomas@1103 51
tomas@989 52 extern void getenv_setargv(const char *envvar, int *pargc, char** *pargv);
tomas@989 53 extern void backend_init();
tomas@989 54 extern void backend_term();
tomas@989 55
tomas@989 56 static cl::opt<bool> noDefaultLib("nodefaultlib",
tomas@989 57 cl::desc("Don't add a default library for linking implicitly"),
tomas@989 58 cl::ZeroOrMore);
tomas@989 59
tomas@989 60 static ArrayAdapter impPathsStore("I", global.params.imppath);
tomas@989 61 static cl::list<std::string, ArrayAdapter> importPaths("I",
tomas@989 62 cl::desc("Where to look for imports"),
tomas@989 63 cl::value_desc("path"),
tomas@989 64 cl::location(impPathsStore),
tomas@989 65 cl::Prefix);
tomas@989 66
tomas@989 67 static ArrayAdapter defaultLibStore("defaultlib", global.params.defaultlibnames);
tomas@989 68 static cl::list<std::string, ArrayAdapter> defaultlibs("defaultlib",
tomas@989 69 cl::desc("Set default libraries for non-debug build"),
tomas@989 70 cl::value_desc("lib,..."),
tomas@989 71 cl::location(defaultLibStore),
tomas@989 72 cl::CommaSeparated);
tomas@989 73
tomas@989 74 static ArrayAdapter debugLibStore("debuglib", global.params.debuglibnames);
tomas@989 75 static cl::list<std::string, ArrayAdapter> debuglibs("debuglib",
tomas@989 76 cl::desc("Set default libraries for debug build"),
tomas@989 77 cl::value_desc("lib,..."),
tomas@989 78 cl::location(debugLibStore),
tomas@989 79 cl::CommaSeparated);
tomas@989 80
tomas@989 81 void printVersion() {
tomas@989 82 printf("LLVM D Compiler %s\nbased on DMD %s and %s\n%s\n%s\n",
tomas@989 83 global.ldc_version, global.version, global.llvm_version, global.copyright, global.written);
tomas@989 84 printf("D Language Documentation: http://www.digitalmars.com/d/1.0/index.html\n"
tomas@989 85 "LDC Homepage: http://www.dsource.org/projects/ldc\n");
tomas@989 86 }
tomas@989 87
tomas@989 88 // Helper function to handle -d-debug=* and -d-version=*
tomas@989 89 static void processVersions(std::vector<std::string>& list, char* type,
tomas@989 90 void (*setLevel)(unsigned), void (*addIdent)(const char*)) {
tomas@989 91 typedef std::vector<std::string>::iterator It;
tomas@989 92
tomas@989 93 for(It I = list.begin(), E = list.end(); I != E; ++I) {
tomas@989 94 const char* value = I->c_str();
tomas@989 95 if (isdigit(value[0])) {
tomas@989 96 errno = 0;
tomas@989 97 char* end;
tomas@989 98 long level = strtol(value, &end, 10);
tomas@989 99 if (*end || errno || level > INT_MAX) {
tomas@989 100 error("Invalid %s level: %s", type, I->c_str());
tomas@989 101 } else {
tomas@989 102 setLevel((unsigned)level);
tomas@989 103 }
tomas@989 104 } else {
tomas@989 105 char* cstr = mem.strdup(value);
tomas@989 106 if (Lexer::isValidIdentifier(cstr)) {
tomas@989 107 addIdent(cstr);
tomas@989 108 continue;
tomas@989 109 } else {
tomas@989 110 error("Invalid %s identifier or level: '%s'", type, I->c_str());
tomas@989 111 }
tomas@989 112 }
tomas@989 113 }
tomas@989 114 }
tomas@989 115
tomas@989 116 // Helper function to handle -of, -od, etc.
tomas@989 117 static void initFromString(char*& dest, const cl::opt<std::string>& src) {
tomas@989 118 dest = 0;
tomas@989 119 if (src.getNumOccurrences() != 0) {
tomas@989 120 if (src.empty())
tomas@989 121 error("Expected argument to '-%s'", src.ArgStr);
tomas@989 122 dest = mem.strdup(src.c_str());
tomas@989 123 }
tomas@989 124 }
tomas@989 125
tomas@989 126 int main(int argc, char** argv)
tomas@989 127 {
tomas@1149 128 // stack trace on signals
tomas@1149 129 llvm::sys::PrintStackTraceOnErrorSignal();
tomas@1149 130
tomas@989 131 Array files;
tomas@989 132 char *p, *ext;
tomas@989 133 Module *m;
tomas@989 134 int status = EXIT_SUCCESS;
tomas@989 135
tomas@989 136 // Set some default values
tomas@989 137 #if _WIN32
tomas@989 138 char buf[MAX_PATH];
tomas@989 139 GetModuleFileName(NULL, buf, MAX_PATH);
tomas@989 140 global.params.argv0 = buf;
tomas@989 141 #else
tomas@989 142 global.params.argv0 = argv[0];
tomas@989 143 #endif
tomas@989 144 global.params.useSwitchError = 1;
tomas@989 145
tomas@989 146 global.params.linkswitches = new Array();
tomas@989 147 global.params.libfiles = new Array();
tomas@989 148 global.params.objfiles = new Array();
tomas@989 149 global.params.ddocfiles = new Array();
kamm@1402 150
kamm@1402 151 global.params.moduleDeps = NULL;
kamm@1402 152 global.params.moduleDepsFile = NULL;
tomas@999 153
tomas@989 154 // Set predefined version identifiers
tomas@989 155 VersionCondition::addPredefinedGlobalIdent("LLVM");
tomas@989 156 VersionCondition::addPredefinedGlobalIdent("LDC");
tomas@989 157 VersionCondition::addPredefinedGlobalIdent("all");
tomas@999 158 #if DMDV2
tomas@999 159 VersionCondition::addPredefinedGlobalIdent("D_Version2");
tomas@999 160 #endif
tomas@999 161
tomas@1103 162 // merge DFLAGS environment variable into argc/argv
tomas@989 163 getenv_setargv("DFLAGS", &argc, &argv);
tomas@989 164 #if 0
tomas@989 165 for (int i = 0; i < argc; i++)
tomas@989 166 {
tomas@989 167 printf("argv[%d] = '%s'\n", i, argv[i]);
tomas@989 168 }
tomas@989 169 #endif
tomas@989 170
tomas@1103 171 // build complete fixed up list of command line arguments
tomas@1103 172 std::vector<const char*> final_args;
tomas@1103 173 final_args.reserve(argc);
tomas@1103 174
kamm@1197 175 // insert command line args until -run is reached
kamm@1197 176 int run_argnum = 1;
kamm@1197 177 while (run_argnum < argc && strncmp(argv[run_argnum], "-run", 4) != 0)
kamm@1197 178 ++run_argnum;
kamm@1197 179 final_args.insert(final_args.end(), &argv[0], &argv[run_argnum]);
tomas@1103 180
tomas@1103 181 // read the configuration file
tomas@1103 182 ConfigFile cfg_file;
tomas@1103 183
tomas@1103 184 // just ignore errors for now, they are still printed
tomas@1103 185 #if DMDV2
tomas@1103 186 #define CFG_FILENAME "ldc2.conf"
tomas@1103 187 #else
tomas@1103 188 #define CFG_FILENAME "ldc.conf"
tomas@1103 189 #endif
tomas@1103 190 cfg_file.read(global.params.argv0, (void*)main, CFG_FILENAME);
tomas@1103 191 #undef CFG_FILENAME
tomas@1103 192
tomas@1103 193 // insert config file additions to the argument list
tomas@1103 194 final_args.insert(final_args.end(), cfg_file.switches_begin(), cfg_file.switches_end());
tomas@1103 195
kamm@1197 196 // insert -run and everything beyond
kamm@1197 197 final_args.insert(final_args.end(), &argv[run_argnum], &argv[argc]);
kamm@1197 198
tomas@1103 199 #if 0
tomas@1103 200 for (size_t i = 0; i < final_args.size(); ++i)
tomas@1103 201 {
tomas@1103 202 printf("final_args[%zu] = %s\n", i, final_args[i]);
tomas@1103 203 }
tomas@1103 204 #endif
tomas@1103 205
tomas@989 206 // Handle fixed-up arguments!
tomas@989 207 cl::SetVersionPrinter(&printVersion);
tomas@1103 208 cl::ParseCommandLineOptions(final_args.size(), (char**)&final_args[0], "LLVM-based D Compiler\n", true);
tomas@989 209
fvbommel@1484 210 // Print config file path if -v was passed
fvbommel@1484 211 if (global.params.verbose) {
fvbommel@1484 212 const std::string& path = cfg_file.path();
fvbommel@1484 213 if (!path.empty())
fvbommel@1484 214 printf("config %s\n", path.c_str());
fvbommel@1484 215 }
fvbommel@1484 216
tomas@989 217 // Negated options
tomas@989 218 global.params.link = !compileOnly;
tomas@989 219 global.params.obj = !dontWriteObj;
tomas@989 220 global.params.useInlineAsm = !noAsm;
tomas@989 221
tomas@989 222 // String options: std::string --> char*
tomas@989 223 initFromString(global.params.objname, objectFile);
tomas@989 224 initFromString(global.params.objdir, objectDir);
tomas@989 225
tomas@989 226 initFromString(global.params.docdir, ddocDir);
tomas@989 227 initFromString(global.params.docname, ddocFile);
tomas@989 228 global.params.doDocComments |=
tomas@989 229 global.params.docdir || global.params.docname;
tomas@989 230
tomas@989 231 #ifdef _DH
tomas@989 232 initFromString(global.params.hdrdir, hdrDir);
tomas@989 233 initFromString(global.params.hdrname, hdrFile);
tomas@989 234 global.params.doHdrGeneration |=
tomas@989 235 global.params.hdrdir || global.params.hdrname;
tomas@989 236 #endif
tomas@989 237
kamm@1402 238 initFromString(global.params.moduleDepsFile, moduleDepsFile);
kamm@1402 239 if (global.params.moduleDepsFile != NULL)
kamm@1402 240 {
kamm@1402 241 global.params.moduleDeps = new OutBuffer;
kamm@1402 242 }
kamm@1402 243
tomas@989 244 processVersions(debugArgs, "debug",
tomas@989 245 DebugCondition::setGlobalLevel,
tomas@989 246 DebugCondition::addGlobalIdent);
tomas@989 247 processVersions(versions, "version",
tomas@989 248 VersionCondition::setGlobalLevel,
tomas@989 249 VersionCondition::addGlobalIdent);
tomas@989 250
tomas@989 251 global.params.output_o =
fvbommel@1415 252 (opts::output_o == cl::BOU_UNSET
fvbommel@1415 253 && !(opts::output_bc || opts::output_ll || opts::output_s))
tomas@989 254 ? OUTPUTFLAGdefault
tomas@989 255 : opts::output_o == cl::BOU_TRUE
tomas@989 256 ? OUTPUTFLAGset
tomas@989 257 : OUTPUTFLAGno;
tomas@989 258 global.params.output_bc = opts::output_bc ? OUTPUTFLAGset : OUTPUTFLAGno;
tomas@989 259 global.params.output_ll = opts::output_ll ? OUTPUTFLAGset : OUTPUTFLAGno;
tomas@989 260 global.params.output_s = opts::output_s ? OUTPUTFLAGset : OUTPUTFLAGno;
tomas@989 261
tomas@989 262 if (global.params.run || !runargs.empty()) {
tomas@989 263 // FIXME: how to properly detect the presence of a PositionalEatsArgs
tomas@989 264 // option without parameters? We want to emit an error in that case...
tomas@989 265 // You'd think getNumOccurrences would do it, but it just returns the
tomas@989 266 // number of parameters)
tomas@989 267 // NOTE: Hacked around it by detecting -run in getenv_setargv(), where
tomas@989 268 // we're looking for it anyway, and pre-setting the flag...
tomas@989 269 global.params.run = true;
tomas@989 270 if (!runargs.empty()) {
tomas@989 271 files.push(mem.strdup(runargs[0].c_str()));
tomas@989 272 } else {
tomas@989 273 global.params.run = false;
tomas@989 274 error("Expected at least one argument to '-run'\n");
tomas@989 275 }
tomas@989 276 }
tomas@989 277
tomas@989 278
tomas@989 279 files.reserve(fileList.size());
tomas@989 280 typedef std::vector<std::string>::iterator It;
tomas@989 281 for(It I = fileList.begin(), E = fileList.end(); I != E; ++I)
tomas@989 282 if (!I->empty())
tomas@989 283 files.push(mem.strdup(I->c_str()));
tomas@989 284
tomas@989 285 if (global.errors)
tomas@989 286 {
kamm@1007 287 fatal();
tomas@989 288 }
tomas@989 289 if (files.dim == 0)
tomas@989 290 {
tomas@989 291 cl::PrintHelpMessage();
kamm@1007 292 return EXIT_FAILURE;
tomas@989 293 }
tomas@989 294
tomas@989 295 Array* libs;
tomas@989 296 if (global.params.symdebug)
kamm@1199 297 {
kamm@1007 298 libs = global.params.debuglibnames;
kamm@1199 299 llvm::NoFramePointerElim = true;
kamm@1199 300 }
tomas@989 301 else
kamm@1007 302 libs = global.params.defaultlibnames;
tomas@989 303
matti@1635 304 if (!noDefaultLib)
tomas@989 305 {
matti@1635 306 if (libs)
kamm@1007 307 {
matti@1635 308 for (int i = 0; i < libs->dim; i++)
matti@1635 309 {
matti@1635 310 char* lib = (char *)libs->data[i];
matti@1635 311 char *arg = (char *)mem.malloc(strlen(lib) + 3);
matti@1635 312 strcpy(arg, "-l");
matti@1635 313 strcpy(arg+2, lib);
matti@1635 314 global.params.linkswitches->push(arg);
matti@1635 315 }
kamm@1007 316 }
matti@1635 317 else
matti@1635 318 {
robert@1527 319 #if DMDV2
matti@1635 320 global.params.linkswitches->push(mem.strdup("-ldruntime-ldc"));
robert@1527 321 #else
matti@1635 322 global.params.linkswitches->push(mem.strdup("-lldc-runtime"));
matti@1635 323 global.params.linkswitches->push(mem.strdup("-ltango-cc-tango"));
matti@1635 324 global.params.linkswitches->push(mem.strdup("-ltango-gc-basic"));
matti@1635 325 // pass the runtime again to resolve issues
matti@1635 326 // with linking order
matti@1635 327 global.params.linkswitches->push(mem.strdup("-lldc-runtime"));
robert@1523 328 #endif
matti@1635 329 }
tomas@989 330 }
tomas@989 331
tomas@989 332 if (global.params.run)
tomas@989 333 quiet = 1;
tomas@989 334
tomas@989 335 if (global.params.useUnitTests)
kamm@1007 336 global.params.useAssert = 1;
tomas@989 337
tomas@989 338 // LDC output determination
tomas@989 339
tomas@989 340 // if we don't link, autodetect target from extension
tomas@989 341 if(!global.params.link && global.params.objname) {
kamm@1007 342 ext = FileName::ext(global.params.objname);
kamm@1007 343 bool autofound = false;
kamm@1007 344 if (!ext) {
kamm@1007 345 // keep things as they are
kamm@1007 346 } else if (strcmp(ext, global.ll_ext) == 0) {
kamm@1007 347 global.params.output_ll = OUTPUTFLAGset;
kamm@1007 348 autofound = true;
kamm@1007 349 } else if (strcmp(ext, global.bc_ext) == 0) {
kamm@1007 350 global.params.output_bc = OUTPUTFLAGset;
kamm@1007 351 autofound = true;
kamm@1007 352 } else if (strcmp(ext, global.s_ext) == 0) {
kamm@1007 353 global.params.output_s = OUTPUTFLAGset;
kamm@1007 354 autofound = true;
kamm@1007 355 } else if (strcmp(ext, global.obj_ext) == 0) {
kamm@1007 356 global.params.output_o = OUTPUTFLAGset;
kamm@1007 357 autofound = true;
kamm@1007 358 } else {
kamm@1007 359 // append dot, so forceExt won't change existing name even if it contains dots
kamm@1007 360 size_t len = strlen(global.params.objname);
kamm@1007 361 size_t extlen = strlen(".");
kamm@1007 362 char* s = (char *)mem.malloc(len + 1 + extlen + 1);
kamm@1007 363 memcpy(s, global.params.objname, len);
kamm@1007 364 s[len] = '.';
kamm@1007 365 s[len+1+extlen] = 0;
kamm@1007 366 global.params.objname = s;
tomas@989 367
kamm@1007 368 }
kamm@1007 369 if(autofound && global.params.output_o == OUTPUTFLAGdefault)
kamm@1007 370 global.params.output_o = OUTPUTFLAGno;
tomas@989 371 }
tomas@989 372
tomas@989 373 // only link if possible
tomas@989 374 if (!global.params.obj || !global.params.output_o)
kamm@1007 375 global.params.link = 0;
tomas@989 376
tomas@989 377 if (global.params.link)
tomas@989 378 {
kamm@1007 379 global.params.exefile = global.params.objname;
kamm@1007 380 if (files.dim > 1)
kamm@1007 381 global.params.objname = NULL;
tomas@989 382 }
tomas@989 383 else if (global.params.run)
tomas@989 384 {
kamm@1007 385 error("flags conflict with -run");
kamm@1007 386 fatal();
tomas@989 387 }
tomas@989 388 else
tomas@989 389 {
kamm@1433 390 if (global.params.objname && files.dim > 1 && !singleObj)
kamm@1007 391 {
kamm@1007 392 error("multiple source files, but only one .obj name");
kamm@1007 393 fatal();
kamm@1007 394 }
tomas@989 395 }
tomas@989 396
tomas@989 397 // create a proper target
tomas@1147 398 Ir ir;
tomas@1021 399
tomas@1021 400 // check -m32/64 sanity
tomas@1021 401 if (m32bits && m64bits)
tomas@1021 402 error("cannot use both -m32 and -m64 options");
benny@1544 403 else if ((m32bits || m64bits) && (!mArch.empty() || !mTargetTriple.empty()))
tomas@1021 404 error("-m32 and -m64 switches cannot be used together with -march and -mtriple switches");
tomas@1021 405 if (global.errors)
tomas@1021 406 fatal();
tomas@1021 407
tomas@1021 408 // override triple if needed
tomas@1021 409 const char* defaultTriple = DEFAULT_TARGET_TRIPLE;
tomas@1021 410 if ((sizeof(void*) == 4 && m64bits) || (sizeof(void*) == 8 && m32bits))
tomas@1021 411 {
tomas@1021 412 defaultTriple = DEFAULT_ALT_TARGET_TRIPLE;
tomas@1021 413 }
tomas@1021 414
tomas@989 415 // did the user override the target triple?
tomas@989 416 if (mTargetTriple.empty())
tomas@989 417 {
benny@1544 418 if (!mArch.empty())
tomas@989 419 {
tomas@989 420 error("you must specify a target triple as well with -mtriple when using the -march option");
tomas@989 421 fatal();
tomas@989 422 }
tomas@1021 423 global.params.targetTriple = defaultTriple;
tomas@989 424 }
tomas@989 425 else
tomas@989 426 {
tomas@989 427 global.params.targetTriple = mTargetTriple.c_str();
tomas@989 428 }
tomas@989 429
benny@1570 430 std::string triple = global.params.targetTriple;
tomas@989 431
kamm@1518 432 // Allocate target machine.
kamm@1518 433
kamm@1518 434 // first initialize llvm
benny@1543 435 #define LLVM_TARGET(A) LLVMInitialize##A##TargetInfo(); LLVMInitialize##A##Target(); LLVMInitialize##A##AsmPrinter();
kamm@1518 436 // this is defined to be LLVM_TARGET(target name 1) LLVM_TARGET(target name 2) ...
kamm@1518 437 LDC_TARGETS
kamm@1518 438 #undef LLVM_TARGET
kamm@1518 439
benny@1544 440 const llvm::Target *theTarget = NULL;
kamm@1518 441 // Check whether the user has explicitly specified an architecture to compile for.
benny@1544 442 if (mArch.empty())
tomas@989 443 {
tomas@989 444 std::string Err;
benny@1570 445 theTarget = llvm::TargetRegistry::lookupTarget(triple, Err);
benny@1543 446 if (theTarget == 0)
tomas@989 447 {
tomas@997 448 error("failed to auto-select target: %s, please use the -march option", Err.c_str());
tomas@989 449 fatal();
tomas@989 450 }
tomas@989 451 }
benny@1543 452 else
benny@1543 453 {
benny@1544 454 for (llvm::TargetRegistry::iterator it = llvm::TargetRegistry::begin(),
benny@1544 455 ie = llvm::TargetRegistry::end(); it != ie; ++it)
benny@1544 456 {
benny@1544 457 if (mArch == it->getName())
benny@1544 458 {
benny@1544 459 theTarget = &*it;
benny@1544 460 break;
benny@1544 461 }
benny@1544 462 }
benny@1544 463
benny@1544 464 if (!theTarget)
benny@1544 465 {
benny@1544 466 error("invalid target '%s'", mArch.c_str());
benny@1544 467 fatal();
benny@1544 468 }
benny@1543 469 }
tomas@989 470
tomas@989 471 // Package up features to be passed to target/subtarget
tomas@989 472 std::string FeaturesStr;
tomas@989 473 if (mCPU.size() || mAttrs.size())
tomas@989 474 {
tomas@989 475 llvm::SubtargetFeatures Features;
tomas@989 476 Features.setCPU(mCPU);
tomas@989 477 for (unsigned i = 0; i != mAttrs.size(); ++i)
tomas@989 478 Features.AddFeature(mAttrs[i]);
tomas@989 479 FeaturesStr = Features.getString();
tomas@989 480 }
tomas@989 481
benny@1570 482 std::auto_ptr<llvm::TargetMachine> target(theTarget->createTargetMachine(triple, FeaturesStr));
tomas@989 483 assert(target.get() && "Could not allocate target machine!");
tomas@989 484 gTargetMachine = target.get();
tomas@989 485 gTargetData = gTargetMachine->getTargetData();
tomas@989 486
tomas@989 487 // get final data layout
tomas@989 488 std::string datalayout = gTargetData->getStringRepresentation();
tomas@989 489 global.params.dataLayout = datalayout.c_str();
tomas@989 490
benny@1543 491 global.params.llvmArch = theTarget->getName();
tomas@989 492
tomas@989 493 if (strcmp(global.params.llvmArch,"x86")==0) {
tomas@989 494 VersionCondition::addPredefinedGlobalIdent("X86");
tomas@989 495 global.params.isLE = true;
tomas@989 496 global.params.is64bit = false;
tomas@989 497 global.params.cpu = ARCHx86;
tomas@989 498 if (global.params.useInlineAsm) {
kamm@1033 499 VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86");
tomas@989 500 }
tomas@989 501 }
tomas@989 502 else if (strcmp(global.params.llvmArch,"x86-64")==0) {
tomas@989 503 VersionCondition::addPredefinedGlobalIdent("X86_64");
tomas@989 504 global.params.isLE = true;
tomas@989 505 global.params.is64bit = true;
tomas@989 506 global.params.cpu = ARCHx86_64;
tomas@989 507 if (global.params.useInlineAsm) {
kamm@1033 508 VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86_64");
tomas@989 509 }
tomas@989 510 }
tomas@989 511 else if (strcmp(global.params.llvmArch,"ppc32")==0) {
tomas@989 512 VersionCondition::addPredefinedGlobalIdent("PPC");
tomas@989 513 global.params.isLE = false;
tomas@989 514 global.params.is64bit = false;
tomas@989 515 global.params.cpu = ARCHppc;
tomas@989 516 }
tomas@989 517 else if (strcmp(global.params.llvmArch,"ppc64")==0) {
tomas@989 518 VersionCondition::addPredefinedGlobalIdent("PPC64");
tomas@989 519 global.params.isLE = false;
tomas@989 520 global.params.is64bit = true;
tomas@989 521 global.params.cpu = ARCHppc_64;
tomas@989 522 }
tomas@989 523 else if (strcmp(global.params.llvmArch,"arm")==0) {
tomas@989 524 VersionCondition::addPredefinedGlobalIdent("ARM");
tomas@989 525 global.params.isLE = true;
tomas@989 526 global.params.is64bit = false;
tomas@989 527 global.params.cpu = ARCHarm;
tomas@989 528 }
tomas@989 529 else if (strcmp(global.params.llvmArch,"thumb")==0) {
tomas@989 530 VersionCondition::addPredefinedGlobalIdent("Thumb");
tomas@989 531 global.params.isLE = true;
tomas@989 532 global.params.is64bit = false;
tomas@989 533 global.params.cpu = ARCHthumb;
tomas@989 534 }
tomas@989 535 else {
tomas@989 536 error("invalid cpu architecture specified: %s", global.params.llvmArch);
tomas@989 537 fatal();
tomas@989 538 }
tomas@989 539
tomas@989 540 // endianness
tomas@989 541 if (global.params.isLE) {
tomas@989 542 VersionCondition::addPredefinedGlobalIdent("LittleEndian");
tomas@989 543 }
tomas@989 544 else {
tomas@989 545 VersionCondition::addPredefinedGlobalIdent("BigEndian");
tomas@989 546 }
tomas@989 547
tomas@989 548 // a generic 64bit version
tomas@989 549 if (global.params.is64bit) {
tomas@989 550 VersionCondition::addPredefinedGlobalIdent("LLVM64");
tomas@999 551 // FIXME: is this always correct?
tomas@999 552 VersionCondition::addPredefinedGlobalIdent("D_LP64");
tomas@989 553 }
tomas@989 554
tomas@989 555 // parse the OS out of the target triple
tomas@989 556 // see http://gcc.gnu.org/install/specific.html for details
tomas@989 557 // also llvm's different SubTargets have useful information
tomas@989 558 size_t npos = std::string::npos;
tomas@989 559
tomas@989 560 // windows
tomas@989 561 // FIXME: win64
tomas@989 562 if (triple.find("windows") != npos || triple.find("win32") != npos || triple.find("mingw") != npos)
tomas@989 563 {
tomas@989 564 global.params.os = OSWindows;
tomas@989 565 VersionCondition::addPredefinedGlobalIdent("Windows");
tomas@989 566 VersionCondition::addPredefinedGlobalIdent("Win32");
tomas@989 567 VersionCondition::addPredefinedGlobalIdent("mingw32");
tomas@989 568 }
tomas@989 569 // FIXME: cygwin
tomas@989 570 else if (triple.find("cygwin") != npos)
tomas@989 571 {
tomas@989 572 error("CygWin is not yet supported");
tomas@989 573 fatal();
tomas@989 574 }
tomas@989 575 // linux
tomas@989 576 else if (triple.find("linux") != npos)
tomas@989 577 {
tomas@989 578 global.params.os = OSLinux;
tomas@989 579 VersionCondition::addPredefinedGlobalIdent("linux");
tomas@989 580 VersionCondition::addPredefinedGlobalIdent("Posix");
tomas@989 581 }
tomas@989 582 // darwin
tomas@989 583 else if (triple.find("-darwin") != npos)
tomas@989 584 {
tomas@989 585 global.params.os = OSMacOSX;
tomas@989 586 VersionCondition::addPredefinedGlobalIdent("OSX");
tomas@989 587 VersionCondition::addPredefinedGlobalIdent("darwin");
tomas@989 588 VersionCondition::addPredefinedGlobalIdent("Posix");
tomas@989 589 }
tomas@989 590 // freebsd
tomas@989 591 else if (triple.find("-freebsd") != npos)
tomas@989 592 {
tomas@989 593 global.params.os = OSFreeBSD;
tomas@989 594 VersionCondition::addPredefinedGlobalIdent("freebsd");
tomas@1387 595 VersionCondition::addPredefinedGlobalIdent("FreeBSD");
tomas@989 596 VersionCondition::addPredefinedGlobalIdent("Posix");
tomas@989 597 }
tomas@989 598 // solaris
tomas@989 599 else if (triple.find("-solaris") != npos)
tomas@989 600 {
tomas@989 601 global.params.os = OSSolaris;
tomas@989 602 VersionCondition::addPredefinedGlobalIdent("solaris");
tomas@1387 603 VersionCondition::addPredefinedGlobalIdent("Solaris");
tomas@989 604 VersionCondition::addPredefinedGlobalIdent("Posix");
tomas@989 605 }
tomas@989 606 // unsupported
tomas@989 607 else
tomas@989 608 {
tomas@1463 609 error("target '%s' is not yet supported", global.params.targetTriple);
tomas@989 610 fatal();
tomas@989 611 }
tomas@989 612
tomas@989 613 // added in 1.039
tomas@989 614 if (global.params.doDocComments)
tomas@989 615 VersionCondition::addPredefinedGlobalIdent("D_Ddoc");
tomas@989 616
tomas@999 617 #if DMDV2
tomas@999 618 // unittests?
tomas@999 619 if (global.params.useUnitTests)
tomas@999 620 VersionCondition::addPredefinedGlobalIdent("unittest");
tomas@999 621 #endif
tomas@999 622
tomas@989 623 // Initialization
tomas@1147 624 Type::init(&ir);
tomas@989 625 Id::initialize();
tomas@989 626 Module::init();
tomas@989 627 initPrecedence();
tomas@989 628
tomas@989 629 backend_init();
tomas@989 630
tomas@989 631 //printf("%d source files\n",files.dim);
tomas@989 632
tomas@989 633 // Build import search path
tomas@989 634 if (global.params.imppath)
tomas@989 635 {
kamm@1007 636 for (int i = 0; i < global.params.imppath->dim; i++)
kamm@1007 637 {
kamm@1007 638 char *path = (char *)global.params.imppath->data[i];
kamm@1007 639 Array *a = FileName::splitPath(path);
tomas@989 640
kamm@1007 641 if (a)
kamm@1007 642 {
kamm@1007 643 if (!global.path)
kamm@1007 644 global.path = new Array();
kamm@1007 645 global.path->append(a);
kamm@1007 646 }
tomas@989 647 }
tomas@989 648 }
tomas@989 649
tomas@989 650 // Build string import search path
tomas@989 651 if (global.params.fileImppath)
tomas@989 652 {
kamm@1007 653 for (int i = 0; i < global.params.fileImppath->dim; i++)
kamm@1007 654 {
kamm@1007 655 char *path = (char *)global.params.fileImppath->data[i];
kamm@1007 656 Array *a = FileName::splitPath(path);
tomas@989 657
kamm@1007 658 if (a)
kamm@1007 659 {
kamm@1007 660 if (!global.filePath)
kamm@1007 661 global.filePath = new Array();
kamm@1007 662 global.filePath->append(a);
kamm@1007 663 }
tomas@989 664 }
tomas@989 665 }
tomas@989 666
tomas@989 667 // Create Modules
tomas@989 668 Array modules;
tomas@989 669 modules.reserve(files.dim);
tomas@989 670 for (int i = 0; i < files.dim; i++)
tomas@989 671 { Identifier *id;
kamm@1007 672 char *ext;
kamm@1007 673 char *name;
tomas@989 674
kamm@1007 675 p = (char *) files.data[i];
tomas@989 676
kamm@1007 677 p = FileName::name(p); // strip path
kamm@1007 678 ext = FileName::ext(p);
kamm@1007 679 if (ext)
kamm@1007 680 {
tomas@989 681 #if POSIX
kamm@1007 682 if (strcmp(ext, global.obj_ext) == 0 ||
kamm@1007 683 strcmp(ext, global.bc_ext) == 0)
tomas@989 684 #else
kamm@1007 685 if (stricmp(ext, global.obj_ext) == 0 ||
kamm@1007 686 stricmp(ext, global.bc_ext) == 0)
tomas@989 687 #endif
kamm@1007 688 {
kamm@1007 689 global.params.objfiles->push(files.data[i]);
kamm@1007 690 continue;
kamm@1007 691 }
kamm@1007 692
kamm@1007 693 #if POSIX
kamm@1007 694 if (strcmp(ext, "a") == 0)
kamm@1007 695 #elif __MINGW32__
kamm@1007 696 if (stricmp(ext, "a") == 0)
kamm@1007 697 #else
kamm@1007 698 if (stricmp(ext, "lib") == 0)
kamm@1007 699 #endif
kamm@1007 700 {
kamm@1007 701 global.params.libfiles->push(files.data[i]);
kamm@1007 702 continue;
kamm@1007 703 }
kamm@1007 704
kamm@1007 705 if (strcmp(ext, global.ddoc_ext) == 0)
kamm@1007 706 {
kamm@1007 707 global.params.ddocfiles->push(files.data[i]);
kamm@1007 708 continue;
kamm@1007 709 }
kamm@1007 710
kamm@1007 711 #if !POSIX
kamm@1007 712 if (stricmp(ext, "res") == 0)
kamm@1007 713 {
kamm@1007 714 global.params.resfile = (char *)files.data[i];
kamm@1007 715 continue;
kamm@1007 716 }
kamm@1007 717
kamm@1007 718 if (stricmp(ext, "def") == 0)
kamm@1007 719 {
kamm@1007 720 global.params.deffile = (char *)files.data[i];
kamm@1007 721 continue;
kamm@1007 722 }
kamm@1007 723
kamm@1007 724 if (stricmp(ext, "exe") == 0)
kamm@1007 725 {
kamm@1007 726 global.params.exefile = (char *)files.data[i];
kamm@1007 727 continue;
kamm@1007 728 }
kamm@1007 729 #endif
kamm@1007 730
kamm@1007 731 if (stricmp(ext, global.mars_ext) == 0 ||
kamm@1007 732 stricmp(ext, global.hdr_ext) == 0 ||
kamm@1007 733 stricmp(ext, "htm") == 0 ||
kamm@1007 734 stricmp(ext, "html") == 0 ||
kamm@1007 735 stricmp(ext, "xhtml") == 0)
kamm@1007 736 {
kamm@1007 737 ext--; // skip onto '.'
kamm@1007 738 assert(*ext == '.');
kamm@1007 739 name = (char *)mem.malloc((ext - p) + 1);
kamm@1007 740 memcpy(name, p, ext - p);
kamm@1007 741 name[ext - p] = 0; // strip extension
kamm@1007 742
kamm@1007 743 if (name[0] == 0 ||
kamm@1007 744 strcmp(name, "..") == 0 ||
kamm@1007 745 strcmp(name, ".") == 0)
kamm@1007 746 {
kamm@1007 747 Linvalid:
kamm@1007 748 error("invalid file name '%s'", (char *)files.data[i]);
kamm@1007 749 fatal();
kamm@1007 750 }
kamm@1007 751 }
kamm@1007 752 else
kamm@1007 753 { error("unrecognized file extension %s\n", ext);
kamm@1007 754 fatal();
kamm@1007 755 }
kamm@1007 756 }
kamm@1007 757 else
kamm@1007 758 { name = p;
kamm@1007 759 if (!*name)
kamm@1007 760 goto Linvalid;
tomas@989 761 }
tomas@989 762
kamm@1007 763 id = new Identifier(name, 0);
kamm@1007 764 m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration);
kamm@1007 765 modules.push(m);
tomas@989 766 }
tomas@989 767
tomas@989 768 // Read files, parse them
tomas@989 769 for (int i = 0; i < modules.dim; i++)
tomas@989 770 {
kamm@1007 771 m = (Module *)modules.data[i];
kamm@1007 772 if (global.params.verbose)
kamm@1007 773 printf("parse %s\n", m->toChars());
kamm@1007 774 if (!Module::rootModule)
kamm@1007 775 Module::rootModule = m;
kamm@1007 776 m->importedFrom = m;
kamm@1007 777 m->read(0);
kamm@1007 778 m->parse();
kamm@1007 779 m->buildTargetFiles();
kamm@1007 780 m->deleteObjFile();
kamm@1007 781 if (m->isDocFile)
kamm@1007 782 {
kamm@1007 783 m->gendocfile();
tomas@989 784
kamm@1007 785 // Remove m from list of modules
kamm@1007 786 modules.remove(i);
kamm@1007 787 i--;
kamm@1007 788 }
tomas@989 789 }
tomas@989 790 if (global.errors)
kamm@1007 791 fatal();
tomas@989 792 #ifdef _DH
tomas@989 793 if (global.params.doHdrGeneration)
tomas@989 794 {
kamm@1007 795 /* Generate 'header' import files.
kamm@1007 796 * Since 'header' import files must be independent of command
kamm@1007 797 * line switches and what else is imported, they are generated
kamm@1007 798 * before any semantic analysis.
kamm@1007 799 */
kamm@1007 800 for (int i = 0; i < modules.dim; i++)
kamm@1007 801 {
kamm@1007 802 m = (Module *)modules.data[i];
kamm@1007 803 if (global.params.verbose)
kamm@1007 804 printf("import %s\n", m->toChars());
kamm@1007 805 m->genhdrfile();
kamm@1007 806 }
tomas@989 807 }
tomas@989 808 if (global.errors)
kamm@1007 809 fatal();
tomas@989 810 #endif
tomas@989 811
kamm@1587 812 // load all unconditional imports for better symbol resolving
kamm@1587 813 for (int i = 0; i < modules.dim; i++)
kamm@1587 814 {
kamm@1587 815 m = (Module *)modules.data[i];
kamm@1587 816 if (global.params.verbose)
kamm@1587 817 printf("importall %s\n", m->toChars());
kamm@1587 818 m->importAll(0);
kamm@1587 819 }
kamm@1587 820 if (global.errors)
kamm@1587 821 fatal();
kamm@1587 822
tomas@989 823 // Do semantic analysis
tomas@989 824 for (int i = 0; i < modules.dim; i++)
tomas@989 825 {
kamm@1007 826 m = (Module *)modules.data[i];
kamm@1007 827 if (global.params.verbose)
kamm@1007 828 printf("semantic %s\n", m->toChars());
kamm@1007 829 m->semantic();
tomas@989 830 }
tomas@989 831 if (global.errors)
kamm@1007 832 fatal();
tomas@989 833
tomas@989 834 // Do pass 2 semantic analysis
tomas@989 835 for (int i = 0; i < modules.dim; i++)
tomas@989 836 {
kamm@1007 837 m = (Module *)modules.data[i];
kamm@1007 838 if (global.params.verbose)
kamm@1007 839 printf("semantic2 %s\n", m->toChars());
kamm@1007 840 m->semantic2();
tomas@989 841 }
tomas@989 842 if (global.errors)
kamm@1007 843 fatal();
tomas@989 844
tomas@989 845 // Do pass 3 semantic analysis
tomas@989 846 for (int i = 0; i < modules.dim; i++)
tomas@989 847 {
kamm@1007 848 m = (Module *)modules.data[i];
kamm@1007 849 if (global.params.verbose)
kamm@1007 850 printf("semantic3 %s\n", m->toChars());
kamm@1007 851 m->semantic3();
tomas@989 852 }
tomas@989 853 if (global.errors)
kamm@1007 854 fatal();
tomas@989 855
tomas@989 856 #if !IN_LLVM
tomas@989 857 // Scan for functions to inline
tomas@989 858 if (global.params.useInline)
tomas@989 859 {
kamm@1007 860 /* The problem with useArrayBounds and useAssert is that the
kamm@1007 861 * module being linked to may not have generated them, so if
kamm@1007 862 * we inline functions from those modules, the symbols for them will
kamm@1007 863 * not be found at link time.
kamm@1007 864 */
kamm@1007 865 if (!global.params.useArrayBounds && !global.params.useAssert)
benny@1532 866 #else
fvbommel@1482 867 // This doesn't play nice with debug info at the moment
fvbommel@1482 868 if (!global.params.symdebug && willInline())
fvbommel@1482 869 {
fvbommel@1482 870 global.params.useAvailableExternally = true;
fvbommel@1482 871 Logger::println("Running some extra semantic3's for inlining purposes");
fvbommel@1482 872 #endif
kamm@1007 873 {
kamm@1007 874 // Do pass 3 semantic analysis on all imported modules,
kamm@1007 875 // since otherwise functions in them cannot be inlined
kamm@1007 876 for (int i = 0; i < Module::amodules.dim; i++)
kamm@1007 877 {
kamm@1007 878 m = (Module *)Module::amodules.data[i];
kamm@1007 879 if (global.params.verbose)
kamm@1007 880 printf("semantic3 %s\n", m->toChars());
kamm@1007 881 m->semantic3();
kamm@1007 882 }
kamm@1007 883 if (global.errors)
kamm@1007 884 fatal();
kamm@1007 885 }
kamm@1007 886
fvbommel@1482 887 #if !IN_LLVM
kamm@1007 888 for (int i = 0; i < modules.dim; i++)
tomas@989 889 {
kamm@1007 890 m = (Module *)modules.data[i];
kamm@1007 891 if (global.params.verbose)
kamm@1007 892 printf("inline scan %s\n", m->toChars());
kamm@1007 893 m->inlineScan();
tomas@989 894 }
fvbommel@1482 895 #endif
kamm@1007 896 }
kamm@1007 897 if (global.errors)
tomas@989 898 fatal();
tomas@989 899
kamm@1402 900 // write module dependencies to file if requested
kamm@1402 901 if (global.params.moduleDepsFile != NULL)
kamm@1402 902 {
kamm@1402 903 assert (global.params.moduleDepsFile != NULL);
kamm@1402 904
kamm@1402 905 File deps(global.params.moduleDepsFile);
kamm@1402 906 OutBuffer* ob = global.params.moduleDeps;
kamm@1402 907 deps.setbuffer((void*)ob->data, ob->offset);
kamm@1402 908 deps.write();
kamm@1402 909 }
kamm@1402 910
kamm@1052 911 // collects llvm modules to be linked if singleobj is passed
kamm@1052 912 std::vector<llvm::Module*> llvmModules;
benny@1570 913 llvm::LLVMContext& context = llvm::getGlobalContext();
kamm@1052 914
kamm@1007 915 // Generate output files
tomas@989 916 for (int i = 0; i < modules.dim; i++)
tomas@989 917 {
tomas@989 918 m = (Module *)modules.data[i];
tomas@989 919 if (global.params.verbose)
kamm@1007 920 printf("code %s\n", m->toChars());
kamm@1007 921 if (global.params.obj)
kamm@1007 922 {
benny@1535 923 llvm::Module* lm = m->genLLVMModule(context, &ir);
kamm@1052 924 if (!singleObj)
kamm@1052 925 {
kamm@1052 926 m->deleteObjFile();
kamm@1052 927 writeModule(lm, m->objfile->name->str);
kamm@1052 928 global.params.objfiles->push(m->objfile->name->str);
kamm@1052 929 delete lm;
kamm@1052 930 }
kamm@1052 931 else
kamm@1052 932 llvmModules.push_back(lm);
kamm@1007 933 }
kamm@1007 934 if (global.errors)
kamm@1007 935 m->deleteObjFile();
kamm@1007 936 else
kamm@1007 937 {
kamm@1007 938 if (global.params.doDocComments)
kamm@1007 939 m->gendocfile();
kamm@1007 940 }
tomas@989 941 }
kamm@1052 942
kamm@1052 943 // internal linking for singleobj
kamm@1052 944 if (singleObj && llvmModules.size() > 0)
kamm@1052 945 {
kamm@1052 946 Module* m = (Module*)modules.data[0];
kamm@1052 947 char* name = m->toChars();
kamm@1052 948 char* filename = m->objfile->name->str;
kamm@1052 949
benny@1535 950 llvm::Linker linker(name, name, context);
benny@1532 951
kamm@1052 952 std::string errormsg;
kamm@1052 953 for (int i = 0; i < llvmModules.size(); i++)
kamm@1052 954 {
kamm@1052 955 if(linker.LinkInModule(llvmModules[i], &errormsg))
fvbommel@1372 956 error("%s", errormsg.c_str());
kamm@1052 957 delete llvmModules[i];
kamm@1052 958 }
kamm@1052 959
kamm@1052 960 m->deleteObjFile();
kamm@1052 961 writeModule(linker.getModule(), filename);
kamm@1052 962 global.params.objfiles->push(filename);
kamm@1052 963 }
kamm@1052 964
tomas@989 965 backend_term();
tomas@989 966 if (global.errors)
kamm@1007 967 fatal();
tomas@989 968
tomas@989 969 if (!global.params.objfiles->dim)
tomas@989 970 {
kamm@1007 971 if (global.params.link)
kamm@1007 972 error("no object files to link");
tomas@989 973 }
tomas@989 974 else
tomas@989 975 {
kamm@1007 976 if (global.params.link)
kamm@1586 977 status = linkObjToExecutable(global.params.argv0);
tomas@989 978
kamm@1007 979 if (global.params.run)
tomas@989 980 {
kamm@1007 981 if (!status)
kamm@1007 982 {
fvbommel@1313 983 status = runExecutable();
tomas@989 984
kamm@1007 985 /* Delete .obj files and .exe file
kamm@1007 986 */
kamm@1007 987 for (int i = 0; i < modules.dim; i++)
kamm@1007 988 {
kamm@1007 989 m = (Module *)modules.data[i];
kamm@1007 990 m->deleteObjFile();
kamm@1007 991 }
kamm@1007 992 deleteExecutable();
kamm@1007 993 }
tomas@989 994 }
tomas@989 995 }
tomas@989 996
tomas@989 997 return status;
tomas@989 998 }