//===-- ldmd.cpp - Drop-in DMD replacement wrapper for LDC ----------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license, except for the // command line handling code, which originated from DMD. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// // // Wrapper allowing use of LDC as drop-in replacement for DMD. // // Most command-line options are passed through to LDC; some with different // names or semantics need to be translated. // // DMD also reads switches from the DFLAGS enviroment variable, if present. This // is contrary to what C compilers do, where CFLAGS is usually handled by the // build system. // //===----------------------------------------------------------------------===// #ifndef LDC_EXE_NAME #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" #include "llvm/Support/Program.h" #include "llvm/Support/SystemUtils.h" #include "llvm/Support/raw_ostream.h" #if _WIN32 #include "Windows.h" #else #include #endif #include #include #include #include #include #include #include #include #ifdef HAVE_SC_ARG_MAX #include #endif namespace ls = llvm::sys; // We reuse DMD's response file parsing routine for maximum compatibility - it // handles quotes in a very peculiar way. int response_expand(size_t *pargc, char ***pargv); // in ddmd/root/man.d void browse(const char *url); /** * Prints a formatted error message to stderr and exits the program. */ void error(const char *fmt, ...) { va_list argp; va_start(argp, fmt); fprintf(stderr, "Error: "); vfprintf(stderr, fmt, argp); fprintf(stderr, "\n"); exit(EXIT_FAILURE); va_end(argp); } /** * Prints a formatted warning message to stderr. */ void warning(const char *fmt, ...) { va_list argp; va_start(argp, fmt); fprintf(stderr, "Warning: "); vfprintf(stderr, fmt, argp); fprintf(stderr, "\n"); va_end(argp); } char *concat(const char *a, const char *b) { size_t na = strlen(a); size_t nb = strlen(b); char *result = static_cast(malloc(na + nb + 1)); assert(result); memcpy(result, a, na); memcpy(result + na, b, nb + 1); return result; } char *concat(const char *a, int b) { char bStr[14]; #if defined(_MSC_VER) _snprintf_s(bStr, _countof(bStr), sizeof(bStr), "%d", b); #else snprintf(bStr, sizeof(bStr), "%d", b); #endif return concat(a, bStr); } /** * Runs the given executable, returning its error code. */ int execute(const std::string &exePath, const char **args) { std::string errorMsg; int rc = ls::ExecuteAndWait(exePath, args, nullptr, #if LDC_LLVM_VER >= 600 {}, #else nullptr, #endif 0, 0, &errorMsg); if (!errorMsg.empty()) { error("Error executing %s: %s", exePath.c_str(), errorMsg.c_str()); } return rc; } /** * Prints usage information to stdout. */ void printUsage(const char *argv0, const std::string &ldcPath) { // Print version information by actually invoking ldc -version. const char *args[] = {ldcPath.c_str(), "-version", nullptr}; execute(ldcPath, args); printf( "\n\ Usage:\n\ %s [