diff --git a/CHANGELOG b/CHANGELOG index 81bdaba..05efaa3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ changed: * improved and colorized wrapper error/warning/debug/info messages added: +* support for ccache symlinks * darling-dmg sdk packaging script * include path warnings for /usr/include and /usr/local/include (can be switched off via 'OSXCROSS_NO_INCLUDE_PATH_WARNINGS=1') diff --git a/README.MACPORTS.md b/README.MACPORTS.md index b0b69b4..a5021b5 100644 --- a/README.MACPORTS.md +++ b/README.MACPORTS.md @@ -12,11 +12,11 @@ Also ensure that you are using the 10.6 SDK (or later). ### INSTALLATION: ### -Run OSXCross's `./build.sh`, then you should have `osxcross-macports` in PATH. +Run OSXCross' `./build.sh`, then you should have `osxcross-macports` in PATH. **Setting up osxcross-macports:** -MacPorts doesn't support 10.5 anymore, so we need to change OSXCross's +MacPorts doesn't support 10.5 anymore, so we need to change OSXCross' default target to 10.6 (better 10.7, or later). To achive this, add the following to your bashrc (or similar): @@ -35,7 +35,7 @@ Then run `osxcross-macports `. **pkg-config:** -OSXCross's `pkg-config` (`-apple-darwinXX-pkg-config`) +OSXCross' `pkg-config` (`-apple-darwinXX-pkg-config`) is automatically aware of MacPorts packages. If you want `pkg-config` to be unaware of MacPorts packages diff --git a/wrapper/main.cpp b/wrapper/main.cpp old mode 100755 new mode 100644 index 4bd8b7b..8f1af26 --- a/wrapper/main.cpp +++ b/wrapper/main.cpp @@ -51,15 +51,11 @@ namespace { int unittest = 0; -// -// detectTarget(): -// detect target and setup invocation command -// - void checkIncludePath(const char *opt, const char *path) { #ifndef __APPLE__ constexpr const char *DangerousIncludePaths[] = { "/usr/include", "/usr/local/include" }; + if (!path) return; @@ -108,6 +104,11 @@ void warnExtension(const char *extension) { << "'OSXCROSS_NO_EXTENSION_WARNINGS=1' (env)" << warninfo.endl(); } +// +// detectTarget(): +// detect target and setup invocation command +// + #define PABREAK \ else target.args.push_back(arg); \ break @@ -409,16 +410,17 @@ bool detectTarget(int argc, char **argv, Target &target) { }; auto checkCXXLib = [&]() { - if (target.compiler.size() <= 7) + if (target.compilername.size() <= 7) return; - if (target.compiler.rfind("-libc++") == (target.compiler.size() - 7)) { + if (target.compilername.rfind("-libc++") == + (target.compilername.size() - 7)) { if (target.stdlib != StdLib::unset && target.stdlib != StdLib::libcxx) { warn << "'-stdlib=" << getStdLibString(target.stdlib) << "' will be ignored" << warn.endl(); } - target.compiler.resize(target.compiler.size() - 7); + target.compilername.resize(target.compilername.size() - 7); target.stdlib = StdLib::libcxx; } }; @@ -452,13 +454,13 @@ bool detectTarget(int argc, char **argv, Target &target) { return false; target.target = std::string(cmd, p - cmd); - target.compiler = &p[1]; + target.compilername = &p[1]; - if (target.compiler == "cc") - target.compiler = getDefaultCompiler(); - else if (target.compiler == "c++") - target.compiler = getDefaultCXXCompiler(); - else if (auto *prog = program::getprog(target.compiler)) + if (target.compilername == "cc") + target.compilername = getDefaultCompiler(); + else if (target.compilername == "c++") + target.compilername = getDefaultCXXCompiler(); + else if (auto *prog = program::getprog(target.compilername)) (*prog)(argc, argv, target); if (target.target != getDefaultTarget()) { @@ -484,7 +486,7 @@ bool detectTarget(int argc, char **argv, Target &target) { return false; if (const char *p = strchr(cmd, '-')) - target.compiler = &cmd[p - cmd + 1]; + target.compilername = &cmd[p - cmd + 1]; if (!parseArgs()) return false; @@ -681,10 +683,10 @@ void generateMultiArchObjectFile(int &rc, int argc, char **argv, Target &target, lipo += getDefaultTarget(); lipo += "-lipo"; - if (getPathOfCommand(lipo.c_str(), path).empty()) { + if (!getPathOfCommand(lipo.c_str(), path)) { lipo = "lipo"; - if (getPathOfCommand(lipo.c_str(), path).empty()) { + if (!getPathOfCommand(lipo.c_str(), path)) { err << "cannot find lipo binary" << err.endl(); rc = 1; } @@ -759,7 +761,7 @@ int main(int argc, char **argv) { if (debug >= 2) { dbg << "detected target triple: " << target.getTriple() << dbg.endl(); - dbg << "detected compiler: " << target.compiler << dbg.endl(); + dbg << "detected compiler: " << target.compilername << dbg.endl(); dbg << "detected stdlib: " << getStdLibString(target.stdlib) << dbg.endl(); @@ -789,8 +791,18 @@ int main(int argc, char **argv) { in += " "; } - for (auto &arg : target.fargs) { - out += arg; + out += target.compilerpath; + + if (target.compilerpath != target.fargs[0]) { + out += " ("; + out += target.fargs[0]; + out += ") "; + } else { + out += " "; + } + + for (size_t i = 1; i < target.fargs.size(); ++i) { + out += target.fargs[i]; out += " "; } @@ -831,7 +843,7 @@ int main(int argc, char **argv) { if (unittest == 2) return 0; - if (rc == -1 && execvp(cargs[0], cargs)) { + if (rc == -1 && execvp(target.compilerpath.c_str(), cargs)) { err << "invoking compiler failed" << err.endl(); if (!debug) diff --git a/wrapper/programs/osxcross-env.cpp b/wrapper/programs/osxcross-env.cpp old mode 100755 new mode 100644 diff --git a/wrapper/programs/osxcross-version.cpp b/wrapper/programs/osxcross-version.cpp old mode 100755 new mode 100644 diff --git a/wrapper/programs/pkg-config.cpp b/wrapper/programs/pkg-config.cpp old mode 100755 new mode 100644 diff --git a/wrapper/programs/sw_vers.cpp b/wrapper/programs/sw_vers.cpp old mode 100755 new mode 100644 diff --git a/wrapper/target.cpp b/wrapper/target.cpp index 1301ced..ea2ef05 100644 --- a/wrapper/target.cpp +++ b/wrapper/target.cpp @@ -156,11 +156,11 @@ bool Target::isC(bool r) { return true; } - return compiler.find("++") == std::string::npos && !isObjC(true); + return compilername.find("++") == std::string::npos && !isObjC(true); } bool Target::isCXX() { - bool CXXCompiler = compiler.find("++") != std::string::npos; + bool CXXCompiler = compilername.find("++") != std::string::npos; if (!langGiven() && CXXCompiler && !isObjC(true)) return true; @@ -229,34 +229,37 @@ bool Target::isCXX11orNewer() const { return false; } -const std::string Target::getFullCompilerName() const { - std::string compiler; - +void Target::setCompilerPath() { if (isGCC()) { - compiler = execpath; - compiler += "/"; - compiler += getTriple(); - compiler += "-"; + compilerpath = execpath; + compilerpath += "/"; + compilerpath += getTriple(); + compilerpath += "-"; + compilerpath += "base-"; + compilerpath += compilername; + + compilerexecname = getTriple(); + compilerexecname += "-"; + compilerexecname += compilername; + } else { + if (!realPath(compilername.c_str(), compilerpath, ignoreCCACHE)) + compilerpath = compilername; + + compilerexecname += compilername; } - - if (isGCC()) - compiler += "base-"; - - compiler += this->compiler; - return compiler; } bool Target::findClangIntrinsicHeaders(std::string &path) { - std::string clangbin; static std::stringstream dir; assert(isClang()); - getPathOfCommand(compiler.c_str(), clangbin); - - if (clangbin.empty()) + if (compilerpath.empty()) return false; + std::string clangbindir = compilerpath; + stripFileName(clangbindir); + static ClangVersion *clangversion; static std::string pathtmp; @@ -266,10 +269,8 @@ bool Target::findClangIntrinsicHeaders(std::string &path) { *clangversion = ClangVersion(); pathtmp.clear(); - auto check = []()->bool { - + auto tryDir = [&]()->bool { listFiles(dir.str().c_str(), nullptr, [](const char *file) { - if (file[0] != '.' && isDirectory(file, dir.str().c_str())) { ClangVersion cv = parseClangVersion(file); @@ -303,47 +304,55 @@ bool Target::findClangIntrinsicHeaders(std::string &path) { checkDir(tmp); } } - return true; } - return true; }); - return *clangversion != ClangVersion(); }; - dir << clangbin << "/../lib/clang"; +#define TRYDIR(basedir, subdir) \ +do { \ + dir << basedir << subdir; \ + if (tryDir()) { \ + path.swap(pathtmp); \ + return true; \ + } \ + clear(dir); \ +} while (0) - if (!check()) { - clear(dir); +#define TRYDIR2(libdir) TRYDIR(clangbindir, libdir) +#define TRYDIR3(libdir) TRYDIR(std::string(), libdir) -#ifdef __APPLE__ - constexpr const char *OSXIntrinDirs[] = { - "/Library/Developer/CommandLineTools/usr/lib/clang", - "/Applications/Contents/Developer/Toolchains/" - "XcodeDefault.xctoolchain/usr/lib/clang" - }; + TRYDIR2("/../lib/clang"); - for (auto intrindir : OSXIntrinDirs) { - dir << intrindir; - if (check()) { - break; - } - clear(dir); - } +#ifdef __linux__ +#ifdef __x86_64__ + // opensuse uses lib64 instead of lib on x86_64 + TRYDIR2("/../lib64/clang"); +#elif __i386__ + TRYDIR2("/../lib32/clang"); +#endif #endif - if (!dir.rdbuf()->in_avail()) { - dir << clangbin << "/../include/clang"; +#ifdef __APPLE__ + constexpr const char *OSXIntrinDirs[] = { + "/Library/Developer/CommandLineTools/usr/lib/clang", + "/Applications/Contents/Developer/Toolchains/" + "XcodeDefault.xctoolchain/usr/lib/clang" + }; - if (!check()) - return false; - } - } + for (auto intrindir : OSXIntrinDirs) + TRYDIR3(intrindir); +#endif - path.swap(pathtmp); - return *clangversion != ClangVersion(); + TRYDIR2("/../include/clang"); + TRYDIR2("/usr/include/clang"); + + return false; +#undef TRYDIR +#undef TRYDIR2 +#undef TRYDIR3 } void Target::setupGCCLibs(Arch arch) { @@ -409,7 +418,7 @@ bool Target::setup() { OSVersion SDKOSNum = getSDKOSNum(); if (!isKnownCompiler()) - warn << "unknown compiler '" << compiler << "'" << warn.endl(); + warn << "unknown compiler '" << compilername << "'" << warn.endl(); if (!getSDKPath(SDKPath)) { err << "cannot find Mac OS X SDK (expected in: " << SDKPath << ")" @@ -439,6 +448,8 @@ bool Target::setup() { otriple += "-"; otriple += target; + setCompilerPath(); + if (!OSNum.Num()) { if (haveArch(Arch::x86_64h)) { OSNum = OSVersion(10, 8); // Default to 10.8 for x86_64h @@ -569,7 +580,7 @@ bool Target::setup() { abort(); } - fargs.push_back(getFullCompilerName()); + fargs.push_back(compilerexecname); if (isClang()) { std::string tmp; @@ -585,7 +596,7 @@ bool Target::setup() { #ifndef __APPLE__ if (!findClangIntrinsicHeaders(tmp)) { - warn << "cannot find clang intrinsic headers, please report this " + warn << "cannot find clang intrinsic headers; please report this " "issue to the OSXCross project" << warn.endl(); } else { fargs.push_back("-isystem"); diff --git a/wrapper/target.h b/wrapper/target.h index ea2fe2b..8682240 100644 --- a/wrapper/target.h +++ b/wrapper/target.h @@ -75,7 +75,7 @@ struct Target { Target() : vendor(getDefaultVendor()), target(getDefaultTarget()), stdlib(StdLib::unset), usegcclibs(), nocodegen(), - compiler(getDefaultCompiler()), lang(), langstd(), sourcefile(), + compilername(getDefaultCompiler()), lang(), langstd(), sourcefile(), outputname() { if (!getExecutablePath(execpath, sizeof(execpath))) abort(); @@ -115,11 +115,11 @@ struct Target { } bool isClang() const { - return !strncmp(getFileName(compiler.c_str()), "clang", 5); + return !strncmp(getFileName(compilername.c_str()), "clang", 5); } bool isGCC() const { - const char *c = getFileName(compiler.c_str()); + const char *c = getFileName(compilername.c_str()); return (!strncmp(c, "gcc", 3) || !strncmp(c, "g++", 3)); } @@ -133,7 +133,7 @@ struct Target { const std::string &getTriple() const { return triple; } - const std::string getFullCompilerName() const; + void setCompilerPath(); bool findClangIntrinsicHeaders(std::string &path); void setupGCCLibs(Arch arch); @@ -149,7 +149,9 @@ struct Target { GCCVersion gccversion; bool usegcclibs; bool nocodegen; - std::string compiler; + std::string compilerpath; // /usr/bin/clang | [...]/target/bin/*-gcc + std::string compilername; // clang | gcc + std::string compilerexecname; // clang | *-apple-darwin-gcc std::string triple; std::string otriple; const char *lang; diff --git a/wrapper/tools.cpp b/wrapper/tools.cpp old mode 100755 new mode 100644 index 4b33515..1f87308 --- a/wrapper/tools.cpp +++ b/wrapper/tools.cpp @@ -144,7 +144,6 @@ const std::string &getParentProcessName() { if (Process32First(h, &pe)) { do { - std::cout << pe.szExeFile << " " << pe.th32ProcessID << std::endl; if (pe.th32ProcessID == ppid) { ppe = &pe; break; @@ -336,54 +335,92 @@ bool isExecutable(const char *f, const struct stat &) { return !access(f, F_OK | X_OK); } -std::string &realPath(const char *file, std::string &result, realpathcmp cmp) { +bool ignoreCCACHE(const char *f, const struct stat &) { + const char *name = getFileName(f); + return name && strstr(name, "ccache") != name; +} + +bool realPath(const char *file, std::string &result, + realpathcmp cmp1, realpathcmp cmp2) { char *PATH = getenv("PATH"); const char *p = PATH ? PATH : ""; - std::string sfile; struct stat st; + result.clear(); + do { if (*p == ':') ++p; while (*p && *p != ':') - sfile += *p++; + result += *p++; - sfile += "/"; - sfile += file; - - if (!stat(sfile.c_str(), &st) && (!cmp || cmp(sfile.c_str(), st))) - break; - - sfile.clear(); - } while (*p); + result += "/"; + result += file; + if (!stat(result.c_str(), &st)) { #ifndef _WIN32 - if (!sfile.empty()) { - char buf[PATH_MAX + 1]; - ssize_t len; + char buf[PATH_MAX + 1]; - if ((len = readlink(sfile.c_str(), buf, PATH_MAX)) != -1) - result.assign(buf, len); - } + if (realpath(result.c_str(), buf)) { + result.assign(buf); + } else { + ssize_t len; + char path[PATH_MAX]; + size_t pathlen; + size_t n = 0; + + pathlen = result.find_last_of(PATHDIV); + + if (pathlen == std::string::npos) + pathlen = result.length(); + else + ++pathlen; // PATHDIV + + memcpy(path, result.c_str(), pathlen); // not null terminated + + while ((len = readlink(result.c_str(), buf, PATH_MAX)) != -1) { + if (buf[0] != PATHDIV) { + result.assign(path, pathlen); + result.append(buf, len); + } else { + result.assign(buf, len); + pathlen = strrchr(buf, PATHDIV) - buf + 1; // + 1: PATHDIV + memcpy(path, buf, pathlen); + } + if (++n >= 1000) { + err << result << ": too many levels of symbolic links" + << err.endl(); + result.clear(); + break; + } + } + } #endif - result.swap(sfile); - return result; + if ((!cmp1 || cmp1(result.c_str(), st)) && + (!cmp2 || cmp2(result.c_str(), st))) + break; + } + + result.clear(); + } while (*p); + + return !result.empty(); } -std::string &getPathOfCommand(const char *command, std::string &result) { - realPath(command, result, isExecutable); +bool getPathOfCommand(const char *command, std::string &result, + realpathcmp cmp) { + if (realPath(command, result, isExecutable, cmp)) + stripFileName(result); - const size_t len = strlen(command) + 1; + return !result.empty(); +} - if (result.size() < len) { - result.clear(); - return result; - } - - result.resize(result.size() - len); - return result; +void stripFileName(std::string &path) { + size_t lastpathdiv = path.find_last_of(PATHDIV); + if (lastpathdiv != 0 && lastpathdiv != std::string::npos) + path.resize(lastpathdiv); } const char *getFileName(const char *file) { diff --git a/wrapper/tools.h b/wrapper/tools.h old mode 100755 new mode 100644 index 4316e06..ddf87ee --- a/wrapper/tools.h +++ b/wrapper/tools.h @@ -19,6 +19,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***********************************************************************/ +struct stat; + namespace tools { // @@ -142,8 +144,13 @@ bool listFiles(const char *dir, std::vector *files, typedef bool (*realpathcmp)(const char *file, const struct stat &st); bool isExecutable(const char *f, const struct stat &); -std::string &realPath(const char *file, std::string &result, realpathcmp cmp); -std::string &getPathOfCommand(const char *command, std::string &result); +bool ignoreCCACHE(const char *f, const struct stat &); +bool realPath(const char *file, std::string &result, + realpathcmp cmp1 = nullptr, realpathcmp cmp2 = nullptr); +bool getPathOfCommand(const char *command, std::string &result, + realpathcmp cmp = nullptr); + +void stripFileName(std::string &path); const char *getFileName(const char *file); const char *getFileExtension(const char *file);