From da2b8f25f5e5ce5d3ba73000f3d8d6e0aa27df67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20P=C3=B6chtrager?= Date: Sat, 27 Jun 2015 19:01:56 +0200 Subject: [PATCH] xcrun: * handle '-sdk' / 'SDKROOT' (env.) properly. e.g. 'xcrun -sdk /[...]/MacOSX10.6.sdk clang' will use the specified 10.6 SDK. * never execute xcode tools outside target/bin even when a full path is specified. e.g. 'xcrun /usr/bin/gcc' will execute target/bin/-gcc. other wrapper changes: * implement 'OSXCROSS_SDKROOT' env. variable for 'xcrun -sdk'. * error on '-arch x86_64h' + clang <= 3.4. clang <= 3.4 misinterprets x86_64h as x86_64. * only create x86_64h symlinks when the 10.8 (or later) SDK is used. other changes: * misc fixes and cleanup --- LICENSE => COPYING | 0 README.md | 32 +++++----- TODO | 1 - build.sh | 26 ++++---- build_clang.sh | 7 ++- cleanup.sh | 6 +- tools/tools.sh | 7 +++ wrapper/build.sh | 15 +++-- wrapper/main.cpp | 4 +- wrapper/programs/xcrun.cpp | 118 +++++++++++++++++++++++++++++-------- wrapper/target.cpp | 65 ++++++++++++++------ wrapper/target.h | 10 ++-- wrapper/tools.h | 2 +- wrapper/wrapper.project | 55 ++++------------- wrapper/wrapper.workspace | 9 +++ 15 files changed, 223 insertions(+), 134 deletions(-) rename LICENSE => COPYING (100%) create mode 100644 wrapper/wrapper.workspace diff --git a/LICENSE b/COPYING similarity index 100% rename from LICENSE rename to COPYING diff --git a/README.md b/README.md index 3a17f2e..7ab5a20 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,9 @@ You can turn this behavior off with `OSXCROSS_GCC_NO_STATIC_RUNTIME=1` (env). ### PACKAGING THE SDK: ### +** [Please ensure you have read and understood the Xcode license + terms before continuing.](https://www.apple.com/legal/sla/docs/xcode.pdf) ** + ##### Packaging the SDK on Mac OS X: ##### 1. [Download [Xcode](https://developer.apple.com/downloads/index.action?name=Xcode%205.1.1) \*\*] @@ -84,18 +87,12 @@ You can turn this behavior off with `OSXCROSS_GCC_NO_STATIC_RUNTIME=1` (env). Step 1. and 2. can be skipped if you have Xcode installed. -##### Packing the SDK on Linux, Method 1 (does *NOT* work with Xcode 4.3 or later!): ##### +##### Packing the SDK on Linux (and others), Method 1 (works with Xcode >= 4.3): ##### -1. Download - [Xcode 4.2](https://startpage.com/do/search?q=stackoverflow+xcode+4.2+download+snow+leopard) - for Snow Leopard \*\* -2. Ensure you are downloading the "Snow Leopard" version -3. Install `dmg2img` -4. Run (as root): `./tools/mount_xcode_image.sh /path/to/xcode.dmg` -5. Follow the instructions printed by `./tools/mount_xcode_image.sh` -6. Copy or move the SDK into the tarballs/ directory - -\*\* SHA1 Sum: 1a06882638996dfbff65ea6b4c6625842903ead3. +1. Download Xcode like described in 'Packaging the SDK on Mac OS X' +2. Ensure you have `clang` and `make` installed +3. Run `./gen_sdk_package_p7zip.sh .dmg` +4. Copy or move the SDK into the tarballs/ directory ##### Packing the SDK on Linux, Method 2 (works with Xcode >= 4.3): ##### @@ -104,12 +101,15 @@ Step 1. and 2. can be skipped if you have Xcode installed. 3. Run `./gen_sdk_package_darling_dmg.sh .dmg` 4. Copy or move the SDK into the tarballs/ directory -##### Packing the SDK on Linux (and others), Method 3 (works with Xcode >= 4.3): ##### +##### Packing the SDK on Linux, Method 3 (does *NOT* work with Xcode 4.3 or later!): ##### + +1. Download Xcode 4.2 for Snow Leopard +2. Ensure you are downloading the "Snow Leopard" version +3. Install `dmg2img` +4. Run (as root): `./tools/mount_xcode_image.sh /path/to/xcode.dmg` +5. Follow the instructions printed by `./tools/mount_xcode_image.sh` +6. Copy or move the SDK into the tarballs/ directory -1. Download Xcode like described in 'Packaging the SDK on Mac OS X' -2. Ensure you have `clang` and `make` installed -3. Run `./gen_sdk_package_darling_p7zip.sh .dmg` -4. Copy or move the SDK into the tarballs/ directory ### USAGE EXAMPLES: ### diff --git a/TODO b/TODO index 1003b95..e69de29 100644 --- a/TODO +++ b/TODO @@ -1 +0,0 @@ -report the __block issue in unistd.h to the maintainers diff --git a/build.sh b/build.sh index c2073f6..8ee378e 100755 --- a/build.sh +++ b/build.sh @@ -66,8 +66,6 @@ verify_sdk_version $SDK_VERSION # Minimum targeted OS X version # Must be <= SDK_VERSION -# You can comment this variable out, -# if you want to use the compiler's default value if [ -z "$OSX_VERSION_MIN" ]; then if [ $SDK_VERSION = 10.4u ]; then OSX_VERSION_MIN=10.4 @@ -78,10 +76,6 @@ fi OSXCROSS_VERSION=0.10 -if [ -z "$OSX_VERSION_MIN" ]; then - OSX_VERSION_MIN="default" -fi - case $SDK_VERSION in 10.4*) TARGET=darwin8 ;; 10.5*) TARGET=darwin9 ;; @@ -324,18 +318,18 @@ $BASE_DIR/wrapper/build.sh 1>/dev/null echo "" -if [ "$OSX_VERSION_MIN" != "default" ]; then - if [ `osxcross-cmp ${SDK_VERSION/u/} "<" $OSX_VERSION_MIN` -eq 1 ]; then - echo "OSX_VERSION_MIN must be <= SDK_VERSION" - trap "" EXIT - exit 1 - elif [ `osxcross-cmp $OSX_VERSION_MIN "<" 10.4` -eq 1 ]; then - echo "OSX_VERSION_MIN must be >= 10.4" - trap "" EXIT - exit 1 - fi +if [ `osxcross-cmp ${SDK_VERSION/u/} "<" $OSX_VERSION_MIN` -eq 1 ]; then + echo "OSX_VERSION_MIN must be <= SDK_VERSION" + trap "" EXIT + exit 1 +elif [ `osxcross-cmp $OSX_VERSION_MIN "<" 10.4` -eq 1 ]; then + echo "OSX_VERSION_MIN must be >= 10.4" + trap "" EXIT + exit 1 fi +unset MACOSX_DEPLOYMENT_TARGET + test_compiler o32-clang $BASE_DIR/oclang/test.c test_compiler o64-clang $BASE_DIR/oclang/test.c diff --git a/build_clang.sh b/build_clang.sh index e34cbe8..49e799b 100755 --- a/build_clang.sh +++ b/build_clang.sh @@ -85,8 +85,11 @@ fi echo "Building Clang/LLVM $CLANG_VERSION may take a long time." echo "Installation Prefix: $INSTALLPREFIX" -read -p "Press enter to start building." -echo "" + +if [ -z "$UNATTENDED" ]; then + read -p "Press enter to start building." + echo "" +fi pushd $TARBALL_DIR &>/dev/null diff --git a/cleanup.sh b/cleanup.sh index aed06b4..a35305f 100755 --- a/cleanup.sh +++ b/cleanup.sh @@ -1,5 +1,3 @@ #!/usr/bin/env bash -rm -f *~ -rm -rf build -rm -rf target -rm -f *.tar.xz + +git clean -fdx || rm -rf *~ build target *.tar.xz diff --git a/tools/tools.sh b/tools/tools.sh index 2087e4a..6354404 100755 --- a/tools/tools.sh +++ b/tools/tools.sh @@ -66,6 +66,13 @@ else MAKE=make fi +if [[ $PLATFORM == *BSD ]] || [ $PLATFORM == "Darwin" ]; then + READLINK=greadlink +else + READLINK=readlink +fi + + require $MAKE function extract() diff --git a/wrapper/build.sh b/wrapper/build.sh index 381b414..fee42ba 100755 --- a/wrapper/build.sh +++ b/wrapper/build.sh @@ -8,6 +8,11 @@ popd &>/dev/null set +e if [ -z "$OSXCROSS_VERSION" ]; then `../target/bin/osxcross-conf 2>/dev/null` + + if [ -n "$OSXCROSS_SDK_VERSION" ] || + [ `osxcross-cmp $OSXCROSS_SDK_VERSION ">=" 10.8` -eq 1 ]; then + X86_64H_SUPPORTED=1 + fi fi set -e @@ -41,8 +46,8 @@ function create_wrapper_link verbose_cmd ln -sf "${TARGETTRIPLE}-wrapper${EXESUFFIX}" \ "x86_64-apple-${OSXCROSS_TARGET}-${1}${EXESUFFIX}" - if [[ $1 != gcc* ]] && [[ $1 != g++* ]]; then - # do not create Haswell links for gcc + if [ -n "$X86_64H_SUPPORTED" ] && + ([[ $1 != gcc* ]] && [[ $1 != g++* ]]); then verbose_cmd ln -sf "${TARGETTRIPLE}-wrapper${EXESUFFIX}" \ "x86_64h-apple-${OSXCROSS_TARGET}-${1}${EXESUFFIX}" fi @@ -53,8 +58,8 @@ function create_wrapper_link verbose_cmd ln -sf "${TARGETTRIPLE}-wrapper${EXESUFFIX}" \ "o64-${1}${EXESUFFIX}" - if [[ $1 != gcc* ]] && [[ $1 != g++* ]]; then - # do not create Haswell links for gcc + if [ -n "$X86_64H_SUPPORTED" ] && + ([[ $1 != gcc* ]] && [[ $1 != g++* ]]); then verbose_cmd ln -sf "${TARGETTRIPLE}-wrapper${EXESUFFIX}" \ "o64h-${1}${EXESUFFIX}" fi @@ -93,7 +98,7 @@ if [ -n "$BWPLATFORM" ]; then [ -z "$BWCOMPILEONLY" ] && BWCOMPILEONLY=1 else PLATFORM=$(uname -s) - FLAGS="-march=native $CXXFLAGS " + [ -z "$PORTABLE"] && FLAGS="-march=native $CXXFLAGS " fi if [ -n "$BWCXX" ]; then diff --git a/wrapper/main.cpp b/wrapper/main.cpp index 8f1af26..aa96824 100644 --- a/wrapper/main.cpp +++ b/wrapper/main.cpp @@ -464,8 +464,8 @@ bool detectTarget(int argc, char **argv, Target &target) { (*prog)(argc, argv, target); if (target.target != getDefaultTarget()) { - warn << "target mismatch (" << target.target - << " != " << getDefaultTarget() << ")" << warn.endl(); + warn << "this wrapper was built for target " + << "'" << getDefaultTarget() << "'" << warn.endl(); } if (!parseArgs()) diff --git a/wrapper/programs/xcrun.cpp b/wrapper/programs/xcrun.cpp index 8e77c65..9485001 100644 --- a/wrapper/programs/xcrun.cpp +++ b/wrapper/programs/xcrun.cpp @@ -33,22 +33,52 @@ namespace { bool showCommand = false; +bool isXcodeTool(const char *tool) { + constexpr const char *XcodeTools[] = { + "ar", "as", "c89", "c99", "c11", "c++", "cc", "checksyms", "clang", + "dsymutil", "codesign_allocate", "dyldinfo", "gcc", "g++", "gcov", + "gprof", "indr", "install_name_tool", "ld", "libtool", "lipo", + "machocheck", "nm", "nmedit", "ObjectDump", "objdump", "otool", + "pagestuff", "pkg-config", "ranlib", "redo_prebinding", + "seg_addr_table", "seg_hack", "size", "strings", "strip", "sw_vers", + "unwinddump", "xcodebuild", "xcrun" + }; + + for (const char *xctool : XcodeTools) + if (!strncmp(tool, xctool, strlen(xctool))) + return true; + + return false; +} + bool getToolPath(Target &target, std::string &toolpath, const char *tool) { - toolpath = target.execpath; - toolpath += "/"; - toolpath += getArchName(target.arch); - toolpath += "-"; - toolpath += getDefaultVendor(); - toolpath += "-"; - toolpath += getDefaultTarget(); - toolpath += "-"; - toolpath += tool; + const char *filename = getFileName(tool); + bool isxcodetool = isXcodeTool(filename); + + toolpath.clear(); + + if (tool[0] == PATHDIV) { + if (isxcodetool) + tool = filename; // map /usr/bin/clang (etc.) to -clang + else + toolpath = tool; + } + + if (toolpath.empty()) { + toolpath = target.execpath; + toolpath += PATHDIV; + toolpath += getArchName(target.arch); + toolpath += "-"; + toolpath += getDefaultVendor(); + toolpath += "-"; + toolpath += getDefaultTarget(); + toolpath += "-"; + toolpath += tool; + } if (!fileExists(toolpath.c_str())) { // Fall back to system executables so 'xcrun git status' etc. works. - toolpath.clear(); - - if (realPath(tool, toolpath)) + if (!isxcodetool && realPath(tool, toolpath)) return true; err << "xcrun: cannot find '" << tool << "' executable" << err.endl(); @@ -58,22 +88,52 @@ bool getToolPath(Target &target, std::string &toolpath, const char *tool) { return true; } -int help(Target&, char **) { +int help(Target&, char**) { std::cerr << "https://developer.apple.com/library/mac/documentation/Darwin/" "Reference/ManPages/man1/xcrun.1.html" << std::endl; return 0; } -int version(Target&, char **) { +int version(Target&, char**) { std::cout << "xcrun version: 0." << std::endl; return 0; } int sdk(Target&, char **argv) { - if (strcmp(argv[0], "macosx")) { - err << "xcrun: expected 'macosx' for '-sdk'" << err.endl(); + const char *SDK = argv[0]; + + if (!strcmp(SDK, "macosx") || !strcmp(SDK, "macosx.internal")) + return 0; + + // Ignore '/'. + if (SDK[0] == PATHDIV && !SDK[1]) + return 0; + + std::string SDKPath = SDK; + + while (SDKPath.size() && SDKPath[SDKPath.size() - 1] == PATHDIV) + SDKPath.erase(SDKPath.size() - 1, 1); + + const char *SDKName = getFileName(SDKPath); + + if (!strncasecmp(SDKName, "MacOSX", 6)) { + if (!dirExists(SDK)) { + err << "xcrun: '-sdk': directory '" << SDK << "' does not exist" + << err.endl(); + return 1; + } + + setenv("OSXCROSS_SDKROOT", SDK, 1); + + return 0; + } + + // Ignore empty argument. + if (SDK[0]) { + err << "xcrun: '-sdk': expected Mac OS X SDK" << err.endl(); return 1; } + return 0; } @@ -95,13 +155,18 @@ int find(Target &target, char **argv) { int run(Target &target, char **argv) { std::string toolpath; std::string command; + if (!getToolPath(target, toolpath, argv[0])) - exit(1); // Should never return. + exit(1); + std::vector args; args.push_back(const_cast(toolpath.c_str())); + for (char **arg = &argv[1]; *arg; ++arg) args.push_back(*arg); + args.push_back(nullptr); + if (showCommand) { for (size_t i = 0; i < args.size() - 1; ++i) { std::cout << args[i]; @@ -110,15 +175,17 @@ int run(Target &target, char **argv) { } std::cout << std::endl; } + execvp(args[0], args.data()); err << "xcrun: cannot execute '" << args[0] << "'" << err.endl(); exit(1); + // Silence -Wreturn-type warnings in case exit() is not marked as // "no-return" for whatever reason. __builtin_unreachable(); } -int showSDKPath(Target &target, char **) { +int showSDKPath(Target &target, char**) { std::string SDKPath; if (!target.getSDKPath(SDKPath)) return 1; @@ -126,7 +193,7 @@ int showSDKPath(Target &target, char **) { return 0; } -int showSDKVersion(Target &target, char **) { +int showSDKVersion(Target &target, char**) { std::cout << target.getSDKOSNum().shortStr() << std::endl; return 0; } @@ -138,17 +205,22 @@ int xcrun(int argc, char **argv, Target &target) { showCommand = true; constexpr const char *ENVVARS[] = { - "DEVELOPER_DIR", "SDKROOT", "TOOLCHAINS", - "xcrun_verbose" + "DEVELOPER_DIR", "TOOLCHAINS", "xcrun_verbose" }; for (const char *evar : ENVVARS) { if (getenv(evar)) { - warn << "xcrun: ignoring environment variable '" << evar << "'" - << warn.endl(); + warn << "xcrun: ignoring environment variable " + << "'" << evar << "'" << warn.endl(); } } + if (char *SDK = getenv("SDKROOT")) { + unsetenv("OSXCROSS_SDKROOT"); + char *argv[1] = { SDK }; + sdk(target, argv); + } + auto dummy = [](Target&, char**) { return 0; }; ArgParser argParser = {{ diff --git a/wrapper/target.cpp b/wrapper/target.cpp index 39e727e..b75c5b7 100644 --- a/wrapper/target.cpp +++ b/wrapper/target.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -38,24 +39,42 @@ namespace target { OSVersion Target::getSDKOSNum() const { - if (target.size() < 7) - return OSVersion(); + if (SDK) { + std::string SDKPath = SDK; - int n = atoi(target.c_str() + 6); - return OSVersion(10, 4 + (n - 8)); + while (SDKPath.size() && SDKPath[SDKPath.size() - 1] == PATHDIV) + SDKPath.erase(SDKPath.size() - 1, 1); + + const char *SDKName = getFileName(SDKPath); + + if (strncasecmp(SDKName, "MacOSX", 6)) + return OSVersion(); + + return parseOSVersion(SDKName + 6); + } else { + if (target.size() < 7) + return OSVersion(); + + int n = atoi(target.c_str() + 6); + return OSVersion(10, 4 + (n - 8)); + } } bool Target::getSDKPath(std::string &path) const { - OSVersion SDKVer = getSDKOSNum(); + if (SDK) { + path = SDK; + } else { + OSVersion SDKVer = getSDKOSNum(); - path = execpath; - path += "/../SDK/MacOSX"; - path += SDKVer.shortStr(); + path = execpath; + path += "/../SDK/MacOSX"; + path += SDKVer.shortStr(); - if (SDKVer <= OSVersion(10, 4)) - path += "u"; + if (SDKVer <= OSVersion(10, 4)) + path += "u"; - path += ".sdk"; + path += ".sdk"; + } if (!dirExists(path)) { err << "cannot find Mac OS X SDK (expected in: " << path << ")" @@ -467,8 +486,8 @@ bool Target::setup() { if (haveArch(Arch::x86_64h)) { OSNum = OSVersion(10, 8); // Default to 10.8 for x86_64h if (SDKOSNum < OSNum) { - err << "'" << getArchName(arch) << "' requires the SDK from " - << OSNum.Str() << " (or later)" << err.endl(); + err << "'" << getArchName(arch) << "' requires Mac OS X SDK " + << OSNum.shortStr() << " (or later)" << err.endl(); return false; } } else if (stdlib == StdLib::libcxx) { @@ -488,9 +507,15 @@ bool Target::setup() { } if (haveArch(Arch::x86_64h) && OSNum < OSVersion(10, 8)) { - err << "'" << getArchName(Arch::x86_64h) << "' requires " - << "'-mmacosx-version-min=10.8' (or later)" << err.endl(); - return false; + // -mmacosx-version-min= < 10.8 in combination with '-arch x86_64h' + // may cause linker errors. + + // Erroring here is really annoying, better risk linking errors instead + // of enforcing '-mmacosx-version-min= >= 10.8'. + + if (!getenv("OSXCROSS_NO_X86_64H_DEPLOYMENT_TARGET_WARNING")) + warn << "'-mmacosx-version-min=' should be '>= 10.8' for architecture " + << "'" << getArchName(Arch::x86_64h) << "'" << warn.endl(); } if (stdlib == StdLib::unset) { @@ -501,7 +526,7 @@ bool Target::setup() { } } else if (stdlib == StdLib::libcxx) { if (!hasLibCXX()) { - err << "libc++ requires the SDK from 10.7 (or later)" << err.endl(); + err << "libc++ requires Mac OS X SDK 10.7 (or later)" << err.endl(); return false; } @@ -612,6 +637,12 @@ bool Target::setup() { warn << "cannot find clang intrinsic headers; please report this " "issue to the OSXCross project" << warn.endl(); } else { + if (haveArch(Arch::x86_64h) && clangversion < ClangVersion(3, 5)) { + err << "'" << getArchName(Arch::x86_64h) << "' requires clang 3.5 " + << "(or later)" << err.endl(); + return false; + } + fargs.push_back("-isystem"); fargs.push_back(tmp); } diff --git a/wrapper/target.h b/wrapper/target.h index c2cec9c..36243ec 100644 --- a/wrapper/target.h +++ b/wrapper/target.h @@ -73,11 +73,10 @@ constexpr OSVersion getDefaultMinTarget() { return OSVersion(); } struct Target { Target() - : vendor(getDefaultVendor()), arch(Arch::x86_64), - target(getDefaultTarget()), stdlib(StdLib::unset), usegcclibs(), - nocodegen(), compilername(getDefaultCompiler()), lang(), langstd(), - sourcefile(), - outputname() { + : vendor(getDefaultVendor()), SDK(getenv("OSXCROSS_SDKROOT")), + arch(Arch::x86_64), target(getDefaultTarget()), stdlib(StdLib::unset), + usegcclibs(), nocodegen(), compilername(getDefaultCompiler()), lang(), + langstd(), sourcefile(), outputname() { if (!getExecutablePath(execpath, sizeof(execpath))) abort(); } @@ -142,6 +141,7 @@ struct Target { bool setup(); const char *vendor; + const char *SDK; Arch arch; std::vector targetarch; std::string target; diff --git a/wrapper/tools.h b/wrapper/tools.h index b53c22f..845aadb 100644 --- a/wrapper/tools.h +++ b/wrapper/tools.h @@ -112,7 +112,7 @@ public: Message(const char *msg, Color color = FG_RED, std::ostream &os = std::cerr) : msg(msg), color(color), os(os), printprefix(true) {} } warn("warning"), err("error"), dbg("debug", FG_LIGHT_MAGENTA), - info("info", FG_LIGHT_MAGENTA), warninfo(" info", FG_LIGHT_MAGENTA); + info("info", FG_LIGHT_MAGENTA), warninfo("info", FG_LIGHT_MAGENTA); // // Executable path diff --git a/wrapper/wrapper.project b/wrapper/wrapper.project index 8961c3d..f7799dc 100644 --- a/wrapper/wrapper.project +++ b/wrapper/wrapper.project @@ -1,8 +1,20 @@ + + + - - - @@ -71,7 +80,7 @@ make clean - make + ./build.sh @@ -89,43 +98,5 @@ - - - - - - - - - - - - - - - - - - - - make clean - make - - - - None - $(WorkspacePath) - - - - - - - - - - - - diff --git a/wrapper/wrapper.workspace b/wrapper/wrapper.workspace new file mode 100644 index 0000000..e32a680 --- /dev/null +++ b/wrapper/wrapper.workspace @@ -0,0 +1,9 @@ + + + + + + + + +