//===-- 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. // // The reason why full command line parsing is required instead of just // rewriting the names of a few switches is an annoying impedance mismatch // between the way how DMD handles arguments and the LLVM command line library: // DMD allows all switches to be specified multiple times – in case of // conflicts, the last one takes precedence. There is no easy way to replicate // this behavior with LLVM, save parsing the switches and re-emitting a cleaned // up string. // // 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. Thus, conflicts like mentioned above occur quite frequently in // practice in makefiles written for DMD, as DFLAGS is also a natural name for // handling flags there. // // In order to maintain backwards compatibility with earlier versions of LDMD, // unknown switches are passed through verbatim to LDC. Finding a better // solution for this is tricky, as some of the LLVM arguments can be // intentionally specified multiple times to get a certain effect (e.g. pass, // linker options). // // Just as with the old LDMD script, arguments can be passed through unmodified // to LDC by using -Csomearg. // // If maintaining this wrapper is deemed too messy at some point, an alternative // would be to either extend the LLVM command line library to support the DMD // semantics (unlikely to happen), or to abandon it altogether (except for // passing the LLVM-defined flags to the various passes). // // Note: This program inherited ugly C-style string handling and memory leaks // from DMD, but this should not be a problem due to the short-livedness of // the process. // //===----------------------------------------------------------------------===// #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 compatibilty - it // handles quotes in a very peculiar way. int response_expand(size_t *pargc, char ***pargv); 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, nullptr, 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 [