//===-- 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/args.h" #include "driver/exe_path.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/SystemUtils.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include #include #if _WIN32 #include #else #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 dmd/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]; snprintf(bStr, sizeof(bStr), "%d", b); return concat(a, bStr); } template bool startsWith(const char *str, const char (&prefix)[N]) { // N includes terminating null return strncmp(str, prefix, N - 1) == 0; } /** * Runs the given executable, returning its error code. */ int execute(std::vector fullArgs) { std::string errorMsg; const char *executable = fullArgs[0]; const int rc = args::executeAndWait(std::move(fullArgs), llvm::sys::WEM_UTF8, &errorMsg); if (rc && !errorMsg.empty()) { error("Error executing %s: %s", executable, 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. execute({ldcPath.c_str(), "-version"}); printf( "\n\ Usage:\n\ %s [