diff --git a/wrapper/main.cpp b/wrapper/main.cpp index 0aef128..4f90da5 100644 --- a/wrapper/main.cpp +++ b/wrapper/main.cpp @@ -239,10 +239,10 @@ constexpr struct Opt { const size_t valseparatorlen; constexpr Opt(const char *name, optFun fun, const bool valrequired = false, const bool pusharg = false, const char *valseparator = nullptr) - : name(name), namelen(slen(name)), fun(fun), + : name(name), namelen(constexprStrLen(name)), fun(fun), valrequired(valrequired), pusharg(pusharg), valseparator(valseparator), - valseparatorlen(valseparator ? slen(valseparator) : 0) {} + valseparatorlen(valseparator ? constexprStrLen(valseparator) : 0) {} } opts[] = { {"-mmacosx-version-min", versionmin, true, false, "="}, {"-stdlib", stdlib, true, false, "="}, diff --git a/wrapper/programs/dsymutil.cpp b/wrapper/programs/dsymutil.cpp index 7974e9a..31bc597 100644 --- a/wrapper/programs/dsymutil.cpp +++ b/wrapper/programs/dsymutil.cpp @@ -23,6 +23,9 @@ #ifndef _WIN32 #include +#include +#include +#include #endif using namespace tools; @@ -32,6 +35,19 @@ namespace program { int dsymutil(int argc, char **argv, Target &target) { (void)argc; + // + // LLVM 3.6 and LLVM 3.7 come with too early in-development versions of + // llvm-dsymutil, which we *must* ignore here. + // + // 1. Lookup the [osxcross-]llvm-dsymutil binary. + // If no binary is found, then silently return 0/EXIT_SUCCESS. + // 2. Run . + // 3. Check whether we are using llvm-dsymutil 3.8 (or later), + // otherwise silently return 0/EXIT_SUCCESS. + // 4. Apply compatibility workarounds. + // 5. Run [osxcross-]llvm-dsymutil. + // + std::string dsymutil; char LLVMDsymutilVersionOutput[1024]; const char *LLVMDsymutilVersionStr; @@ -75,7 +91,7 @@ int dsymutil(int argc, char **argv, Target &target) { return 0; } - LLVMDsymutilVersionStr += 13; // strlen("LLVM version "); + LLVMDsymutilVersionStr += constexprStrLen("LLVM version "); LLVMDsymutilVersion = parseLLVMVersion(LLVMDsymutilVersionStr); @@ -97,7 +113,104 @@ int dsymutil(int argc, char **argv, Target &target) { lipo << target.execpath << PATHDIV << target.getDefaultTriple(triple) << "-lipo"; - setenv("LIPO", lipo.str().c_str(), 1); + if (endsWith(dsymutil, "osxcross-llvm-dsymutil")) { + // This is a patched llvm-dsymutil, just need to set LIPO here. + setenv("LIPO", lipo.str().c_str(), 1); + } else { + // This is an unpatched llvm-dsymutil, need to use stupid workarounds here. + + // There is a bug in the vanilla llvm-dsymutil sources which would cause it + // to crash when operating on gcc object files. + // Fix: https://github.com/tpoechtrager/llvm-dsymutil/commit/5e0fea25.patch + + auto fixHint = []() { + info << "you can build a patched llvm-dsymutil via " + << "./build_llvm_dsymutil.sh" + << info.endl(); + }; + + if (ParentProcessName == "collect2" && + !getenv("OSXCROSS_FORCE_GCC_DSYMUTIL_INVOCATION")) { + if (!getenv("OSXCROSS_NO_GCC_DSYMUTIL_WARNING")) { + warn << "dsymutil is a no-op when being invoked via gcc; " + << "you would get a crash otherwise" + << warn.endl(); + fixHint(); + } + return 0; + } + +#ifndef _WIN32 + // + // A glorious workaround to make the vanilla llvm-dsymutil find lipo. + // + // 1. Create a temporary directory. + // 2. Store a lipo symlink there. + // 3. Append to PATH. + // 4. Fork the process and wait until the child process exited. + // 5. Remove the temporary directory and return the llvm-dsymutil. + // exit code. + // + + char tmpdir[] = "/tmp/XXXXXX"; + std::string lipolink; + pid_t pid; + + if (mkdtemp(tmpdir)) { + lipolink = tmpdir; + lipolink += "/lipo"; + + auto removeTemporaryDirectory = [&]() { + if ((!lipolink.empty() && unlink(lipolink.c_str())) || rmdir(tmpdir)) { + warn << "dsymutil: cannot remove temporary directory '" + << tmpdir << "'" << warn.endl(); + } + }; + + if (!symlink(lipo.str().c_str(), lipolink.c_str())) { + concatEnvVariable("PATH", tmpdir); + + if ((pid = fork()) == -1) { + err << "dsymutil: fork() failed" << err.endl(); + removeTemporaryDirectory(); + return 2; + } else if (pid > 0) { + int status; + + if (waitpid(pid, &status, 0) == -1) { + err << "dsymutil: waitpid() failed" << err.endl(); + removeTemporaryDirectory(); + return 2; + } + + removeTemporaryDirectory(); + + if (WIFSIGNALED(status)) { + int signal = WTERMSIG(status); + + err << "dsymutil: signal: " << strsignal(signal) << err.endl(); + + if (signal == SIGSEGV) { + info << "the vanilla llvm-dsymutil is known to crash " + << "when operating on gcc object files" << info.endl(); + fixHint(); + } + + return 2; + } + + if (WIFEXITED(status)) + return WEXITSTATUS(status); + + abort(); + } + } else { + lipolink.clear(); + removeTemporaryDirectory(); + } + } +#endif + } if (execvp(dsymutil.c_str(), argv)) err << "cannot execute '" << dsymutil << "'" << err.endl(); diff --git a/wrapper/tools.h b/wrapper/tools.h index aa7d924..0472305 100644 --- a/wrapper/tools.h +++ b/wrapper/tools.h @@ -40,8 +40,8 @@ static inline bool endsWith(std::string const &str, std::string const &end) { return std::equal(end.rbegin(), end.rend(), str.rbegin()); } -size_t constexpr slen(const char *str) { - return *str ? 1 + slen(str + 1) : 0; +size_t constexpr constexprStrLen(const char *str) { + return *str ? 1 + constexprStrLen(str + 1) : 0; } //