diff --git a/wrapper/target.cpp b/wrapper/target.cpp index 5ce8472..c648a65 100644 --- a/wrapper/target.cpp +++ b/wrapper/target.cpp @@ -32,12 +32,27 @@ #include #include #include +#include +#include #include "tools.h" #include "target.h" namespace target { +Target::Target() + : vendor(getDefaultVendor()), SDK(getenv("OSXCROSS_SDKROOT")), + arch(Arch::x86_64), target(getDefaultTarget()), stdlib(StdLib::unset), + usegcclibs(), compilername(getDefaultCompiler()), language() { + if (!getExecutablePath(execpath, sizeof(execpath))) + abort(); + + const char *SDKSearchDir = getSDKSearchDir(); + + if (!SDK && SDKSearchDir[0]) + overrideDefaultSDKPath(SDKSearchDir); +} + OSVersion Target::getSDKOSNum() const { if (SDK) { std::string SDKPath = SDK; @@ -60,6 +75,63 @@ OSVersion Target::getSDKOSNum() const { } } +void Target::overrideDefaultSDKPath(const char *SDKSearchDir) { + std::string defaultSDKPath; + + defaultSDKPath = SDKSearchDir; + defaultSDKPath += PATHDIV; + defaultSDKPath += "default"; + + struct stat st; + + if (!lstat(defaultSDKPath.c_str(), &st)) { + if (!S_ISLNK(st.st_mode)) { + err << "'" << defaultSDKPath << "' must be a symlink to an SDK" + << err.endl(); + exit(EXIT_FAILURE); + } + + if (char *resolved = realpath(defaultSDKPath.c_str(), nullptr)) { + SDK = resolved; + } else { + err << "'" << defaultSDKPath << "' broken symlink" << err.endl(); + exit(EXIT_FAILURE); + } + } else { + // Choose the latest SDK + + static OSVersion latestSDKVersion; + static std::string latestSDK; + + latestSDKVersion = OSVersion(); + latestSDK.clear(); + + listFiles(SDKSearchDir, nullptr, [](const char *SDK) { + if (!strncasecmp(SDK, "MacOSX", 6)) { + OSVersion SDKVersion = parseOSVersion(SDK + 6); + if (SDKVersion > latestSDKVersion) { + latestSDKVersion = SDKVersion; + latestSDK = SDK; + } + } + return false; + }); + + if (!latestSDKVersion.Num()) { + err << "no SDK found in '" << SDKSearchDir << "'" << err.endl(); + exit(EXIT_FAILURE); + } + + std::string SDKPath; + + SDKPath = SDKSearchDir; + SDKPath += PATHDIV; + SDKPath += latestSDK; + + SDK = strdup(SDKPath.c_str()); // intentionally leaked + } +} + bool Target::getSDKPath(std::string &path) const { if (SDK) { path = SDK; diff --git a/wrapper/target.h b/wrapper/target.h index 92fd381..dbfa18a 100644 --- a/wrapper/target.h +++ b/wrapper/target.h @@ -61,21 +61,26 @@ inline OSVersion getDefaultMinTarget() { constexpr OSVersion getDefaultMinTarget() { return OSVersion(); } #endif +inline const char *getSDKSearchDir() { + const char *SDKSearchDir = getenv("OSXCROSS_SDK_SEARCH_DIR"); + +#ifdef OSXCROSS_SDK_SEARCH_DIR + if (!SDKSearchDir) + SDKSearchDir = OSXCROSS_SDK_SEARCH_DIR; +#endif + + return SDKSearchDir ? SDKSearchDir : ""; +} + // // Target // struct Target { - Target() - : vendor(getDefaultVendor()), SDK(getenv("OSXCROSS_SDKROOT")), - arch(Arch::x86_64), target(getDefaultTarget()), stdlib(StdLib::unset), - usegcclibs(), nocodegen(), compilername(getDefaultCompiler()), - language() { - if (!getExecutablePath(execpath, sizeof(execpath))) - abort(); - } + Target(); OSVersion getSDKOSNum() const; + void overrideDefaultSDKPath(const char *SDKSearchDir); bool getSDKPath(std::string &path) const; bool getMacPortsDir(std::string &path) const; @@ -120,7 +125,6 @@ struct Target { ClangVersion clangversion; GCCVersion gccversion; bool usegcclibs; - bool nocodegen; std::string compilerpath; // /usr/bin/clang | [...]/target/bin/*-gcc std::string compilername; // clang | gcc std::string compilerexecname; // clang | *-apple-darwin-gcc diff --git a/wrapper/unittests/run.bats b/wrapper/unittests/run.bats index 17742b6..fc6dc9f 100755 --- a/wrapper/unittests/run.bats +++ b/wrapper/unittests/run.bats @@ -473,6 +473,15 @@ eval $(osxcross-conf) [ "$status" -eq 0 ] } +@test "OSXCROSS_SDK_SEARCH_DIR" { + OSXCROSS_SDK_SEARCH_DIR=/dev/null run o64-clang++ + [ "$status" -ne 0 ] + [[ "${lines[0]}" == *error:\ no\ SDK\ found\ in\ \'/dev/null\' ]] + + OSXCROSS_SDK_SEARCH_DIR=$OSXCROSS_SDK/.. run o64-clang++ + [ "$status" -eq 0 ] +} + @test "xcrun" { run xcrun -sdk [ "$status" -ne 0 ]