mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-29 14:40:40 +03:00

DMD does too, and the front-end's FileName class expects backslashes in some places. Due to the import and lib directories in the ldc2.conf file being specified with forward slashes, most paths produced by LDC used both slashes, e.g., `C:/LDC/ldc/runtime/druntime/src\object.d`, which looks unprofessional, is problematic for the front-end and leads to differences wrt. DMD when outputting module dependencies etc.
1176 lines
38 KiB
C++
1176 lines
38 KiB
C++
//===-- main.cpp --------------------------------------------------------===//
|
||
//
|
||
// LDC – the LLVM D compiler
|
||
//
|
||
// This file is distributed under the BSD-style LDC license. See the LICENSE
|
||
// file for details.
|
||
//
|
||
//===----------------------------------------------------------------------===//
|
||
|
||
#include "module.h"
|
||
#include "errors.h"
|
||
#include "id.h"
|
||
#include "hdrgen.h"
|
||
#include "json.h"
|
||
#include "mars.h"
|
||
#include "mtype.h"
|
||
#include "identifier.h"
|
||
#include "rmem.h"
|
||
#include "root.h"
|
||
#include "scope.h"
|
||
#include "ddmd/target.h"
|
||
#include "driver/cl_options.h"
|
||
#include "driver/codegenerator.h"
|
||
#include "driver/configfile.h"
|
||
#include "driver/exe_path.h"
|
||
#include "driver/ldc-version.h"
|
||
#include "driver/linker.h"
|
||
#include "driver/targetmachine.h"
|
||
#include "gen/cl_helpers.h"
|
||
#include "gen/irstate.h"
|
||
#include "gen/linkage.h"
|
||
#include "gen/llvm.h"
|
||
#include "gen/llvmhelpers.h"
|
||
#include "gen/logger.h"
|
||
#include "gen/metadata.h"
|
||
#include "gen/modules.h"
|
||
#include "gen/objcgen.h"
|
||
#include "gen/optimizer.h"
|
||
#include "gen/passes/Passes.h"
|
||
#include "gen/runtime.h"
|
||
#include "gen/abi.h"
|
||
#include "llvm/InitializePasses.h"
|
||
#include "llvm/LinkAllPasses.h"
|
||
#include "llvm/Support/FileSystem.h"
|
||
#include "llvm/Support/Host.h"
|
||
#include "llvm/Support/ManagedStatic.h"
|
||
#include "llvm/Support/Path.h"
|
||
#if LDC_LLVM_VER >= 308
|
||
#include "llvm/Support/StringSaver.h"
|
||
#endif
|
||
#include "llvm/Support/TargetRegistry.h"
|
||
#include "llvm/Support/TargetSelect.h"
|
||
#include "llvm/Target/TargetMachine.h"
|
||
#if LDC_LLVM_VER >= 306
|
||
#include "llvm/Target/TargetSubtargetInfo.h"
|
||
#endif
|
||
#include "llvm/LinkAllIR.h"
|
||
#include "llvm/IR/LLVMContext.h"
|
||
#include <assert.h>
|
||
#include <limits.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#if _WIN32
|
||
#include <windows.h>
|
||
#endif
|
||
|
||
// Needs Type already declared.
|
||
#include "cond.h"
|
||
|
||
// From druntime/src/core/runtime.d.
|
||
extern "C" {
|
||
int rt_init();
|
||
}
|
||
|
||
// In ddmd/doc.d
|
||
void gendocfile(Module *m);
|
||
|
||
using namespace opts;
|
||
|
||
extern void getenv_setargv(const char *envvar, int *pargc, char ***pargv);
|
||
|
||
static cl::opt<bool>
|
||
noDefaultLib("nodefaultlib",
|
||
cl::desc("Don't add a default library for linking implicitly"),
|
||
cl::ZeroOrMore, cl::Hidden);
|
||
|
||
static StringsAdapter impPathsStore("I", global.params.imppath);
|
||
static cl::list<std::string, StringsAdapter>
|
||
importPaths("I", cl::desc("Where to look for imports"),
|
||
cl::value_desc("path"), cl::location(impPathsStore),
|
||
cl::Prefix);
|
||
|
||
static cl::opt<std::string>
|
||
defaultLib("defaultlib",
|
||
cl::desc("Default libraries to link with (overrides previous)"),
|
||
cl::value_desc("lib1,lib2,..."), cl::ZeroOrMore);
|
||
|
||
static cl::opt<std::string> debugLib(
|
||
"debuglib",
|
||
cl::desc("Debug versions of default libraries (overrides previous)"),
|
||
cl::value_desc("lib1,lib2,..."), cl::ZeroOrMore);
|
||
|
||
static cl::opt<bool> linkDebugLib(
|
||
"link-debuglib",
|
||
cl::desc("Link with libraries specified in -debuglib, not -defaultlib"),
|
||
cl::ZeroOrMore);
|
||
|
||
#if LDC_LLVM_VER >= 309
|
||
static inline llvm::Optional<llvm::Reloc::Model> getRelocModel() {
|
||
if (mRelocModel.getNumOccurrences()) {
|
||
llvm::Reloc::Model R = mRelocModel;
|
||
return R;
|
||
}
|
||
return llvm::None;
|
||
}
|
||
#else
|
||
static inline llvm::Reloc::Model getRelocModel() { return mRelocModel; }
|
||
#endif
|
||
|
||
void printVersion() {
|
||
printf("LDC - the LLVM D compiler (%s):\n", global.ldc_version);
|
||
printf(" based on DMD %s and LLVM %s\n", global.version,
|
||
global.llvm_version);
|
||
printf(" built with %s\n", ldc::built_with_Dcompiler_version);
|
||
#if defined(__has_feature)
|
||
#if __has_feature(address_sanitizer)
|
||
printf(" compiled with address sanitizer enabled\n");
|
||
#endif
|
||
#endif
|
||
printf(" Default target: %s\n", llvm::sys::getDefaultTargetTriple().c_str());
|
||
std::string CPU = llvm::sys::getHostCPUName();
|
||
if (CPU == "generic") {
|
||
CPU = "(unknown)";
|
||
}
|
||
printf(" Host CPU: %s\n", CPU.c_str());
|
||
printf(" http://dlang.org - http://wiki.dlang.org/LDC\n");
|
||
printf("\n");
|
||
|
||
// Without explicitly flushing here, only the target list is visible when
|
||
// redirecting stdout to a file.
|
||
fflush(stdout);
|
||
|
||
llvm::TargetRegistry::printRegisteredTargetsForVersion();
|
||
exit(EXIT_SUCCESS);
|
||
}
|
||
|
||
namespace {
|
||
|
||
// Helper function to handle -d-debug=* and -d-version=*
|
||
void processVersions(std::vector<std::string> &list, const char *type,
|
||
void (*setLevel)(unsigned),
|
||
void (*addIdent)(const char *)) {
|
||
for (const auto &i : list) {
|
||
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(Loc(), "Invalid %s level: %s", type, i.c_str());
|
||
} else {
|
||
setLevel(static_cast<unsigned>(level));
|
||
}
|
||
} else {
|
||
char *cstr = mem.xstrdup(value);
|
||
if (Identifier::isValidIdentifier(cstr)) {
|
||
addIdent(cstr);
|
||
continue;
|
||
} else {
|
||
error(Loc(), "Invalid %s identifier or level: '%s'", type, i.c_str());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Helper function to handle -transition=*
|
||
void processTransitions(std::vector<std::string> &list) {
|
||
for (const auto &i : list) {
|
||
if (i == "?") {
|
||
printf("Language changes listed by -transition=id:\n");
|
||
printf(" = all list information on all language changes\n");
|
||
printf(" = checkimports give deprecation messages about 10378 "
|
||
"anomalies\n");
|
||
printf(
|
||
" = complex,14488 list all usages of complex or imaginary types\n");
|
||
printf(" = field,3449 list all non - mutable fields which occupy an "
|
||
"object instance\n");
|
||
printf(" = import,10378 revert to single phase name lookup\n");
|
||
printf(" = tls list all variables going into thread local "
|
||
"storage\n");
|
||
exit(EXIT_SUCCESS);
|
||
} else if (i == "all") {
|
||
global.params.vtls = true;
|
||
global.params.vfield = true;
|
||
global.params.vcomplex = true;
|
||
global.params.bug10378 = true; // not set in DMD
|
||
global.params.check10378 = true; // not set in DMD
|
||
} else if (i == "checkimports") {
|
||
global.params.check10378 = true;
|
||
} else if (i == "complex" || i == "14488") {
|
||
global.params.vcomplex = true;
|
||
} else if (i == "field" || i == "3449") {
|
||
global.params.vfield = true;
|
||
} else if (i == "import" || i == "10378") {
|
||
global.params.bug10378 = true;
|
||
} else if (i == "tls") {
|
||
global.params.vtls = true;
|
||
} else {
|
||
error(Loc(), "Invalid transition %s", i.c_str());
|
||
}
|
||
}
|
||
}
|
||
|
||
char *dupPathString(const std::string &src) {
|
||
char *r = mem.xstrdup(src.c_str());
|
||
#if _WIN32
|
||
std::replace(r, r + src.length(), '/', '\\');
|
||
#endif
|
||
return r;
|
||
}
|
||
|
||
// Helper function to handle -of, -od, etc.
|
||
void initFromPathString(const char *&dest, const cl::opt<std::string> &src) {
|
||
dest = nullptr;
|
||
if (src.getNumOccurrences() != 0) {
|
||
if (src.empty()) {
|
||
error(Loc(), "Expected argument to '-%s'", src.ArgStr);
|
||
}
|
||
dest = dupPathString(src);
|
||
}
|
||
}
|
||
|
||
void hide(llvm::StringMap<cl::Option *> &map, const char *name) {
|
||
// Check if option exists first for resilience against LLVM changes
|
||
// between versions.
|
||
if (map.count(name)) {
|
||
map[name]->setHiddenFlag(cl::Hidden);
|
||
}
|
||
}
|
||
|
||
#if LDC_LLVM_VER >= 307
|
||
void rename(llvm::StringMap<cl::Option *> &map, const char *from,
|
||
const char *to) {
|
||
auto i = map.find(from);
|
||
if (i != map.end()) {
|
||
cl::Option *opt = i->getValue();
|
||
map.erase(i);
|
||
opt->setArgStr(to);
|
||
map[to] = opt;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/// Removes command line options exposed from within LLVM that are unlikely
|
||
/// to be useful for end users from the -help output.
|
||
void hideLLVMOptions() {
|
||
#if LDC_LLVM_VER >= 307
|
||
llvm::StringMap<cl::Option *> &map = cl::getRegisteredOptions();
|
||
#else
|
||
llvm::StringMap<cl::Option *> map;
|
||
cl::getRegisteredOptions(map);
|
||
#endif
|
||
hide(map, "bounds-checking-single-trap");
|
||
hide(map, "disable-debug-info-verifier");
|
||
hide(map, "disable-objc-arc-checkforcfghazards");
|
||
hide(map, "disable-spill-fusing");
|
||
hide(map, "cppfname");
|
||
hide(map, "cppfor");
|
||
hide(map, "cppgen");
|
||
hide(map, "enable-correct-eh-support");
|
||
hide(map, "enable-load-pre");
|
||
hide(map, "enable-misched");
|
||
hide(map, "enable-objc-arc-annotations");
|
||
hide(map, "enable-objc-arc-opts");
|
||
hide(map, "enable-scoped-noalias");
|
||
hide(map, "enable-tbaa");
|
||
hide(map, "exhaustive-register-search");
|
||
hide(map, "fatal-assembler-warnings");
|
||
hide(map, "internalize-public-api-file");
|
||
hide(map, "internalize-public-api-list");
|
||
hide(map, "join-liveintervals");
|
||
hide(map, "limit-float-precision");
|
||
hide(map, "mc-x86-disable-arith-relaxation");
|
||
hide(map, "mips16-constant-islands");
|
||
hide(map, "mips16-hard-float");
|
||
hide(map, "mlsm");
|
||
hide(map, "mno-ldc1-sdc1");
|
||
hide(map, "nvptx-sched4reg");
|
||
hide(map, "no-discriminators");
|
||
hide(map, "objc-arc-annotation-target-identifier"), hide(map, "pre-RA-sched");
|
||
hide(map, "print-after-all");
|
||
hide(map, "print-before-all");
|
||
hide(map, "print-machineinstrs");
|
||
hide(map, "profile-estimator-loop-weight");
|
||
hide(map, "profile-estimator-loop-weight");
|
||
hide(map, "profile-file");
|
||
hide(map, "profile-info-file");
|
||
hide(map, "profile-verifier-noassert");
|
||
hide(map, "regalloc");
|
||
hide(map, "rewrite-map-file");
|
||
hide(map, "rng-seed");
|
||
hide(map, "sample-profile-max-propagate-iterations");
|
||
hide(map, "shrink-wrap");
|
||
hide(map, "spiller");
|
||
hide(map, "stackmap-version");
|
||
hide(map, "stats");
|
||
hide(map, "strip-debug");
|
||
hide(map, "struct-path-tbaa");
|
||
hide(map, "time-passes");
|
||
hide(map, "unit-at-a-time");
|
||
hide(map, "verify-debug-info");
|
||
hide(map, "verify-dom-info");
|
||
hide(map, "verify-loop-info");
|
||
hide(map, "verify-regalloc");
|
||
hide(map, "verify-region-info");
|
||
hide(map, "verify-scev");
|
||
hide(map, "x86-early-ifcvt");
|
||
hide(map, "x86-use-vzeroupper");
|
||
hide(map, "x86-recip-refinement-steps");
|
||
|
||
// We enable -fdata-sections/-ffunction-sections by default where it makes
|
||
// sense for reducing code size, so hide them to avoid confusion.
|
||
//
|
||
// We need our own switch as these two are defined by LLVM and linked to
|
||
// static TargetMachine members, but the default we want to use depends
|
||
// on the target triple (and thus we do not know it until after the command
|
||
// line has been parsed).
|
||
hide(map, "fdata-sections");
|
||
hide(map, "ffunction-sections");
|
||
|
||
#if LDC_LLVM_VER >= 307
|
||
// LLVM 3.7 introduces compiling as shared library. The result
|
||
// is a clash in the command line options.
|
||
rename(map, "color", "llvm-color");
|
||
hide(map, "llvm-color");
|
||
opts::CreateColorOption();
|
||
#endif
|
||
}
|
||
|
||
const char *tryGetExplicitConfFile(int argc, char **argv) {
|
||
// begin at the back => use latest -conf= specification
|
||
for (int i = argc - 1; i >= 1; --i) {
|
||
if (strncmp(argv[i], "-conf=", 6) == 0) {
|
||
return argv[i] + 6;
|
||
}
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
llvm::Triple tryGetExplicitTriple(int argc, char **argv) {
|
||
// most combinations of flags are illegal, this mimicks command line
|
||
// behaviour for legal ones only
|
||
llvm::Triple triple(llvm::sys::getDefaultTargetTriple());
|
||
const char *mtriple = nullptr;
|
||
const char *march = nullptr;
|
||
for (int i = 1; i < argc; ++i) {
|
||
if (sizeof(void *) != 4 && strcmp(argv[i], "-m32") == 0) {
|
||
triple = triple.get32BitArchVariant();
|
||
if (triple.getArch() == llvm::Triple::ArchType::x86)
|
||
triple.setArchName("i686"); // instead of i386
|
||
return triple;
|
||
}
|
||
|
||
if (sizeof(void *) != 8 && strcmp(argv[i], "-m64") == 0)
|
||
return triple.get64BitArchVariant();
|
||
|
||
if (strncmp(argv[i], "-mtriple=", 9) == 0)
|
||
mtriple = argv[i] + 9;
|
||
else if (strncmp(argv[i], "-march=", 7) == 0)
|
||
march = argv[i] + 7;
|
||
}
|
||
if (mtriple)
|
||
triple = llvm::Triple(llvm::Triple::normalize(mtriple));
|
||
if (march) {
|
||
std::string errorMsg; // ignore error, will show up later anyway
|
||
lookupTarget(march, triple, errorMsg); // modifies triple
|
||
}
|
||
return triple;
|
||
}
|
||
|
||
/// Parses switches from the command line, any response files and the global
|
||
/// config file and sets up global.params accordingly.
|
||
///
|
||
/// Returns a list of source file names.
|
||
void parseCommandLine(int argc, char **argv, Strings &sourceFiles,
|
||
bool &helpOnly) {
|
||
global.params.argv0 = exe_path::getExePath().data();
|
||
|
||
// Set some default values.
|
||
global.params.useSwitchError = 1;
|
||
global.params.color = isConsoleColorSupported();
|
||
|
||
global.params.linkswitches = new Strings();
|
||
global.params.libfiles = new Strings();
|
||
global.params.objfiles = new Strings();
|
||
global.params.ddocfiles = new Strings();
|
||
global.params.bitcodeFiles = new Strings();
|
||
|
||
global.params.moduleDeps = nullptr;
|
||
global.params.moduleDepsFile = nullptr;
|
||
|
||
// Build combined list of command line arguments.
|
||
llvm::SmallVector<const char *, 32> final_args;
|
||
final_args.push_back(argv[0]);
|
||
|
||
ConfigFile cfg_file;
|
||
const char *explicitConfFile = tryGetExplicitConfFile(argc, argv);
|
||
std::string cfg_triple = tryGetExplicitTriple(argc, argv).getTriple();
|
||
// just ignore errors for now, they are still printed
|
||
cfg_file.read(explicitConfFile, cfg_triple.c_str());
|
||
final_args.insert(final_args.end(), cfg_file.switches_begin(),
|
||
cfg_file.switches_end());
|
||
|
||
final_args.insert(final_args.end(), &argv[1], &argv[argc]);
|
||
|
||
cl::SetVersionPrinter(&printVersion);
|
||
hideLLVMOptions();
|
||
|
||
// pre-expand response files (LLVM's ParseCommandLineOptions() always uses
|
||
// TokenizeGNUCommandLine which eats backslashes)
|
||
#if LDC_LLVM_VER >= 308
|
||
llvm::BumpPtrAllocator A;
|
||
llvm::StringSaver Saver(A);
|
||
cl::ExpandResponseFiles(Saver,
|
||
#ifdef _WIN32
|
||
cl::TokenizeWindowsCommandLine
|
||
#else
|
||
cl::TokenizeGNUCommandLine
|
||
#endif
|
||
,
|
||
final_args);
|
||
#endif
|
||
|
||
cl::ParseCommandLineOptions(final_args.size(),
|
||
const_cast<char **>(final_args.data()),
|
||
"LDC - the LLVM D compiler\n");
|
||
|
||
helpOnly = mCPU == "help" ||
|
||
(std::find(mAttrs.begin(), mAttrs.end(), "help") != mAttrs.end());
|
||
|
||
// Print some information if -v was passed
|
||
// - path to compiler binary
|
||
// - version number
|
||
// - used config file
|
||
if (global.params.verbose) {
|
||
fprintf(global.stdmsg, "binary %s\n", exe_path::getExePath().c_str());
|
||
fprintf(global.stdmsg, "version %s (DMD %s, LLVM %s)\n",
|
||
global.ldc_version, global.version, global.llvm_version);
|
||
const std::string &path = cfg_file.path();
|
||
if (!path.empty()) {
|
||
fprintf(global.stdmsg, "config %s\n", path.c_str());
|
||
}
|
||
}
|
||
|
||
// Negated options
|
||
global.params.link = !compileOnly;
|
||
global.params.obj = !dontWriteObj;
|
||
global.params.useInlineAsm = !noAsm;
|
||
|
||
// String options: std::string --> char*
|
||
initFromPathString(global.params.objname, objectFile);
|
||
initFromPathString(global.params.objdir, objectDir);
|
||
|
||
initFromPathString(global.params.docdir, ddocDir);
|
||
initFromPathString(global.params.docname, ddocFile);
|
||
global.params.doDocComments |= global.params.docdir || global.params.docname;
|
||
|
||
initFromPathString(global.params.jsonfilename, jsonFile);
|
||
if (global.params.jsonfilename) {
|
||
global.params.doJsonGeneration = true;
|
||
}
|
||
|
||
initFromPathString(global.params.hdrdir, hdrDir);
|
||
initFromPathString(global.params.hdrname, hdrFile);
|
||
global.params.doHdrGeneration |=
|
||
global.params.hdrdir || global.params.hdrname;
|
||
|
||
if (moduleDeps.getNumOccurrences() != 0) {
|
||
global.params.moduleDeps = new OutBuffer;
|
||
if (!moduleDeps.empty())
|
||
global.params.moduleDepsFile = dupPathString(moduleDeps);
|
||
}
|
||
|
||
#if _WIN32
|
||
const auto toWinPaths = [](Strings *paths) {
|
||
if (!paths)
|
||
return;
|
||
for (unsigned i = 0; i < paths->dim; ++i)
|
||
(*paths)[i] = dupPathString((*paths)[i]);
|
||
};
|
||
toWinPaths(global.params.imppath);
|
||
toWinPaths(global.params.fileImppath);
|
||
#endif
|
||
|
||
// PGO options
|
||
#if LDC_WITH_PGO
|
||
if (genfileInstrProf.getNumOccurrences() > 0) {
|
||
global.params.genInstrProf = true;
|
||
if (genfileInstrProf.empty()) {
|
||
#if LDC_LLVM_VER >= 309
|
||
// profile-rt provides a default filename by itself
|
||
global.params.datafileInstrProf = nullptr;
|
||
#else
|
||
global.params.datafileInstrProf = "default.profraw";
|
||
#endif
|
||
} else {
|
||
initFromPathString(global.params.datafileInstrProf, genfileInstrProf);
|
||
}
|
||
} else {
|
||
global.params.genInstrProf = false;
|
||
// If we don't have to generate instrumentation, we could be given a
|
||
// profdata file:
|
||
initFromPathString(global.params.datafileInstrProf, usefileInstrProf);
|
||
}
|
||
#endif
|
||
|
||
processVersions(debugArgs, "debug", DebugCondition::setGlobalLevel,
|
||
DebugCondition::addGlobalIdent);
|
||
processVersions(versions, "version", VersionCondition::setGlobalLevel,
|
||
VersionCondition::addGlobalIdent);
|
||
|
||
processTransitions(transitions);
|
||
|
||
global.params.output_o =
|
||
(opts::output_o == cl::BOU_UNSET &&
|
||
!(opts::output_bc || opts::output_ll || opts::output_s))
|
||
? 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;
|
||
|
||
global.params.cov = (global.params.covPercent <= 100);
|
||
|
||
templateLinkage = opts::linkonceTemplates ? LLGlobalValue::LinkOnceODRLinkage
|
||
: LLGlobalValue::WeakODRLinkage;
|
||
|
||
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()) {
|
||
char const *name = runargs[0].c_str();
|
||
char const *ext = FileName::ext(name);
|
||
if (ext && FileName::equals(ext, "d") == 0 &&
|
||
FileName::equals(ext, "di") == 0) {
|
||
error(Loc(), "-run must be followed by a source file, not '%s'", name);
|
||
}
|
||
|
||
sourceFiles.push(mem.xstrdup(name));
|
||
runargs.erase(runargs.begin());
|
||
} else {
|
||
global.params.run = false;
|
||
error(Loc(), "Expected at least one argument to '-run'\n");
|
||
}
|
||
}
|
||
|
||
sourceFiles.reserve(fileList.size());
|
||
for (const auto &file : fileList) {
|
||
if (!file.empty()) {
|
||
char *copy = dupPathString(file);
|
||
sourceFiles.push(copy);
|
||
}
|
||
}
|
||
|
||
if (noDefaultLib) {
|
||
deprecation(
|
||
Loc(),
|
||
"-nodefaultlib is deprecated, as "
|
||
"-defaultlib/-debuglib now override the existing list instead of "
|
||
"appending to it. Please use the latter instead.");
|
||
} else {
|
||
// Parse comma-separated default library list.
|
||
std::stringstream libNames(linkDebugLib ? debugLib : defaultLib);
|
||
while (libNames.good()) {
|
||
std::string lib;
|
||
std::getline(libNames, lib, ',');
|
||
if (lib.empty()) {
|
||
continue;
|
||
}
|
||
|
||
char *arg = static_cast<char *>(mem.xmalloc(lib.size() + 3));
|
||
strcpy(arg, "-l");
|
||
strcpy(arg + 2, lib.c_str());
|
||
global.params.linkswitches->push(arg);
|
||
}
|
||
}
|
||
|
||
if (global.params.useUnitTests) {
|
||
global.params.useAssert = 1;
|
||
}
|
||
|
||
// -release downgrades default bounds checking level to BOUNDSCHECKsafeonly
|
||
// (only for safe functions).
|
||
global.params.useArrayBounds =
|
||
opts::nonSafeBoundsChecks ? BOUNDSCHECKon : BOUNDSCHECKsafeonly;
|
||
if (opts::boundsCheck != BOUNDSCHECKdefault) {
|
||
global.params.useArrayBounds = opts::boundsCheck;
|
||
}
|
||
|
||
// LDC output determination
|
||
|
||
// if we don't link, autodetect target from extension
|
||
if (!global.params.link && !global.params.lib && global.params.objname) {
|
||
const char *ext = FileName::ext(global.params.objname);
|
||
bool autofound = false;
|
||
if (!ext) {
|
||
// keep things as they are
|
||
} else if (strcmp(ext, global.ll_ext) == 0) {
|
||
global.params.output_ll = OUTPUTFLAGset;
|
||
autofound = true;
|
||
} else if (strcmp(ext, global.bc_ext) == 0) {
|
||
global.params.output_bc = OUTPUTFLAGset;
|
||
autofound = true;
|
||
} else if (strcmp(ext, global.s_ext) == 0) {
|
||
global.params.output_s = OUTPUTFLAGset;
|
||
autofound = true;
|
||
} else if (strcmp(ext, global.obj_ext) == 0 || strcmp(ext, "obj") == 0) {
|
||
// global.obj_ext hasn't been corrected yet for MSVC targets as we first
|
||
// need the command line to figure out the target...
|
||
// so treat both 'o' and 'obj' extensions as object files
|
||
global.params.output_o = OUTPUTFLAGset;
|
||
autofound = true;
|
||
} else {
|
||
// append dot, so forceExt won't change existing name even if it contains
|
||
// dots
|
||
size_t len = strlen(global.params.objname);
|
||
char *s = static_cast<char *>(mem.xmalloc(len + 1 + 1));
|
||
memcpy(s, global.params.objname, len);
|
||
s[len] = '.';
|
||
s[len + 1] = 0;
|
||
global.params.objname = s;
|
||
}
|
||
if (autofound && global.params.output_o == OUTPUTFLAGdefault) {
|
||
global.params.output_o = OUTPUTFLAGno;
|
||
}
|
||
}
|
||
|
||
// only link if possible
|
||
if (!global.params.obj || !global.params.output_o || global.params.lib) {
|
||
global.params.link = 0;
|
||
}
|
||
|
||
if (global.params.lib && global.params.dll) {
|
||
error(Loc(), "-lib and -shared switches cannot be used together");
|
||
}
|
||
|
||
#if LDC_LLVM_VER >= 309
|
||
if (global.params.dll && !mRelocModel.getNumOccurrences()) {
|
||
#else
|
||
if (global.params.dll && mRelocModel == llvm::Reloc::Default) {
|
||
#endif
|
||
mRelocModel = llvm::Reloc::PIC_;
|
||
}
|
||
|
||
if (global.params.link) {
|
||
global.params.exefile = global.params.objname;
|
||
global.params.oneobj = true;
|
||
if (global.params.objname) {
|
||
/* Use this to name the one object file with the same
|
||
* name as the exe file.
|
||
*/
|
||
global.params.objname =
|
||
FileName::forceExt(global.params.objname, global.obj_ext);
|
||
/* If output directory is given, use that path rather than
|
||
* the exe file path.
|
||
*/
|
||
if (global.params.objdir) {
|
||
const char *name = FileName::name(global.params.objname);
|
||
global.params.objname = FileName::combine(global.params.objdir, name);
|
||
}
|
||
}
|
||
} else if (global.params.run) {
|
||
error(Loc(), "flags conflict with -run");
|
||
fatal();
|
||
} else if (global.params.lib) {
|
||
global.params.libname = global.params.objname;
|
||
global.params.objname = nullptr;
|
||
} else {
|
||
if (global.params.objname && sourceFiles.dim > 1) {
|
||
global.params.oneobj = true;
|
||
// error("multiple source files, but only one .obj name");
|
||
// fatal();
|
||
}
|
||
}
|
||
|
||
if (soname.getNumOccurrences() > 0 && !global.params.dll) {
|
||
error(Loc(), "-soname can be used only when building a shared library");
|
||
}
|
||
}
|
||
|
||
void initializePasses() {
|
||
using namespace llvm;
|
||
// Initialize passes
|
||
PassRegistry &Registry = *PassRegistry::getPassRegistry();
|
||
initializeCore(Registry);
|
||
initializeTransformUtils(Registry);
|
||
initializeScalarOpts(Registry);
|
||
initializeObjCARCOpts(Registry);
|
||
initializeVectorization(Registry);
|
||
initializeInstCombine(Registry);
|
||
initializeIPO(Registry);
|
||
initializeInstrumentation(Registry);
|
||
initializeAnalysis(Registry);
|
||
initializeCodeGen(Registry);
|
||
#if LDC_LLVM_VER >= 309
|
||
initializeGlobalISel(Registry);
|
||
#endif
|
||
initializeTarget(Registry);
|
||
|
||
// Initialize passes not included above
|
||
#if LDC_LLVM_VER < 306
|
||
initializeDebugIRPass(Registry);
|
||
#endif
|
||
#if LDC_LLVM_VER < 308
|
||
initializeIPA(Registry);
|
||
#endif
|
||
#if LDC_LLVM_VER >= 400
|
||
initializeRewriteSymbolsLegacyPassPass(Registry);
|
||
#elif LDC_LLVM_VER >= 306
|
||
initializeRewriteSymbolsPass(Registry);
|
||
#endif
|
||
#if LDC_LLVM_VER >= 307
|
||
initializeSjLjEHPreparePass(Registry);
|
||
#endif
|
||
}
|
||
|
||
/// Register the MIPS ABI.
|
||
static void registerMipsABI() {
|
||
switch (getMipsABI()) {
|
||
case MipsABI::EABI:
|
||
VersionCondition::addPredefinedGlobalIdent("MIPS_EABI");
|
||
break;
|
||
case MipsABI::O32:
|
||
VersionCondition::addPredefinedGlobalIdent("MIPS_O32");
|
||
break;
|
||
case MipsABI::N32:
|
||
VersionCondition::addPredefinedGlobalIdent("MIPS_N32");
|
||
break;
|
||
case MipsABI::N64:
|
||
VersionCondition::addPredefinedGlobalIdent("MIPS_N64");
|
||
break;
|
||
case MipsABI::Unknown:
|
||
break;
|
||
}
|
||
}
|
||
|
||
/// Register the float ABI.
|
||
/// Also defines D_HardFloat or D_SoftFloat depending if FPU should be used
|
||
void registerPredefinedFloatABI(const char *soft, const char *hard,
|
||
const char *softfp = nullptr) {
|
||
// Use target floating point unit instead of s/w float routines
|
||
#if LDC_LLVM_VER >= 307
|
||
// FIXME: This is a semantic change!
|
||
bool useFPU = gTargetMachine->Options.FloatABIType == llvm::FloatABI::Hard;
|
||
#else
|
||
bool useFPU = !gTargetMachine->Options.UseSoftFloat;
|
||
#endif
|
||
VersionCondition::addPredefinedGlobalIdent(useFPU ? "D_HardFloat"
|
||
: "D_SoftFloat");
|
||
|
||
if (gTargetMachine->Options.FloatABIType == llvm::FloatABI::Soft) {
|
||
VersionCondition::addPredefinedGlobalIdent(useFPU && softfp ? softfp
|
||
: soft);
|
||
} else if (gTargetMachine->Options.FloatABIType == llvm::FloatABI::Hard) {
|
||
assert(useFPU && "Should be using the FPU if using float-abi=hard");
|
||
VersionCondition::addPredefinedGlobalIdent(hard);
|
||
} else {
|
||
assert(0 && "FloatABIType neither Soft or Hard");
|
||
}
|
||
}
|
||
|
||
/// Registers the predefined versions specific to the current target triple
|
||
/// and other target specific options with VersionCondition.
|
||
void registerPredefinedTargetVersions() {
|
||
switch (global.params.targetTriple->getArch()) {
|
||
case llvm::Triple::x86:
|
||
VersionCondition::addPredefinedGlobalIdent("X86");
|
||
if (global.params.useInlineAsm) {
|
||
VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86");
|
||
}
|
||
VersionCondition::addPredefinedGlobalIdent("D_HardFloat");
|
||
break;
|
||
case llvm::Triple::x86_64:
|
||
VersionCondition::addPredefinedGlobalIdent("X86_64");
|
||
if (global.params.useInlineAsm) {
|
||
VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86_64");
|
||
}
|
||
VersionCondition::addPredefinedGlobalIdent("D_HardFloat");
|
||
break;
|
||
case llvm::Triple::ppc:
|
||
VersionCondition::addPredefinedGlobalIdent("PPC");
|
||
registerPredefinedFloatABI("PPC_SoftFloat", "PPC_HardFloat");
|
||
break;
|
||
case llvm::Triple::ppc64:
|
||
case llvm::Triple::ppc64le:
|
||
VersionCondition::addPredefinedGlobalIdent("PPC64");
|
||
registerPredefinedFloatABI("PPC_SoftFloat", "PPC_HardFloat");
|
||
if (global.params.targetTriple->getOS() == llvm::Triple::Linux) {
|
||
VersionCondition::addPredefinedGlobalIdent(
|
||
global.params.targetTriple->getArch() == llvm::Triple::ppc64
|
||
? "ELFv1"
|
||
: "ELFv2");
|
||
}
|
||
break;
|
||
case llvm::Triple::arm:
|
||
case llvm::Triple::armeb:
|
||
VersionCondition::addPredefinedGlobalIdent("ARM");
|
||
registerPredefinedFloatABI("ARM_SoftFloat", "ARM_HardFloat", "ARM_SoftFP");
|
||
break;
|
||
case llvm::Triple::thumb:
|
||
VersionCondition::addPredefinedGlobalIdent("ARM");
|
||
VersionCondition::addPredefinedGlobalIdent(
|
||
"Thumb"); // For backwards compatibility.
|
||
VersionCondition::addPredefinedGlobalIdent("ARM_Thumb");
|
||
registerPredefinedFloatABI("ARM_SoftFloat", "ARM_HardFloat", "ARM_SoftFP");
|
||
break;
|
||
#if LDC_LLVM_VER == 305
|
||
case llvm::Triple::arm64:
|
||
case llvm::Triple::arm64_be:
|
||
#endif
|
||
case llvm::Triple::aarch64:
|
||
case llvm::Triple::aarch64_be:
|
||
VersionCondition::addPredefinedGlobalIdent("AArch64");
|
||
registerPredefinedFloatABI("ARM_SoftFloat", "ARM_HardFloat", "ARM_SoftFP");
|
||
break;
|
||
case llvm::Triple::mips:
|
||
case llvm::Triple::mipsel:
|
||
VersionCondition::addPredefinedGlobalIdent("MIPS");
|
||
registerPredefinedFloatABI("MIPS_SoftFloat", "MIPS_HardFloat");
|
||
registerMipsABI();
|
||
break;
|
||
case llvm::Triple::mips64:
|
||
case llvm::Triple::mips64el:
|
||
VersionCondition::addPredefinedGlobalIdent("MIPS64");
|
||
registerPredefinedFloatABI("MIPS_SoftFloat", "MIPS_HardFloat");
|
||
registerMipsABI();
|
||
break;
|
||
case llvm::Triple::sparc:
|
||
// FIXME: Detect SPARC v8+ (SPARC_V8Plus).
|
||
VersionCondition::addPredefinedGlobalIdent("SPARC");
|
||
registerPredefinedFloatABI("SPARC_SoftFloat", "SPARC_HardFloat");
|
||
break;
|
||
case llvm::Triple::sparcv9:
|
||
VersionCondition::addPredefinedGlobalIdent("SPARC64");
|
||
registerPredefinedFloatABI("SPARC_SoftFloat", "SPARC_HardFloat");
|
||
break;
|
||
case llvm::Triple::nvptx:
|
||
VersionCondition::addPredefinedGlobalIdent("NVPTX");
|
||
VersionCondition::addPredefinedGlobalIdent("D_HardFloat");
|
||
break;
|
||
case llvm::Triple::nvptx64:
|
||
VersionCondition::addPredefinedGlobalIdent("NVPTX64");
|
||
VersionCondition::addPredefinedGlobalIdent("D_HardFloat");
|
||
break;
|
||
case llvm::Triple::systemz:
|
||
VersionCondition::addPredefinedGlobalIdent("SystemZ");
|
||
VersionCondition::addPredefinedGlobalIdent(
|
||
"S390X"); // For backwards compatibility.
|
||
VersionCondition::addPredefinedGlobalIdent("D_HardFloat");
|
||
break;
|
||
default:
|
||
error(Loc(), "invalid cpu architecture specified: %s",
|
||
global.params.targetTriple->getArchName().str().c_str());
|
||
fatal();
|
||
}
|
||
|
||
// endianness
|
||
if (gDataLayout->isLittleEndian()) {
|
||
VersionCondition::addPredefinedGlobalIdent("LittleEndian");
|
||
} else {
|
||
VersionCondition::addPredefinedGlobalIdent("BigEndian");
|
||
}
|
||
|
||
// a generic 64bit version
|
||
if (global.params.isLP64) {
|
||
VersionCondition::addPredefinedGlobalIdent("D_LP64");
|
||
}
|
||
|
||
if (gTargetMachine->getRelocationModel() == llvm::Reloc::PIC_) {
|
||
VersionCondition::addPredefinedGlobalIdent("D_PIC");
|
||
}
|
||
|
||
// parse the OS out of the target triple
|
||
// see http://gcc.gnu.org/install/specific.html for details
|
||
// also llvm's different SubTargets have useful information
|
||
switch (global.params.targetTriple->getOS()) {
|
||
case llvm::Triple::Win32:
|
||
VersionCondition::addPredefinedGlobalIdent("Windows");
|
||
VersionCondition::addPredefinedGlobalIdent(global.params.is64bit ? "Win64"
|
||
: "Win32");
|
||
if (global.params.targetTriple->isKnownWindowsMSVCEnvironment()) {
|
||
VersionCondition::addPredefinedGlobalIdent("CRuntime_Microsoft");
|
||
}
|
||
if (global.params.targetTriple->isWindowsGNUEnvironment()) {
|
||
VersionCondition::addPredefinedGlobalIdent(
|
||
"mingw32"); // For backwards compatibility.
|
||
VersionCondition::addPredefinedGlobalIdent("MinGW");
|
||
}
|
||
if (global.params.targetTriple->isWindowsCygwinEnvironment()) {
|
||
error(Loc(), "Cygwin is not yet supported");
|
||
fatal();
|
||
VersionCondition::addPredefinedGlobalIdent("Cygwin");
|
||
}
|
||
break;
|
||
case llvm::Triple::Linux:
|
||
VersionCondition::addPredefinedGlobalIdent("linux");
|
||
VersionCondition::addPredefinedGlobalIdent("Posix");
|
||
if (global.params.targetTriple->getEnvironment() == llvm::Triple::Android) {
|
||
VersionCondition::addPredefinedGlobalIdent("Android");
|
||
VersionCondition::addPredefinedGlobalIdent("CRuntime_Bionic");
|
||
} else {
|
||
VersionCondition::addPredefinedGlobalIdent("CRuntime_Glibc");
|
||
}
|
||
break;
|
||
case llvm::Triple::Haiku:
|
||
VersionCondition::addPredefinedGlobalIdent("Haiku");
|
||
VersionCondition::addPredefinedGlobalIdent("Posix");
|
||
break;
|
||
case llvm::Triple::Darwin:
|
||
case llvm::Triple::MacOSX:
|
||
VersionCondition::addPredefinedGlobalIdent("OSX");
|
||
VersionCondition::addPredefinedGlobalIdent(
|
||
"darwin"); // For backwards compatibility.
|
||
VersionCondition::addPredefinedGlobalIdent("Posix");
|
||
break;
|
||
case llvm::Triple::FreeBSD:
|
||
VersionCondition::addPredefinedGlobalIdent("FreeBSD");
|
||
VersionCondition::addPredefinedGlobalIdent("Posix");
|
||
break;
|
||
case llvm::Triple::Solaris:
|
||
VersionCondition::addPredefinedGlobalIdent("Solaris");
|
||
VersionCondition::addPredefinedGlobalIdent("Posix");
|
||
break;
|
||
case llvm::Triple::DragonFly:
|
||
VersionCondition::addPredefinedGlobalIdent("DragonFlyBSD");
|
||
VersionCondition::addPredefinedGlobalIdent("Posix");
|
||
break;
|
||
case llvm::Triple::NetBSD:
|
||
VersionCondition::addPredefinedGlobalIdent("NetBSD");
|
||
VersionCondition::addPredefinedGlobalIdent("Posix");
|
||
break;
|
||
case llvm::Triple::OpenBSD:
|
||
VersionCondition::addPredefinedGlobalIdent("OpenBSD");
|
||
VersionCondition::addPredefinedGlobalIdent("Posix");
|
||
break;
|
||
case llvm::Triple::AIX:
|
||
VersionCondition::addPredefinedGlobalIdent("AIX");
|
||
VersionCondition::addPredefinedGlobalIdent("Posix");
|
||
break;
|
||
default:
|
||
switch (global.params.targetTriple->getEnvironment()) {
|
||
case llvm::Triple::Android:
|
||
VersionCondition::addPredefinedGlobalIdent("Android");
|
||
break;
|
||
default:
|
||
error(Loc(), "target '%s' is not yet supported",
|
||
global.params.targetTriple->str().c_str());
|
||
fatal();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Registers all predefined D version identifiers for the current
|
||
/// configuration with VersionCondition.
|
||
void registerPredefinedVersions() {
|
||
VersionCondition::addPredefinedGlobalIdent("LDC");
|
||
VersionCondition::addPredefinedGlobalIdent("all");
|
||
VersionCondition::addPredefinedGlobalIdent("D_Version2");
|
||
|
||
if (global.params.doDocComments) {
|
||
VersionCondition::addPredefinedGlobalIdent("D_Ddoc");
|
||
}
|
||
|
||
if (global.params.cov) {
|
||
VersionCondition::addPredefinedGlobalIdent("D_Coverage");
|
||
}
|
||
|
||
if (global.params.useUnitTests) {
|
||
VersionCondition::addPredefinedGlobalIdent("unittest");
|
||
}
|
||
|
||
if (global.params.useAssert) {
|
||
VersionCondition::addPredefinedGlobalIdent("assert");
|
||
}
|
||
|
||
if (global.params.useArrayBounds == BOUNDSCHECKoff) {
|
||
VersionCondition::addPredefinedGlobalIdent("D_NoBoundsChecks");
|
||
}
|
||
|
||
registerPredefinedTargetVersions();
|
||
|
||
if (global.params.hasObjectiveC) {
|
||
VersionCondition::addPredefinedGlobalIdent("D_ObjectiveC");
|
||
}
|
||
|
||
// Pass sanitizer arguments to linker. Requires clang.
|
||
if (opts::sanitize == opts::AddressSanitizer) {
|
||
VersionCondition::addPredefinedGlobalIdent("LDC_AddressSanitizer");
|
||
}
|
||
|
||
if (opts::sanitize == opts::MemorySanitizer) {
|
||
VersionCondition::addPredefinedGlobalIdent("LDC_MemorySanitizer");
|
||
}
|
||
|
||
if (opts::sanitize == opts::ThreadSanitizer) {
|
||
VersionCondition::addPredefinedGlobalIdent("LDC_ThreadSanitizer");
|
||
}
|
||
|
||
// Expose LLVM version to runtime
|
||
#define STR(x) #x
|
||
#define XSTR(x) STR(x)
|
||
VersionCondition::addPredefinedGlobalIdent("LDC_LLVM_" XSTR(LDC_LLVM_VER));
|
||
#undef XSTR
|
||
#undef STR
|
||
}
|
||
|
||
/// Dump all predefined version identifiers.
|
||
void dumpPredefinedVersions() {
|
||
if (global.params.verbose && global.params.versionids) {
|
||
fprintf(global.stdmsg, "predefs ");
|
||
int col = 10;
|
||
for (auto id : *global.params.versionids) {
|
||
int len = strlen(id) + 1;
|
||
if (col + len > 80) {
|
||
col = 10;
|
||
fprintf(global.stdmsg, "\n ");
|
||
}
|
||
col += len;
|
||
fprintf(global.stdmsg, " %s", id);
|
||
}
|
||
fprintf(global.stdmsg, "\n");
|
||
}
|
||
}
|
||
|
||
} // anonymous namespace
|
||
|
||
int cppmain(int argc, char **argv) {
|
||
#if LDC_LLVM_VER >= 309
|
||
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
|
||
#else
|
||
llvm::sys::PrintStackTraceOnErrorSignal();
|
||
#endif
|
||
|
||
exe_path::initialize(argv[0]);
|
||
|
||
global._init();
|
||
global.version = ldc::dmd_version;
|
||
global.ldc_version = ldc::ldc_version;
|
||
global.llvm_version = ldc::llvm_version;
|
||
|
||
// Initialize LLVM before parsing the command line so that --version shows
|
||
// registered targets.
|
||
llvm::InitializeAllTargetInfos();
|
||
llvm::InitializeAllTargets();
|
||
llvm::InitializeAllTargetMCs();
|
||
llvm::InitializeAllAsmPrinters();
|
||
llvm::InitializeAllAsmParsers();
|
||
|
||
initializePasses();
|
||
|
||
bool helpOnly;
|
||
Strings files;
|
||
parseCommandLine(argc, argv, files, helpOnly);
|
||
|
||
if (files.dim == 0 && !helpOnly) {
|
||
cl::PrintHelpMessage();
|
||
return EXIT_FAILURE;
|
||
}
|
||
|
||
if (global.errors) {
|
||
fatal();
|
||
}
|
||
|
||
// Set up the TargetMachine.
|
||
ExplicitBitness::Type bitness = ExplicitBitness::None;
|
||
if ((m32bits || m64bits) && (!mArch.empty() || !mTargetTriple.empty())) {
|
||
error(Loc(), "-m32 and -m64 switches cannot be used together with -march "
|
||
"and -mtriple switches");
|
||
}
|
||
|
||
if (m32bits) {
|
||
bitness = ExplicitBitness::M32;
|
||
}
|
||
if (m64bits) {
|
||
if (bitness != ExplicitBitness::None) {
|
||
error(Loc(), "cannot use both -m32 and -m64 options");
|
||
}
|
||
bitness = ExplicitBitness::M64;
|
||
}
|
||
|
||
if (global.errors) {
|
||
fatal();
|
||
}
|
||
|
||
gTargetMachine = createTargetMachine(
|
||
mTargetTriple, mArch, mCPU, mAttrs, bitness, mFloatABI, getRelocModel(),
|
||
mCodeModel, codeGenOptLevel(), disableFpElim, disableLinkerStripDead);
|
||
|
||
#if LDC_LLVM_VER >= 308
|
||
static llvm::DataLayout DL = gTargetMachine->createDataLayout();
|
||
gDataLayout = &DL;
|
||
#elif LDC_LLVM_VER >= 307
|
||
gDataLayout = gTargetMachine->getDataLayout();
|
||
#elif LDC_LLVM_VER >= 306
|
||
gDataLayout = gTargetMachine->getSubtargetImpl()->getDataLayout();
|
||
#else
|
||
gDataLayout = gTargetMachine->getDataLayout();
|
||
#endif
|
||
|
||
{
|
||
llvm::Triple *triple = new llvm::Triple(gTargetMachine->getTargetTriple());
|
||
global.params.targetTriple = triple;
|
||
global.params.isWindows = triple->isOSWindows();
|
||
global.params.isLP64 = gDataLayout->getPointerSizeInBits() == 64;
|
||
global.params.is64bit = triple->isArch64Bit();
|
||
global.params.hasObjectiveC = objc_isSupported(*triple);
|
||
// mscoff enables slightly different handling of interface functions
|
||
// in the front end
|
||
global.params.mscoff = triple->isKnownWindowsMSVCEnvironment();
|
||
if (global.params.mscoff)
|
||
global.obj_ext = "obj";
|
||
}
|
||
|
||
// allocate the target abi
|
||
gABI = TargetABI::getTarget();
|
||
|
||
// Set predefined version identifiers.
|
||
registerPredefinedVersions();
|
||
dumpPredefinedVersions();
|
||
|
||
if (global.params.targetTriple->isOSWindows()) {
|
||
global.dll_ext = "dll";
|
||
global.lib_ext =
|
||
(global.params.targetTriple->isWindowsMSVCEnvironment() ? "lib" : "a");
|
||
} else {
|
||
global.dll_ext = "so";
|
||
global.lib_ext = "a";
|
||
}
|
||
|
||
Strings libmodules;
|
||
return mars_mainBody(files, libmodules);
|
||
}
|
||
|
||
void codegenModules(Modules &modules) {
|
||
// Generate one or more object/IR/bitcode files.
|
||
if (global.params.obj && !modules.empty()) {
|
||
ldc::CodeGenerator cg(getGlobalContext(), global.params.oneobj);
|
||
|
||
// When inlining is enabled, we are calling semantic3 on function
|
||
// declarations, which may _add_ members to the first module in the modules
|
||
// array. These added functions must be codegenned, because these functions
|
||
// may be "alwaysinline" and linker problems arise otherwise with templates
|
||
// that have __FILE__ as parameters (which must be `pragma(inline, true);`)
|
||
// Therefore, codegen is done in reverse order with members[0] last, to make
|
||
// sure these functions (added to members[0] by members[x>0]) are
|
||
// codegenned.
|
||
for (d_size_t i = modules.dim; i-- > 0;) {
|
||
Module *const m = modules[i];
|
||
if (global.params.verbose)
|
||
fprintf(global.stdmsg, "code %s\n", m->toChars());
|
||
|
||
cg.emit(m);
|
||
|
||
if (global.errors)
|
||
fatal();
|
||
}
|
||
}
|
||
|
||
freeRuntime();
|
||
llvm::llvm_shutdown();
|
||
}
|