diff --git a/.travis.yml b/.travis.yml index 11e228aa1ea..6253dd4f0a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,11 +36,12 @@ addons: - llvm-3.7-dev install: - if [[ "${LLVM_CONFIG}" == *3\.[567]* ]]; then export CC="gcc-4.9"; export CXX="g++-4.9"; fi + - if [[ "${OPTS}" == *TEST_COVERAGE*ON* ]]; then pip install --user coveralls; fi env: - - LLVM_CONFIG="llvm-config-3.7" - - LLVM_CONFIG="llvm-config-3.6" OPTS="-DMULTILIB=ON" - - LLVM_CONFIG="llvm-config-3.5" OPTS="-DBUILD_SHARED_LIBS=ON" - - LLVM_CONFIG="llvm-config-3.4" OPTS="-DTEST_COVERAGE=ON" + - LLVM_CONFIG="llvm-config-3.7" OPTS="-DMULTILIB=ON" + - LLVM_CONFIG="llvm-config-3.6" OPTS="-DBUILD_SHARED_LIBS=ON" + - LLVM_CONFIG="llvm-config-3.5" OPTS="-DTEST_COVERAGE=ON" + - LLVM_CONFIG="llvm-config-3.4" - LLVM_CONFIG="llvm-config-3.3" - LLVM_CONFIG="llvm-config-3.2" - LLVM_CONFIG="llvm-config-3.1" diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f2d63df990..15ee4b60d05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -248,6 +248,7 @@ set(DRV_SRC driver/cl_options.cpp driver/codegenerator.cpp driver/configfile.cpp + driver/exe_path.cpp driver/targetmachine.cpp driver/toobj.cpp driver/tool.cpp @@ -260,6 +261,7 @@ set(DRV_HDR driver/cl_options.h driver/codegenerator.h driver/configfile.h + driver/exe_path.h driver/ldc-version.h driver/targetmachine.h driver/toobj.h @@ -498,7 +500,7 @@ endif() set_source_files_properties(driver/ldmd.cpp driver/response.cpp PROPERTIES COMPILE_FLAGS "${LDC_CXXFLAGS}" ) -add_executable(${LDMD_EXE} dmd2/root/man.c driver/ldmd.cpp driver/response.cpp) +add_executable(${LDMD_EXE} dmd2/root/man.c driver/exe_path.cpp driver/ldmd.cpp driver/response.cpp driver/exe_path.h) set_target_properties(${LDMD_EXE} PROPERTIES COMPILE_DEFINITIONS LDC_EXE_NAME="${LDC_EXE_NAME}" COMPILE_FLAGS "${LLVM_CXXFLAGS}" @@ -534,6 +536,10 @@ if(${BUILD_SHARED}) endif() install(FILES ${PROJECT_BINARY_DIR}/bin/${LDC_EXE}_install.conf DESTINATION ${CONF_INST_DIR} RENAME ${LDC_EXE}.conf) +if(MSVC) + install(DIRECTORY vcbuild/ DESTINATION ${CMAKE_INSTALL_PREFIX}/bin FILES_MATCHING PATTERN "*.bat") +endif() + if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") find_package(bash-completion QUIET) if(NOT BASH_COMPLETION_FOUND) diff --git a/appveyor.yml b/appveyor.yml index 7a998397b1d..41f89a0fa25 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -90,10 +90,6 @@ before_build: build_script: - cd c:\projects - # Config file templates: add a lib required in combination with VS 2015 - - ps: (gc ldc\ldc2.conf.in).replace('@ADDITIONAL_DEFAULT_LDC_SWITCHES@', ', "-Llegacy_stdio_definitions.lib"@ADDITIONAL_DEFAULT_LDC_SWITCHES@') | sc ldc\ldc2.conf.in - - ps: (gc ldc\ldc2_install.conf.in).replace('@ADDITIONAL_DEFAULT_LDC_SWITCHES@', ', "-Llegacy_stdio_definitions.lib"@ADDITIONAL_DEFAULT_LDC_SWITCHES@') | sc ldc\ldc2_install.conf.in - - ps: (gc ldc\ldc2_phobos.conf.in).replace('@ADDITIONAL_DEFAULT_LDC_SWITCHES@', ', "-Llegacy_stdio_definitions.lib"@ADDITIONAL_DEFAULT_LDC_SWITCHES@') | sc ldc\ldc2_phobos.conf.in # Generate build files for LDC - md ninja-ldc - cd ninja-ldc diff --git a/cmake/Modules/FindLLVM.cmake b/cmake/Modules/FindLLVM.cmake index 2ad80fe87ff..d7d528f0684 100644 --- a/cmake/Modules/FindLLVM.cmake +++ b/cmake/Modules/FindLLVM.cmake @@ -83,6 +83,10 @@ if ((WIN32 AND NOT(MINGW OR CYGWIN)) OR NOT LLVM_CONFIG) list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfodwarf" index) list(APPEND LLVM_FIND_COMPONENTS "debuginfo") endif() + if(${LLVM_VERSION_STRING} MATCHES "^3\\.[8-9][\\.0-9A-Za-z]*") + # Versions beginning with 3.8 do not support component ipa + list(REMOVE_ITEM LLVM_FIND_COMPONENTS "ipa" index) + endif() if(${LLVM_VERSION_STRING} MATCHES "^3\\.[0-4][\\.0-9A-Za-z]*") llvm_map_components_to_libraries(tmplibs ${LLVM_FIND_COMPONENTS}) @@ -163,6 +167,10 @@ else() list(REMOVE_ITEM LLVM_FIND_COMPONENTS "debuginfodwarf" index) list(APPEND LLVM_FIND_COMPONENTS "debuginfo") endif() + if(${LLVM_VERSION_STRING} MATCHES "^3\\.[8-9][\\.0-9A-Za-z]*") + # Versions beginning with 3.8 do not support component ipa + list(REMOVE_ITEM LLVM_FIND_COMPONENTS "ipa" index) + endif() llvm_set(LDFLAGS ldflags) if(NOT ${LLVM_VERSION_STRING} MATCHES "^3\\.[0-4][\\.0-9A-Za-z]*") diff --git a/driver/configfile.cpp b/driver/configfile.cpp index c0867f05e33..2f31816d25f 100644 --- a/driver/configfile.cpp +++ b/driver/configfile.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "driver/configfile.h" +#include "driver/exe_path.h" #include "mars.h" #include "libconfig.h" #include "llvm/Support/FileSystem.h" @@ -51,16 +52,6 @@ std::string getUserHomeDirectory() { } #endif -#if LDC_LLVM_VER >= 304 -static std::string getMainExecutable(const char *argv0, void *MainExecAddr) { - return sys::fs::getMainExecutable(argv0, MainExecAddr); -} -#else -static std::string getMainExecutable(const char *argv0, void *MainExecAddr) { - return llvm::sys::Path::GetMainExecutable(argv0, MainExecAddr).str(); -} -#endif - #if _WIN32 static bool ReadPathFromRegistry(llvm::SmallString<128> &p) { @@ -98,7 +89,7 @@ ConfigFile::~ConfigFile() } -bool ConfigFile::locate(llvm::SmallString<128> &p, const char* argv0, void* mainAddr, const char* filename) +bool ConfigFile::locate(llvm::SmallString<128>& p, const char* filename) { // temporary configuration @@ -111,9 +102,7 @@ bool ConfigFile::locate(llvm::SmallString<128> &p, const char* argv0, void* main } // try next to the executable - p = getMainExecutable(argv0, mainAddr); - sys::path::remove_filename(p); - sys::path::append(p, filename); + p = exe_path::prependBinDir(filename); if (sys::fs::exists(p.str())) return true; @@ -138,9 +127,7 @@ bool ConfigFile::locate(llvm::SmallString<128> &p, const char* argv0, void* main // try in etc relative to the executable: exe\..\etc // do not use .. in path because of security risks - p = getMainExecutable(argv0, mainAddr); - sys::path::remove_filename(p); - sys::path::remove_filename(p); + p = exe_path::getBaseDir(); if (!p.empty()) { sys::path::append(p, "etc"); @@ -190,10 +177,10 @@ bool ConfigFile::locate(llvm::SmallString<128> &p, const char* argv0, void* main return false; } -bool ConfigFile::read(const char* argv0, void* mainAddr, const char* filename) +bool ConfigFile::read(const char* filename) { llvm::SmallString<128> p; - if (!locate(p, argv0, mainAddr, filename)) + if (!locate(p, filename)) { // failed to find cfg, users still have the DFLAGS environment var std::cerr << "Error failed to locate the configuration file: " << filename << std::endl; @@ -228,7 +215,7 @@ bool ConfigFile::read(const char* argv0, void* mainAddr, const char* filename) { std::string binpathkey = "%%ldcbinarypath%%"; - std::string binpath = sys::path::parent_path(getMainExecutable(argv0, mainAddr)); + std::string binpath = exe_path::getBinDir(); int len = config_setting_length(sw); for (int i = 0; i < len; i++) diff --git a/driver/configfile.h b/driver/configfile.h index 43e3871048c..0cfe21656ae 100644 --- a/driver/configfile.h +++ b/driver/configfile.h @@ -29,7 +29,7 @@ class ConfigFile ConfigFile(); ~ConfigFile(); - bool read(const char* argv0, void* mainAddr, const char* filename); + bool read(const char* filename); s_iterator switches_begin() { return switches.begin(); } s_iterator switches_end() { return switches.end(); } @@ -37,7 +37,7 @@ class ConfigFile const std::string& path() { return pathstr; } private: - bool locate(llvm::SmallString<128> &path, const char* argv0, void* mainAddr, const char* filename); + bool locate(llvm::SmallString<128> &path, const char* filename); config_t* cfg; std::string pathstr; diff --git a/driver/exe_path.cpp b/driver/exe_path.cpp new file mode 100644 index 00000000000..aead45f0f65 --- /dev/null +++ b/driver/exe_path.cpp @@ -0,0 +1,56 @@ +//===-- exe_path.cpp ------------------------------------------------------===// +// +// LDC – the LLVM D compiler +// +// This file is distributed under the BSD-style LDC license. See the LICENSE +// file for details. +// +//===----------------------------------------------------------------------===// + +#include "exe_path.h" + +#include +#if LDC_LLVM_VER >= 304 +#include +#endif + +using std::string; +namespace path = llvm::sys::path; + +namespace { string exePath; } + +void exe_path::initialize(const char* arg0, void* mainAddress) +{ + assert(exePath.empty()); +#if LDC_LLVM_VER >= 304 + exePath = llvm::sys::fs::getMainExecutable(arg0, mainAddress); +#else + exePath = llvm::sys::Path::GetMainExecutable(arg0, mainAddress).str(); +#endif +} + +const string& exe_path::getExePath() +{ + assert(!exePath.empty()); + return exePath; +} + +string exe_path::getBinDir() +{ + assert(!exePath.empty()); + return path::parent_path(exePath); +} + +string exe_path::getBaseDir() +{ + string binDir = getBinDir(); + assert(!binDir.empty()); + return path::parent_path(binDir); +} + +string exe_path::prependBinDir(const char* suffix) +{ + llvm::SmallString<128> r(getBinDir()); + path::append(r, suffix); + return r.str(); +} diff --git a/driver/exe_path.h b/driver/exe_path.h new file mode 100644 index 00000000000..a6dff7cf0b3 --- /dev/null +++ b/driver/exe_path.h @@ -0,0 +1,30 @@ +//===-- driver/exe_path.h - Executable path management ----------*- C++ -*-===// +// +// LDC – the LLVM D compiler +// +// This file is distributed under the BSD-style LDC license. See the LICENSE +// file for details. +// +//===----------------------------------------------------------------------===// +// +// Stores the program's executable path and provides some helpers to generate +// derived paths. +// +//===----------------------------------------------------------------------===// + +#ifndef LDC_DRIVER_EXE_PATH_H +#define LDC_DRIVER_EXE_PATH_H + +#include + +namespace exe_path +{ + void initialize(const char* arg0, void* mainAddress); + + const std::string& getExePath(); // /bin/ldc2 + std::string getBinDir(); // /bin + std::string getBaseDir(); // + std::string prependBinDir(const char* suffix); // /bin/ +} + +#endif // LDC_DRIVER_EXE_PATH_H diff --git a/driver/ldmd.cpp b/driver/ldmd.cpp index 110f5a9dccf..023e9d77811 100644 --- a/driver/ldmd.cpp +++ b/driver/ldmd.cpp @@ -48,6 +48,7 @@ # error "Please define LDC_EXE_NAME to the name of the LDC executable to use." #endif +#include "driver/exe_path.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -94,58 +95,8 @@ error_code createUniqueFile(const Twine &Model, int &ResultFD, } #endif -#if LDC_LLVM_VER >= 304 -std::string getEXESuffix() { -#if _WIN32 - return "exe"; -#else - return llvm::StringRef(); -#endif -} -#else -std::string getEXESuffix() { - return ls::Path::GetEXESuffix().str(); -} -#endif - -#if LDC_LLVM_VER >= 304 -namespace llvm { -/// Prepend the path to the program being executed -/// to \p ExeName, given the value of argv[0] and the address of main() -/// itself. This allows us to find another LLVM tool if it is built in the same -/// directory. An empty string is returned on error; note that this function -/// just mainpulates the path and doesn't check for executability. -/// @brief Find a named executable. -static std::string prependMainExecutablePath(const std::string &ExeName, - const char *Argv0, void *MainAddr) { - // Check the directory that the calling program is in. We can do - // this if ProgramPath contains at least one / character, indicating that it - // is a relative path to the executable itself. - llvm::SmallString<128> Result(ls::fs::getMainExecutable(Argv0, MainAddr)); - sys::path::remove_filename(Result); - - if (!Result.empty()) { - sys::path::append(Result, ExeName); - - // Do not use path::append here, this is not a path component before which - // to insert the path seperator. - Result.append(getEXESuffix()); - } - - return Result.str(); -} -} -#else -namespace llvm { -static std::string prependMainExecutablePath(const std::string &ExeName, - const char *Argv0, void *MainAddr) { - return llvm::PrependMainExecutablePath(ExeName, Argv0, MainAddr).str(); -} -} -#endif - // We reuse DMD's response file parsing routine for maximum compatibilty - it -// handles quotes in a very peciuliar way. +// handles quotes in a very peculiar way. int response_expand(size_t *pargc, char ***pargv); void browse(const char *url); @@ -1090,10 +1041,9 @@ size_t maxCommandLineLen() * nothing was found. Search paths: 1. Directory where this binary resides. * 2. System PATH. */ -std::string locateBinary(std::string exeName, const char* argv0) +std::string locateBinary(std::string exeName) { - std::string path = llvm::prependMainExecutablePath(exeName, - argv0, (void*)&locateBinary); + std::string path = exe_path::prependBinDir(exeName.c_str()); if (ls::fs::can_execute(path)) return path; #if LDC_LLVM_VER >= 306 @@ -1130,7 +1080,13 @@ static size_t addStrlen(size_t acc, const char* str) int main(int argc, char *argv[]) { - std::string ldcPath = locateBinary(LDC_EXE_NAME, argv[0]); + exe_path::initialize(argv[0], reinterpret_cast(main)); + + std::string ldcExeName = LDC_EXE_NAME; +#ifdef _WIN32 + ldcExeName += ".exe"; +#endif + std::string ldcPath = locateBinary(ldcExeName); if (ldcPath.empty()) { error("Could not locate " LDC_EXE_NAME " executable."); diff --git a/driver/linker.cpp b/driver/linker.cpp index 664a688e751..5d153eaa3e0 100644 --- a/driver/linker.cpp +++ b/driver/linker.cpp @@ -12,6 +12,7 @@ #include "module.h" #include "root.h" #include "driver/cl_options.h" +#include "driver/exe_path.h" #include "driver/tool.h" #include "gen/llvm.h" #include "gen/logger.h" @@ -277,42 +278,58 @@ static int linkObjToBinaryGcc(bool sharedLib) ////////////////////////////////////////////////////////////////////////////// +static bool setupMSVCEnvironment(std::string& tool, std::vector& args) +{ + // if the VSINSTALLDIR environment variable is NOT set, + // the environment is most likely not set up properly + bool setup = !getenv("VSINSTALLDIR"); + + if (setup) + { + // use a helper batch file to let MSVC set up the environment and + // then invoke the tool + args.push_back(tool); // tool is first arg for batch file + tool = exe_path::prependBinDir( + global.params.targetTriple.isArch64Bit() ? "amd64.bat" : "x86.bat"); + } + else + tool = getProgram(tool.c_str()); + + return setup; +} + +////////////////////////////////////////////////////////////////////////////// + static int linkObjToBinaryWin(bool sharedLib) { Logger::println("*** Linking executable ***"); - // find link.exe for linking - std::string tool(getLink()); + std::string tool = "link.exe"; // build arguments std::vector args; + const bool setupMSVC = setupMSVCEnvironment(tool, args); + args.push_back("/NOLOGO"); // specify that the image will contain a table of safe exception handlers (32bit only) if (!global.params.is64bit) args.push_back("/SAFESEH"); - // mark executable to be compatible with Windows Data Execution Prevention feature - args.push_back("/NXCOMPAT"); - - // use address space layout randomization (ASLR) feature - args.push_back("/DYNAMICBASE"); - - // because of a LLVM bug - // most of the bug is fixed in LLVM 3.4 -#if LDC_LLVM_VER < 304 + // because of a LLVM bug, see LDC issue 442 if (global.params.symdebug) args.push_back("/LARGEADDRESSAWARE:NO"); else -#endif - args.push_back("/LARGEADDRESSAWARE"); + args.push_back("/LARGEADDRESSAWARE"); // output debug information if (global.params.symdebug) - { args.push_back("/DEBUG"); - } + + // enable Link-time Code Generation (aka. whole program optimization) + if (global.params.optimize) + args.push_back("/LTCG"); // remove dead code and fold identical COMDATs if (opts::disableLinkerStripDead) @@ -356,7 +373,7 @@ static int linkObjToBinaryWin(bool sharedLib) // additional linker switches for (unsigned i = 0; i < global.params.linkswitches->dim; i++) { - std::string str(static_cast(global.params.linkswitches->data[i])); + std::string str = global.params.linkswitches->data[i]; if (str.length() > 2) { // rewrite common -L and -l switches @@ -385,6 +402,7 @@ static int linkObjToBinaryWin(bool sharedLib) Logger::println("Linking with: "); std::vector::const_iterator I = args.begin(), E = args.end(); + if (setupMSVC) ++I; // skip link.exe, the first arg for the batch file Stream logstr = Logger::cout(); for (; I != E; ++I) if (!(*I).empty()) @@ -424,11 +442,14 @@ void createStaticLibrary() #endif // find archiver - std::string tool(isTargetWindows ? getLib() : getArchiver()); + std::string tool(isTargetWindows ? "lib.exe" : getArchiver()); // build arguments std::vector args; + if (isTargetWindows) + setupMSVCEnvironment(tool, args); + // ask ar to create a new library if (!isTargetWindows) args.push_back("rcs"); @@ -437,6 +458,10 @@ void createStaticLibrary() if (isTargetWindows) args.push_back("/NOLOGO"); + // enable Link-time Code Generation (aka. whole program optimization) + if (isTargetWindows && global.params.optimize) + args.push_back("/LTCG"); + // output filename std::string libName; if (global.params.objname) diff --git a/driver/linker.h b/driver/linker.h index 7b503e7f25b..27d2979910e 100644 --- a/driver/linker.h +++ b/driver/linker.h @@ -17,7 +17,6 @@ /** * Link an executable only from object files. - * @param argv0 the argv[0] value as passed to main * @return 0 on success. */ int linkObjToBinary(bool sharedLib); diff --git a/driver/main.cpp b/driver/main.cpp index 93039eb25b4..6c8545e4fed 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -23,6 +23,7 @@ #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" @@ -103,18 +104,6 @@ static cl::opt linkDebugLib("link-debuglib", cl::desc("Link with libraries specified in -debuglib, not -defaultlib"), cl::ZeroOrMore); -#if LDC_LLVM_VER < 304 -namespace llvm { -namespace sys { -namespace fs { -static std::string getMainExecutable(const char *argv0, void *MainExecAddr) { - return llvm::sys::Path::GetMainExecutable(argv0, MainExecAddr).str(); -} -} -} -} -#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); @@ -263,16 +252,7 @@ int main(int argc, char **argv); /// /// Returns a list of source file names. static void parseCommandLine(int argc, char **argv, Strings &sourceFiles, bool &helpOnly) { -#if _WIN32 - char buf[MAX_PATH]; - GetModuleFileName(NULL, buf, MAX_PATH); - const char* argv0 = &buf[0]; - // FIXME: We cannot set params.argv0 here, as we would escape a stack - // reference, but it is unused anyway. - global.params.argv0 = NULL; -#else - const char* argv0 = global.params.argv0 = argv[0]; -#endif + global.params.argv0 = exe_path::getExePath().data(); // Set some default values. global.params.useSwitchError = 1; @@ -292,7 +272,7 @@ static void parseCommandLine(int argc, char **argv, Strings &sourceFiles, bool & ConfigFile cfg_file; // just ignore errors for now, they are still printed - cfg_file.read(argv0, (void*)main, "ldc2.conf"); + cfg_file.read("ldc2.conf"); final_args.insert(final_args.end(), cfg_file.switches_begin(), cfg_file.switches_end()); final_args.insert(final_args.end(), &argv[1], &argv[argc]); @@ -316,7 +296,7 @@ static void parseCommandLine(int argc, char **argv, Strings &sourceFiles, bool & // - version number // - used config file if (global.params.verbose) { - fprintf(global.stdmsg, "binary %s\n", llvm::sys::fs::getMainExecutable(argv0, (void*)main).c_str()); + 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()) @@ -940,6 +920,8 @@ int main(int argc, char **argv) // stack trace on signals llvm::sys::PrintStackTraceOnErrorSignal(); + exe_path::initialize(argv[0], reinterpret_cast(main)); + global.init(); global.version = ldc::dmd_version; global.ldc_version = ldc::ldc_version; diff --git a/gen/arrays.cpp b/gen/arrays.cpp index f5156451900..cba8ee54af5 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -363,15 +363,15 @@ static void DtoSetArray(DValue* array, LLValue* dim, LLValue* ptr) ////////////////////////////////////////////////////////////////////////////////////////// -LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit) +LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit, Type* targetType) { - IF_LOG Logger::println("DtoConstArrayInitializer: %s | %s", arrinit->toChars(), arrinit->type->toChars()); + IF_LOG Logger::println("DtoConstArrayInitializer: %s | %s", arrinit->toChars(), targetType->toChars()); LOG_SCOPE; assert(arrinit->value.dim == arrinit->index.dim); // get base array type - Type* arrty = arrinit->type->toBasetype(); + Type* arrty = targetType->toBasetype(); size_t arrlen = arrinit->dim; // for statis arrays, dmd does not include any trailing default diff --git a/gen/arrays.h b/gen/arrays.h index fcc73ad3daf..b5a5aa9547a 100644 --- a/gen/arrays.h +++ b/gen/arrays.h @@ -30,8 +30,11 @@ llvm::StructType* DtoArrayType(Type* arrayTy); llvm::StructType* DtoArrayType(LLType* elemTy); llvm::ArrayType* DtoStaticArrayType(Type* sarrayTy); -LLType* DtoConstArrayInitializerType(ArrayInitializer* arrinit); -LLConstant* DtoConstArrayInitializer(ArrayInitializer* si); +/// Creates a (global) constant with the element data for the given arary +/// initializer. targetType is explicit because the frontend sometimes emits +/// ArrayInitializers for vectors typed as static arrays. +LLConstant* DtoConstArrayInitializer(ArrayInitializer* si, Type* targetType); + LLConstant* DtoConstSlice(LLConstant* dim, LLConstant* ptr, Type *type = 0); /// Returns whether the array literal can be evaluated to a (LLVM) constant. diff --git a/gen/dibuilder.cpp b/gen/dibuilder.cpp index db9edeedb58..9e7685c8476 100644 --- a/gen/dibuilder.cpp +++ b/gen/dibuilder.cpp @@ -81,16 +81,17 @@ void ldc::DIBuilder::Declare(const Loc &loc, llvm::Value *var, ldc::DILocalVaria #endif ) { + unsigned charnum = (loc.linnum ? loc.charnum : 0); llvm::Instruction *instr = DBuilder.insertDeclare(var, divar, #if LDC_LLVM_VER >= 306 diexpr, #endif #if LDC_LLVM_VER >= 307 - llvm::DebugLoc::get(loc.linnum, loc.charnum, GetCurrentScope()), + llvm::DebugLoc::get(loc.linnum, charnum, GetCurrentScope()), #endif IR->scopebb()); #if LDC_LLVM_VER < 307 - instr->setDebugLoc(llvm::DebugLoc::get(loc.linnum, loc.charnum, GetCurrentScope())); + instr->setDebugLoc(llvm::DebugLoc::get(loc.linnum, charnum, GetCurrentScope())); #endif } @@ -810,7 +811,7 @@ void ldc::DIBuilder::EmitBlockStart(Loc& loc) GetCurrentScope(), // scope CreateFile(loc), // file loc.linnum, // line - loc.charnum // column + loc.linnum ? loc.charnum : 0 // column #if LDC_LLVM_VER == 305 , 0 // DWARF path discriminator value #endif @@ -849,9 +850,10 @@ void ldc::DIBuilder::EmitStopPoint(Loc& loc) ) return; - Logger::println("D to dwarf stoppoint at line %u, column %u", loc.linnum, loc.charnum); + unsigned charnum = (loc.linnum ? loc.charnum : 0); + Logger::println("D to dwarf stoppoint at line %u, column %u", loc.linnum, charnum); LOG_SCOPE; - IR->ir->SetCurrentDebugLocation(llvm::DebugLoc::get(loc.linnum, loc.charnum, GetCurrentScope())); + IR->ir->SetCurrentDebugLocation(llvm::DebugLoc::get(loc.linnum, charnum, GetCurrentScope())); } void ldc::DIBuilder::EmitValue(llvm::Value *val, VarDeclaration *vd) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index ebe0d97cd06..a4f0ab39446 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1178,7 +1178,7 @@ LLConstant* DtoConstInitializer(Loc& loc, Type* type, Initializer* init) else if (ArrayInitializer* ai = init->isArrayInitializer()) { Logger::println("const array initializer"); - _init = DtoConstArrayInitializer(ai); + _init = DtoConstArrayInitializer(ai, type); } else if (init->isVoidInitializer()) { diff --git a/gen/nested.cpp b/gen/nested.cpp index c594018fd80..9689dc4151d 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -535,7 +535,7 @@ void DtoCreateNestedContext(FuncDeclaration* fd) { LLSmallVector addr; #endif gIR->DBuilder.OpOffset(addr, frameType, irLocal->nestedIndex); - gIR->DBuilder.EmitLocalVariable(frame, vd, 0, false, addr); + gIR->DBuilder.EmitLocalVariable(gep, vd, 0, false, addr); } } } diff --git a/gen/programs.cpp b/gen/programs.cpp index fc77ba9f98a..cc16efda06e 100644 --- a/gen/programs.cpp +++ b/gen/programs.cpp @@ -24,17 +24,7 @@ static cl::opt ar("ar", cl::Hidden, cl::ZeroOrMore); -static cl::opt mslink("ms-link", - cl::desc("LINK to use for linking on Windows"), - cl::Hidden, - cl::ZeroOrMore); - -static cl::opt mslib("ms-lib", - cl::desc("Library Manager to use on Windows"), - cl::Hidden, - cl::ZeroOrMore); - -inline static std::string findProgramByName(const std::string& name) +static std::string findProgramByName(const std::string& name) { #if LDC_LLVM_VER >= 306 llvm::ErrorOr res = llvm::sys::findProgramByName(name); @@ -46,12 +36,12 @@ inline static std::string findProgramByName(const std::string& name) #endif } -static std::string getProgram(const char *name, const cl::opt &opt, const char *envVar = 0) +static std::string getProgram(const char* name, const cl::opt* opt, const char* envVar = NULL) { std::string path; const char *prog = NULL; - if (opt.getNumOccurrences() > 0 && opt.length() > 0 && (prog = opt.c_str())) + if (opt && opt->getNumOccurrences() > 0 && opt->length() > 0 && (prog = opt->c_str())) path = findProgramByName(prog); if (path.empty() && envVar && (prog = getenv(envVar))) @@ -68,27 +58,22 @@ static std::string getProgram(const char *name, const cl::opt &opt, return path; } +std::string getProgram(const char* name, const char* envVar) +{ + return getProgram(name, NULL, envVar); +} + std::string getGcc() { #if defined(__FreeBSD__) && __FreeBSD__ >= 10 // Default compiler on FreeBSD 10 is clang return getProgram("clang", gcc, "CC"); #else - return getProgram("gcc", gcc, "CC"); + return getProgram("gcc", &gcc, "CC"); #endif } std::string getArchiver() { - return getProgram("ar", ar); -} - -std::string getLink() -{ - return getProgram("link.exe", mslink); -} - -std::string getLib() -{ - return getProgram("lib.exe", mslib); + return getProgram("ar", &ar); } diff --git a/gen/programs.h b/gen/programs.h index 02829e575a1..24c3b7353e7 100644 --- a/gen/programs.h +++ b/gen/programs.h @@ -16,11 +16,9 @@ #include +std::string getProgram(const char* name, const char* envVar = 0); + std::string getGcc(); std::string getArchiver(); -// For Windows with MS tool chain -std::string getLink(); -std::string getLib(); - #endif diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 771ae63871c..46bbaedcc05 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -191,8 +191,10 @@ endif() # # Create configuration files. # -if(MSVC) - set(ADDITIONAL_DEFAULT_LDC_SWITCHES ",\n \"-L/LARGEADDRESSAWARE:NO\"") + +# Add a lib required by VS 2015+ when building LDC with VS 2015+. +if(MSVC AND (MSVC_VERSION GREATER 1800)) + set(ADDITIONAL_DEFAULT_LDC_SWITCHES ",\n \"-Llegacy_stdio_definitions.lib\"") endif() # Add extra paths on Linux and disable linker arch mismatch warnings (like @@ -245,7 +247,7 @@ foreach(variable ${variables}) endforeach() # Compiles the given D module into an object file, and if enabled, a bitcode -# file. The ouput is written to a path based on output_dir. The paths of the +# file. The output is written to a path based on output_dir. The paths of the # output files are appended to outlist_o and outlist_bc, respectively. macro(dc input_d d_flags output_dir output_suffix outlist_o outlist_bc) file(RELATIVE_PATH output ${output_dir} ${input_d}) diff --git a/vcbuild/amd64.bat b/vcbuild/amd64.bat new file mode 100644 index 00000000000..39f4c727531 --- /dev/null +++ b/vcbuild/amd64.bat @@ -0,0 +1,6 @@ +@echo off +setlocal EnableDelayedExpansion +call "%~dp0msvcEnv.bat" amd64 +:: Invoke the actual command, represented by all args +%* +endlocal diff --git a/vcbuild/msvcEnv.bat b/vcbuild/msvcEnv.bat new file mode 100644 index 00000000000..be1aae7f73a --- /dev/null +++ b/vcbuild/msvcEnv.bat @@ -0,0 +1,26 @@ +@echo off + +:: Environment already set up? +if not "%VSINSTALLDIR%"=="" goto :eof + +:: Clear an existing LDC_VSDIR environment variable if the directory doesn't exist +if not "%LDC_VSDIR%"=="" if not exist "%LDC_VSDIR%" set LDC_VSDIR= + +:: Try to detect the latest VS installation directory if LDC_VSDIR is not set +if not "%LDC_VSDIR%"=="" goto setup +for /F "tokens=1,2*" %%i in ('reg query HKCU\Software\Microsoft\VisualStudio\12.0_Config /v ShellFolder 2^> nul') do set LDC_VSDIR=%%k +for /F "tokens=1,2*" %%i in ('reg query HKCU\Software\Microsoft\VisualStudio\14.0_Config /v ShellFolder 2^> nul') do set LDC_VSDIR=%%k +if "%LDC_VSDIR%"=="" ( + echo WARNING: no Visual Studio installation detected + goto :eof +) + +:: Let MSVC set up environment variables +:setup +echo Using Visual Studio: %LDC_VSDIR% +if not exist "%LDC_VSDIR%VC\vcvarsall.bat" ( + echo WARNING: could not find VC\vcvarsall.bat + goto :eof +) +:: Forward the first arg to the MS batch file +call "%LDC_VSDIR%VC\vcvarsall.bat" %1 diff --git a/vcbuild/x86.bat b/vcbuild/x86.bat new file mode 100644 index 00000000000..b5960b25ec0 --- /dev/null +++ b/vcbuild/x86.bat @@ -0,0 +1,6 @@ +@echo off +setlocal EnableDelayedExpansion +call "%~dp0msvcEnv.bat" x86 +:: Invoke the actual command, represented by all args +%* +endlocal