diff --git a/CHANGELOG b/CHANGELOG index 3497967..aa4df27 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,10 @@ changed: * updated cctools to 855 with ld64-236.3 (Xcode 5.1) * gcc 4.9.0 -> gcc 4.9.1 +added: + * support for new '-arch x86_64h' (requires clang 3.5+) + * support for multiple '-arch' flags with gcc + /******************************* v0.7 *******************************/ added: diff --git a/README.md b/README.md old mode 100644 new mode 100755 index f44b975..6862b15 --- a/README.md +++ b/README.md @@ -145,12 +145,13 @@ However, there are several ways to override the default value: \>= 10.9 also defaults to `libc++` instead of `libstdc++`, this behavior can be overriden by explicitly passing `-stdlib=libstdc++` to clang. +x86_64h defaults to `Mac OS X 10.9` and requires clang 3.5+. + ### LICENSE: #### * scripts/wrapper: GPLv2 * cctools/ld64: APSL 2.0 * xar: New BSD * bc: GPLv3 - ### CREDITS: #### * [cjacker for the cctools linux port](https://code.google.com/p/ios-toolchain-based-on-clang-for-linux/source/browse/#svn%2Ftrunk%2Fcctools-porting%2Fpatches) diff --git a/build.sh b/build.sh index a547bfe..4c6a951 100755 --- a/build.sh +++ b/build.sh @@ -200,6 +200,10 @@ popd &>/dev/null pushd $TARGET_DIR/bin &>/dev/null CCTOOLS=`find . -name "x86_64-apple-darwin*"` CCTOOLS=($CCTOOLS) +for CCTOOL in ${CCTOOLS[@]}; do + CCTOOL_X86_64H=`echo "$CCTOOL" | sed 's/x86_64/x86_64h/g'` + ln -sf $CCTOOL $CCTOOL_X86_64H +done for CCTOOL in ${CCTOOLS[@]}; do CCTOOL_I386=`echo "$CCTOOL" | sed 's/x86_64/i386/g'` ln -sf $CCTOOL $CCTOOL_I386 diff --git a/tools/tools.sh b/tools/tools.sh index 862f276..b15045c 100755 --- a/tools/tools.sh +++ b/tools/tools.sh @@ -20,7 +20,7 @@ PSCRIPT="`basename $0`" if [[ $PSCRIPT != *wrapper/build.sh ]]; then # how many concurrent jobs should be used for compiling? - JOBS=`tools/get_cpu_count.sh` + JOBS=${JOBS:=`tools/get_cpu_count.sh`} if [ $PSCRIPT != "build.sh" ]; then `tools/osxcross_conf.sh` diff --git a/wrapper/main.cpp b/wrapper/main.cpp index 129bac6..e8b6d6d 100644 --- a/wrapper/main.cpp +++ b/wrapper/main.cpp @@ -151,6 +151,27 @@ bool detectTarget(int argc, char **argv, Target &target) { PABREAK; } + case 'f': { + // -f + + if (!strcmp(arg, "-flto") || !strncmp(arg, "-flto=", 5)) { + target.args.push_back(arg); + + if (target.isClang()) + continue; + + delayedfuncs.push_back([](Target &t) { + if (t.targetarch.size() > 1) { + std::cerr << "gcc does not support '-flto' with multiple " + << "-arch flags" << std::endl; + return false; + } + return true; + }); + } + + PABREAK; + } case 'm': { // -m @@ -352,6 +373,8 @@ bool detectTarget(int argc, char **argv, Target &target) { if (!strncmp(cmd, "o32", 3)) target.arch = Arch::i386; + else if (!strncmp(cmd, "o64h", 4)) + target.arch = Arch::x86_64h; else if (!strncmp(cmd, "o64", 3)) target.arch = Arch::x86_64; else @@ -368,6 +391,242 @@ bool detectTarget(int argc, char **argv, Target &target) { return target.setup(); } +// +// generateMultiArchObjectFile(): +// support multiple -arch flags with gcc +// and clang + -oc-use-gcc-libs +// + +void generateMultiArchObjectFile(int &rc, int argc, char **argv, Target &target, + int debug) { +#ifndef _WIN32 + std::string stdintmpfile; + string_vector objs; + std::stringstream obj; + bool compile = false; + size_t num = 0; + + if (!strcmp(argv[argc - 1], "-")) { + // + // fork() + reading from stdin isn't a good idea + // + + std::stringstream file; + std::string stdinsrc; + std::string line; + + while (std::getline(std::cin, line)) { + stdinsrc += line; + stdinsrc += '\n'; + } + + file << "/tmp/" << getNanoSeconds() << "_stdin"; + + if (target.isC()) + file << ".c"; + else if (target.isCXX()) + file << ".cpp"; + else if (target.isObjC()) + file << ".m"; + + stdintmpfile = file.str(); + writeFileContent(stdintmpfile, stdinsrc); + target.args[target.args.size() - 1] = stdintmpfile; + } + + auto cleanup = [&]() { + if (!stdintmpfile.empty()) + remove(stdintmpfile.c_str()); + for (auto &obj : objs) + remove(obj.c_str()); + }; + + if (!target.outputname) { + bool f = false; + + for (auto &arg : target.args) { + if (arg == "-c") { + f = true; + break; + } + } + + if (f && target.haveSourceFile()) { + static std::string outputname; + const char *ext = getFileExtension(target.sourcefile); + size_t pos; + + if (*ext) + outputname = std::string(target.sourcefile, ext - target.sourcefile); + else + outputname = target.sourcefile; + + outputname += ".o"; + + if ((pos = outputname.find_last_of('/')) == std::string::npos) + pos = 0; + else + ++pos; + + target.outputname = outputname.c_str() + pos; + } else { + if (f) { + std::cerr << "source filename detection failed" << std::endl; + std::cerr << "using a.out" << std::endl; + } + target.outputname = "a.out"; + } + } + + const char *outputname = strrchr(target.outputname, '/'); + + if (!outputname) + outputname = target.outputname; + else + ++outputname; + + for (auto &arch : target.targetarch) { + const char *archname = getArchName(arch); + pid_t pid; + ++num; + + obj.str(std::string()); + obj << "/tmp/" << getNanoSeconds() << "_" << outputname << "_" << archname; + + objs.push_back(obj.str()); + pid = fork(); + + if (pid > 0) { + int status = 1; + + if (wait(&status) == -1) { + std::cerr << "wait() failed" << std::endl; + cleanup(); + rc = 1; + break; + } + + if (WIFEXITED(status)) { + status = WEXITSTATUS(status); + + if (status) { + rc = status; + break; + } + } else { + rc = 1; + break; + } + } else if (pid == 0) { + + if (target.isGCC()) { + // GCC + bool is32bit = false; + + switch (arch) { + case Arch::i386: + case Arch::i486: + case Arch::i586: + case Arch::i686: + is32bit = true; + case Arch::x86_64: + break; + default: + assert(false && "unsupported arch"); + } + + target.fargs.push_back(is32bit ? "-m32" : "-m64"); + } else if (target.isClang()) { + // Clang + target.fargs.push_back("-arch"); + target.fargs.push_back(getArchName(arch)); + } else { + assert(false && "unsupported compiler"); + } + + target.fargs.push_back("-o"); + target.fargs.push_back(obj.str()); + + if (target.usegcclibs) { + target.setupGCCLibs(arch); + + if (target.langGiven()) { + // -x must be added *after* the static libstdc++ *.a + // otherwise clang thinks they are source files + target.fargs.push_back("-x"); + target.fargs.push_back(target.lang); + } + } + + if (debug) { + std::cerr << "[d] " + << "[" << num << "/" << target.targetarch.size() + << "] [compiling] " << archname << std::endl; + } + + compile = true; + break; + } else { + std::cerr << "fork() failed" << std::endl; + rc = 1; + break; + } + } + + if (!compile && !target.nocodegen && rc == -1) { + std::string cmd; + std::string lipo; + std::string path; + + lipo = "x86_64-apple-"; + lipo += getDefaultTarget(); + lipo += "-lipo"; + + if (getPathOfCommand(lipo.c_str(), path).empty()) { + lipo = "lipo"; + + if (getPathOfCommand(lipo.c_str(), path).empty()) { + std::cerr << "cannot find lipo binary" << std::endl; + rc = 1; + } + } + + if (rc == -1) { + cmd.swap(path); + cmd += "/"; + cmd += lipo; + cmd += " -create "; + + for (auto &obj : objs) { + cmd += obj; + cmd += " "; + } + + cmd += "-output "; + cmd += target.outputname; + + if (debug) { + std::cerr << "[d] [lipo] <-- " << cmd << std::endl; + } + + rc = system(cmd.c_str()); + rc = WEXITSTATUS(rc); + } + } + + if (!compile) + cleanup(); +#else + (void)rc; + (void)argc; + (void)argv; + (void)target; + (void)debug; + std::cerr << __func__ << " not supported" << std::endl; + rc = 1; +#endif +} + } // unnamed namespace // @@ -416,6 +675,9 @@ int main(int argc, char **argv) { concatEnvVariable("COMPILER_PATH", target.execpath); + if (target.targetarch.size() > 1 && (target.usegcclibs || target.isGCC())) + generateMultiArchObjectFile(rc, argc, argv, target, debug); + auto printCommand = [&]() { std::string in; std::string out; diff --git a/wrapper/target.cpp b/wrapper/target.cpp index ef8d973..ddc82c8 100644 --- a/wrapper/target.cpp +++ b/wrapper/target.cpp @@ -343,6 +343,9 @@ void Target::setupGCCLibs(Arch arch) { fargs.push_back(tmp.str()); fargs.push_back("-lc"); + + if (OSNum <= OSVersion(10, 5)) + fargs.push_back("-Wl,-no_compact_unwind"); } bool Target::setup() { @@ -382,7 +385,14 @@ bool Target::setup() { otriple += target; if (!OSNum.Num()) { - if (stdlib == StdLib::libcxx) { + if (haveArch(Arch::x86_64h)) { + OSNum = OSVersion(10, 9); // Default to 10.9 for x86_64h + if (SDKOSNum < OSNum) { + std::cerr << getArchName(arch) << "requires the SDK from " + << OSNum.Str() << " (or later)"; + return false; + } + } else if (stdlib == StdLib::libcxx) { OSNum = OSVersion(10, 7); // Default to 10.7 for libc++ } else { OSNum = getDefaultMinTarget(); @@ -632,11 +642,19 @@ bool Target::setup() { case Arch::i686: is32bit = true; case Arch::x86_64: + case Arch::x86_64h: if (isGCC()) { if (targetarch.size() > 1) break; fargs.push_back(is32bit ? "-m32" : "-m64"); + + if (arch == Arch::x86_64h) { + std::cerr << getArchName(arch) << " requires clang" << std::endl; + return false; + // fargs.push_back("-march=core-avx2"); + // fargs.push_back("-Wl,-arch,x86_64h"); + } } else if (isClang()) { if (usegcclibs && targetarch.size() > 1) break;