2014-05-17 23:15:15 +02:00
|
|
|
/***********************************************************************
|
|
|
|
* OSXCross Compiler Wrapper *
|
2015-02-08 10:27:26 +01:00
|
|
|
* Copyright (C) 2014, 2015 by Thomas Poechtrager *
|
2014-05-17 23:15:15 +02:00
|
|
|
* t.poechtrager@gmail.com *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or *
|
|
|
|
* modify it under the terms of the GNU General Public License *
|
|
|
|
* as published by the Free Software Foundation; either version 2 *
|
|
|
|
* of the License, or (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This program is distributed in the hope that it will be useful, *
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
* GNU General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the Free Software *
|
|
|
|
* Foundation, Inc., *
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Debug messages can be enabled by setting 'OCDEBUG' (ENV) to >= 1.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "compat.h"
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <string>
|
|
|
|
#include <sstream>
|
|
|
|
#include <iostream>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <climits>
|
|
|
|
#include <cassert>
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "tools.h"
|
|
|
|
#include "target.h"
|
|
|
|
#include "progs.h"
|
|
|
|
|
|
|
|
using namespace tools;
|
|
|
|
using namespace target;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2015-05-03 21:59:40 +02:00
|
|
|
int unittest = 0;
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
void checkIncludePath(const char *opt, const char *path) {
|
|
|
|
#ifndef __APPLE__
|
|
|
|
constexpr const char *DangerousIncludePaths[] = { "/usr/include",
|
|
|
|
"/usr/local/include" };
|
2015-05-30 21:04:51 +02:00
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
if (!path)
|
|
|
|
return;
|
|
|
|
|
|
|
|
static bool noinccheck = !!getenv("OSXCROSS_NO_INCLUDE_PATH_WARNINGS");
|
|
|
|
|
|
|
|
if (noinccheck)
|
|
|
|
return;
|
|
|
|
|
2015-05-03 21:59:40 +02:00
|
|
|
#ifndef _WIN32
|
2015-05-02 21:49:23 +02:00
|
|
|
char buf[PATH_MAX + 1];
|
|
|
|
const char *rpath = realpath(path, buf);
|
|
|
|
|
|
|
|
if (!rpath)
|
|
|
|
rpath = path;
|
2015-05-03 21:59:40 +02:00
|
|
|
#else
|
|
|
|
const char *rpath = path;
|
|
|
|
#endif
|
2015-05-02 21:49:23 +02:00
|
|
|
|
|
|
|
for (const char *dpath : DangerousIncludePaths) {
|
|
|
|
if (!strncmp(rpath, dpath, strlen(dpath))) {
|
2015-05-03 21:59:40 +02:00
|
|
|
warn << "possibly dangerous include path specified: '" << opt << " "
|
2015-05-02 21:49:23 +02:00
|
|
|
<< path << "'";
|
|
|
|
|
|
|
|
if (strcmp(path, rpath))
|
|
|
|
warn << " (" << rpath << ")";
|
|
|
|
|
|
|
|
warn << warn.endl();
|
|
|
|
|
|
|
|
warninfo << "you can silence this warning via "
|
|
|
|
<< "'OSXCROSS_NO_INCLUDE_PATH_WARNINGS=1' (env)"
|
|
|
|
<< warninfo.endl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
(void)opt;
|
|
|
|
(void)path;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void warnExtension(const char *extension) {
|
|
|
|
static bool noextwarnings = !!getenv("OSXCROSS_NO_EXTENSION_WARNINGS");
|
|
|
|
if (noextwarnings)
|
|
|
|
return;
|
|
|
|
warn << extension << " is an osxcross extension" << warn.endl();
|
|
|
|
warninfo << "you can silence this warning via "
|
|
|
|
<< "'OSXCROSS_NO_EXTENSION_WARNINGS=1' (env)" << warninfo.endl();
|
|
|
|
}
|
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
//
|
|
|
|
// detectTarget():
|
|
|
|
// detect target and setup invocation command
|
|
|
|
//
|
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
#define PABREAK \
|
|
|
|
else target.args.push_back(arg); \
|
|
|
|
break
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
#define PAPUSHARG \
|
|
|
|
target.args.push_back(arg); \
|
|
|
|
break
|
|
|
|
|
|
|
|
#define PAPUSHARGANDVAL(splitted) \
|
|
|
|
do { \
|
|
|
|
target.args.push_back(arg); \
|
|
|
|
if (splitted && i < argc) \
|
|
|
|
target.args.push_back(argv[i]); \
|
|
|
|
} while (0); \
|
|
|
|
break
|
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
bool detectTarget(int argc, char **argv, Target &target) {
|
|
|
|
const char *cmd = argv[0];
|
|
|
|
const char *p = strrchr(cmd, '/');
|
|
|
|
size_t len;
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
if (p)
|
|
|
|
cmd = &p[1];
|
|
|
|
|
|
|
|
target.args.reserve(static_cast<size_t>(argc));
|
|
|
|
|
|
|
|
auto parseArgs = [&]()->bool {
|
|
|
|
typedef bool (*delayedfun)(Target &);
|
|
|
|
std::vector<delayedfun> delayedfuncs;
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
auto runLater = [&](delayedfun fun) {
|
|
|
|
for (auto dfun : delayedfuncs) {
|
|
|
|
if (dfun == fun)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
delayedfuncs.push_back(fun);
|
|
|
|
};
|
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
auto getVal = [&](char * arg, const char * flag, int & i)->const char * {
|
|
|
|
const char *val = arg + strlen(flag);
|
|
|
|
|
|
|
|
if (!*val) {
|
|
|
|
val = argv[++i];
|
|
|
|
|
|
|
|
if (i >= argc) {
|
2015-05-02 21:49:23 +02:00
|
|
|
err << "missing argument for '" << flag << "'" << err.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
};
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
auto installGCCArchExtensionWarning = [&]() {
|
|
|
|
runLater([](Target &t) {
|
|
|
|
if (t.targetarch.size() > 1 && t.isGCC())
|
|
|
|
warnExtension("using multiple '-arch' flags with gcc");
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
if (char *p = getenv("MACOSX_DEPLOYMENT_TARGET")) {
|
|
|
|
target.OSNum = parseOSVersion(p);
|
|
|
|
unsetenv("MACOSX_DEPLOYMENT_TARGET");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 1; i < argc; ++i) {
|
|
|
|
char *arg = argv[i];
|
|
|
|
|
|
|
|
if (arg[0] == '-') {
|
|
|
|
switch (arg[1]) {
|
|
|
|
case 'a': {
|
|
|
|
// -a
|
|
|
|
|
|
|
|
if (!strncmp(arg, "-arch", 5)) {
|
|
|
|
const char *val = getVal(arg, "-arch", i);
|
|
|
|
|
|
|
|
if (!val)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Arch arch = parseArch(val);
|
|
|
|
|
|
|
|
if (arch == Arch::unknown) {
|
2015-05-02 21:49:23 +02:00
|
|
|
warn << "'-arch': unknown architecture '" << val << "'"
|
|
|
|
<< warn.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *name = getArchName(arch);
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
if (strcmp(val, name))
|
|
|
|
warn << "'-arch': '" << val << "' != '" << name << "'"
|
|
|
|
<< warn.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
|
|
|
|
target.addArch(arch);
|
2015-05-02 21:49:23 +02:00
|
|
|
installGCCArchExtensionWarning();
|
2014-05-17 23:15:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
PABREAK;
|
|
|
|
}
|
|
|
|
case 'E': {
|
|
|
|
// -E
|
|
|
|
|
|
|
|
if (!strcmp(arg, "-E")) {
|
|
|
|
target.nocodegen = true;
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
runLater([](Target &t) {
|
2014-05-17 23:15:15 +02:00
|
|
|
if (t.targetarch.size() > 1) {
|
2015-05-02 21:49:23 +02:00
|
|
|
err << "cannot use '-E' with multiple -arch options"
|
|
|
|
<< err.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
|
|
|
target.args.push_back(arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
PABREAK;
|
|
|
|
}
|
2014-05-18 22:07:37 +02:00
|
|
|
case 'f': {
|
|
|
|
// -f
|
|
|
|
|
|
|
|
if (!strcmp(arg, "-flto") || !strncmp(arg, "-flto=", 5)) {
|
|
|
|
target.args.push_back(arg);
|
|
|
|
|
|
|
|
if (target.isClang())
|
|
|
|
continue;
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
runLater([](Target &t) {
|
2014-05-18 22:07:37 +02:00
|
|
|
if (t.targetarch.size() > 1) {
|
2015-05-02 21:49:23 +02:00
|
|
|
err << "gcc does not support '-flto' with multiple "
|
|
|
|
<< "'-arch' flags" << err.endl();
|
2014-05-18 22:07:37 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
PABREAK;
|
|
|
|
}
|
2015-05-02 21:49:23 +02:00
|
|
|
case 'c':
|
|
|
|
case 'i':
|
|
|
|
case 'I': {
|
|
|
|
// c
|
|
|
|
// i
|
|
|
|
// I
|
|
|
|
|
|
|
|
constexpr const char *OptsToCheck[] = {
|
|
|
|
"-isystem", "-icxx-isystem", "-cxx-isystem", "-I"
|
|
|
|
};
|
|
|
|
|
|
|
|
bool splitted = false;
|
|
|
|
|
|
|
|
for (const char *opt : OptsToCheck) {
|
|
|
|
if (!strncmp(arg, opt, strlen(opt))) {
|
|
|
|
int iold = i;
|
|
|
|
checkIncludePath(opt, getVal(arg, opt, i));
|
|
|
|
splitted = i > iold;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PAPUSHARGANDVAL(splitted);
|
|
|
|
}
|
2014-05-17 23:15:15 +02:00
|
|
|
case 'm': {
|
|
|
|
// -m
|
|
|
|
|
|
|
|
if (!strncmp(arg, "-mmacosx-version-min=", 21)) {
|
|
|
|
const char *val = arg + 21;
|
|
|
|
target.OSNum = parseOSVersion(val);
|
|
|
|
|
|
|
|
if (target.OSNum != val) {
|
2015-05-02 21:49:23 +02:00
|
|
|
warn << "'-mmacosx-version-min=' (" << target.OSNum.Str()
|
|
|
|
<< " != " << val << ")" << warn.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
}
|
|
|
|
} else if (!strcmp(arg, "-m16") || !strcmp(arg, "-mx32")) {
|
2015-05-02 21:49:23 +02:00
|
|
|
err << "'" << arg << "' is not supported" << err.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
return false;
|
|
|
|
} else if (!strcmp(arg, "-m32")) {
|
|
|
|
target.addArch(Arch::i386);
|
2015-05-02 21:49:23 +02:00
|
|
|
installGCCArchExtensionWarning();
|
2014-05-17 23:15:15 +02:00
|
|
|
} else if (!strcmp(arg, "-m64")) {
|
|
|
|
target.addArch(Arch::x86_64);
|
2015-05-02 21:49:23 +02:00
|
|
|
installGCCArchExtensionWarning();
|
2014-05-17 23:15:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
PABREAK;
|
|
|
|
}
|
|
|
|
case 'o': {
|
|
|
|
// -o
|
|
|
|
|
|
|
|
if (!strcmp(arg, "-oc-use-gcc-libs")) {
|
|
|
|
if (target.isGCC()) {
|
2015-05-03 21:59:40 +02:00
|
|
|
warn << "'" << arg << "' has no effect" << warn.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
target.stdlib = StdLib::libstdcxx;
|
|
|
|
target.usegcclibs = true;
|
|
|
|
} else if (!strncmp(arg, "-o", 2)) {
|
|
|
|
target.outputname = getVal(arg, "-o", i);
|
|
|
|
}
|
|
|
|
|
|
|
|
PABREAK;
|
|
|
|
}
|
|
|
|
case 's': {
|
|
|
|
// -s
|
|
|
|
|
|
|
|
if (!strncmp(arg, "-stdlib=", 8)) {
|
|
|
|
const char *val = arg + 8;
|
|
|
|
size_t i = 0;
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
if (target.isGCC()) {
|
|
|
|
runLater([](Target &) {
|
|
|
|
warnExtension("'-stdlib='");
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
}
|
2014-05-17 23:15:15 +02:00
|
|
|
|
|
|
|
for (auto stdlibname : StdLibNames) {
|
|
|
|
if (!strcmp(val, stdlibname)) {
|
|
|
|
target.stdlib = static_cast<StdLib>(i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == (sizeof(StdLibNames) / sizeof(StdLibNames[0]))) {
|
2015-05-02 21:49:23 +02:00
|
|
|
err << "value of '-stdlib=' must be ";
|
2014-05-17 23:15:15 +02:00
|
|
|
|
|
|
|
for (size_t j = 0; j < i; ++j) {
|
2015-05-02 21:49:23 +02:00
|
|
|
err << "'" << StdLibNames[j] << "'";
|
|
|
|
if (j == i - 2)
|
|
|
|
err << " or ";
|
|
|
|
else if (j < i - 2)
|
|
|
|
err << ", ";
|
2014-05-17 23:15:15 +02:00
|
|
|
}
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
err << err.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (!strncmp(arg, "-std=", 5)) {
|
|
|
|
const char *val = arg + 5;
|
|
|
|
target.langstd = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
PABREAK;
|
|
|
|
}
|
|
|
|
case 'x': {
|
2015-05-02 21:49:23 +02:00
|
|
|
if (!strncmp(arg, "-x", 2))
|
2014-05-17 23:15:15 +02:00
|
|
|
target.lang = getVal(arg, "-x", i);
|
|
|
|
|
|
|
|
PABREAK;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
target.args.push_back(arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Detect source file
|
|
|
|
target.args.push_back(arg);
|
|
|
|
|
|
|
|
const char *prevarg = "";
|
|
|
|
|
|
|
|
if (i > 1) {
|
|
|
|
prevarg = argv[i - 1];
|
|
|
|
|
|
|
|
if (prevarg[0] == '-' && strlen(prevarg) > 2 &&
|
|
|
|
strcmp(prevarg, "-MT") && strcmp(prevarg, "-MF"))
|
|
|
|
prevarg = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prevarg[0] != '-' || !strcmp(prevarg, "-c")) {
|
|
|
|
constexpr const char *badexts[] = { ".o", ".a" };
|
|
|
|
const char *ext = getFileExtension(arg);
|
|
|
|
bool b = false;
|
|
|
|
|
|
|
|
for (auto &badext : badexts) {
|
|
|
|
if (!strcmp(ext, badext)) {
|
|
|
|
b = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!b)
|
|
|
|
target.sourcefile = arg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto fun : delayedfuncs) {
|
|
|
|
if (!fun(target))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
auto checkCXXLib = [&]() {
|
2015-05-30 21:04:51 +02:00
|
|
|
if (target.compilername.size() <= 7)
|
2014-05-17 23:15:15 +02:00
|
|
|
return;
|
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
if (target.compilername.rfind("-libc++") ==
|
|
|
|
(target.compilername.size() - 7)) {
|
2014-05-17 23:15:15 +02:00
|
|
|
if (target.stdlib != StdLib::unset && target.stdlib != StdLib::libcxx) {
|
2015-05-02 21:49:23 +02:00
|
|
|
warn << "'-stdlib=" << getStdLibString(target.stdlib)
|
|
|
|
<< "' will be ignored" << warn.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
}
|
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
target.compilername.resize(target.compilername.size() - 7);
|
2014-05-17 23:15:15 +02:00
|
|
|
target.stdlib = StdLib::libcxx;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (auto *prog = program::getprog(cmd))
|
|
|
|
(*prog)(argc, argv, target);
|
|
|
|
|
|
|
|
// -> x86_64 <- -apple-darwin13
|
|
|
|
p = strchr(cmd, '-');
|
|
|
|
len = (p ? p : cmd) - cmd;
|
|
|
|
|
|
|
|
for (auto arch : ArchNames) {
|
|
|
|
++i;
|
|
|
|
|
|
|
|
if (!strncmp(cmd, arch, len)) {
|
|
|
|
target.arch = static_cast<Arch>(i - 1);
|
|
|
|
cmd += len;
|
|
|
|
|
|
|
|
if (*cmd++ != '-')
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (strncmp(cmd, "apple-", 6))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
cmd += 6;
|
|
|
|
|
|
|
|
if (strncmp(cmd, "darwin", 6))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!(p = strchr(cmd, '-')))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
target.target = std::string(cmd, p - cmd);
|
2015-05-30 21:04:51 +02:00
|
|
|
target.compilername = &p[1];
|
2014-05-17 23:15:15 +02:00
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
if (target.compilername == "cc")
|
|
|
|
target.compilername = getDefaultCompiler();
|
|
|
|
else if (target.compilername == "c++")
|
|
|
|
target.compilername = getDefaultCXXCompiler();
|
|
|
|
else if (auto *prog = program::getprog(target.compilername))
|
2014-05-17 23:15:15 +02:00
|
|
|
(*prog)(argc, argv, target);
|
|
|
|
|
|
|
|
if (target.target != getDefaultTarget()) {
|
2015-05-02 21:49:23 +02:00
|
|
|
warn << "target mismatch (" << target.target
|
|
|
|
<< " != " << getDefaultTarget() << ")" << warn.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!parseArgs())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
checkCXXLib();
|
|
|
|
return target.setup();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(cmd, "o32", 3))
|
|
|
|
target.arch = Arch::i386;
|
2014-05-18 22:07:37 +02:00
|
|
|
else if (!strncmp(cmd, "o64h", 4))
|
|
|
|
target.arch = Arch::x86_64h;
|
2014-05-17 23:15:15 +02:00
|
|
|
else if (!strncmp(cmd, "o64", 3))
|
|
|
|
target.arch = Arch::x86_64;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
|
2014-09-27 10:07:15 +02:00
|
|
|
if (const char *p = strchr(cmd, '-'))
|
2015-05-30 21:04:51 +02:00
|
|
|
target.compilername = &cmd[p - cmd + 1];
|
2014-05-17 23:15:15 +02:00
|
|
|
|
|
|
|
if (!parseArgs())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
checkCXXLib();
|
|
|
|
return target.setup();
|
|
|
|
}
|
|
|
|
|
2014-05-18 22:07:37 +02:00
|
|
|
//
|
|
|
|
// generateMultiArchObjectFile():
|
|
|
|
// support multiple -arch flags with gcc
|
|
|
|
// and clang + -oc-use-gcc-libs
|
|
|
|
//
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
void generateMultiArchObjectFile(int &rc, int argc, char **argv, Target &target,
|
|
|
|
int debug) {
|
2014-05-18 22:07:37 +02:00
|
|
|
#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 {
|
2015-05-02 21:49:23 +02:00
|
|
|
if (f)
|
|
|
|
warn << "source filename detection failed (using a.out)" << warn.endl();
|
2014-05-18 22:07:37 +02:00
|
|
|
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;
|
|
|
|
|
2014-06-20 14:16:57 +02:00
|
|
|
clear(obj);
|
2014-05-18 22:07:37 +02:00
|
|
|
obj << "/tmp/" << getNanoSeconds() << "_" << outputname << "_" << archname;
|
|
|
|
|
|
|
|
objs.push_back(obj.str());
|
|
|
|
pid = fork();
|
|
|
|
|
|
|
|
if (pid > 0) {
|
|
|
|
int status = 1;
|
|
|
|
|
|
|
|
if (wait(&status) == -1) {
|
2015-05-02 21:49:23 +02:00
|
|
|
err << "wait() failed" << err.endl();
|
2014-05-18 22:07:37 +02:00
|
|
|
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) {
|
2015-05-02 21:49:23 +02:00
|
|
|
dbg << "[" << num << "/" << target.targetarch.size() << "] [compiling] "
|
|
|
|
<< archname << dbg.endl();
|
2014-05-18 22:07:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
compile = true;
|
|
|
|
break;
|
|
|
|
} else {
|
2015-05-02 21:49:23 +02:00
|
|
|
err << "fork() failed" << err.endl();
|
2014-05-18 22:07:37 +02:00
|
|
|
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";
|
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
if (!getPathOfCommand(lipo.c_str(), path)) {
|
2014-05-18 22:07:37 +02:00
|
|
|
lipo = "lipo";
|
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
if (!getPathOfCommand(lipo.c_str(), path)) {
|
2015-05-02 21:49:23 +02:00
|
|
|
err << "cannot find lipo binary" << err.endl();
|
2014-05-18 22:07:37 +02:00
|
|
|
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;
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
if (debug)
|
|
|
|
dbg << "[lipo] <-- " << cmd << dbg.endl();
|
2014-05-18 22:07:37 +02:00
|
|
|
|
2015-05-03 21:59:40 +02:00
|
|
|
if (unittest == 2) {
|
|
|
|
rc = 0;
|
|
|
|
} else {
|
|
|
|
rc = system(cmd.c_str());
|
|
|
|
rc = WEXITSTATUS(rc);
|
|
|
|
}
|
2014-05-18 22:07:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!compile)
|
|
|
|
cleanup();
|
|
|
|
#else
|
|
|
|
(void)rc;
|
|
|
|
(void)argc;
|
|
|
|
(void)argv;
|
|
|
|
(void)target;
|
|
|
|
(void)debug;
|
2015-05-02 21:49:23 +02:00
|
|
|
err << __func__ << " not supported" << err.endl();
|
2014-05-18 22:07:37 +02:00
|
|
|
rc = 1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
} // unnamed namespace
|
|
|
|
|
|
|
|
//
|
|
|
|
// Main routine
|
|
|
|
//
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
char bbuf[sizeof(benchmark)];
|
|
|
|
auto b = new (bbuf) benchmark;
|
|
|
|
Target target;
|
|
|
|
char **cargs = nullptr;
|
|
|
|
int debug = 0;
|
|
|
|
int rc = -1;
|
|
|
|
|
2015-05-03 21:59:40 +02:00
|
|
|
if (char *p = getenv("OCDEBUG"))
|
|
|
|
debug = atoi(p);
|
|
|
|
|
|
|
|
if (char *p = getenv("OSXCROSS_UNIT_TEST"))
|
|
|
|
unittest = atoi(p);
|
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
if (!detectTarget(argc, argv, target)) {
|
2015-05-02 21:49:23 +02:00
|
|
|
err << "while detecting target" << err.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
b->halt();
|
|
|
|
|
|
|
|
if (debug >= 2) {
|
2015-05-02 21:49:23 +02:00
|
|
|
dbg << "detected target triple: " << target.getTriple() << dbg.endl();
|
2015-05-30 21:04:51 +02:00
|
|
|
dbg << "detected compiler: " << target.compilername << dbg.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
dbg << "detected stdlib: " << getStdLibString(target.stdlib)
|
|
|
|
<< dbg.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
|
|
|
|
if (debug >= 3) {
|
2015-05-02 21:49:23 +02:00
|
|
|
dbg << "detected source file: "
|
|
|
|
<< (target.sourcefile ? target.sourcefile : "-") << dbg.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
dbg << "detected language: " << target.getLangName() << dbg.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
b->resume();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
concatEnvVariable("COMPILER_PATH", target.execpath);
|
|
|
|
|
2014-05-18 22:07:37 +02:00
|
|
|
if (target.targetarch.size() > 1 && (target.usegcclibs || target.isGCC()))
|
|
|
|
generateMultiArchObjectFile(rc, argc, argv, target, debug);
|
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
auto printCommand = [&]() {
|
|
|
|
std::string in;
|
|
|
|
std::string out;
|
|
|
|
|
|
|
|
for (int i = 0; i < argc; ++i) {
|
|
|
|
in += argv[i];
|
|
|
|
in += " ";
|
|
|
|
}
|
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
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];
|
2014-05-17 23:15:15 +02:00
|
|
|
out += " ";
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto &arg : target.args) {
|
|
|
|
out += arg;
|
|
|
|
out += " ";
|
|
|
|
}
|
|
|
|
|
2015-05-03 21:59:40 +02:00
|
|
|
if (!unittest)
|
|
|
|
dbg << "--> " << in << dbg.endl();
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
dbg << "<-- " << out << dbg.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
if (rc == -1) {
|
|
|
|
cargs = new char *[target.fargs.size() + target.args.size() + 1];
|
|
|
|
size_t i = 0;
|
|
|
|
|
2014-09-27 10:07:15 +02:00
|
|
|
for (auto &arg : target.fargs)
|
2014-05-17 23:15:15 +02:00
|
|
|
cargs[i++] = const_cast<char *>(arg.c_str());
|
|
|
|
|
2014-09-27 10:07:15 +02:00
|
|
|
for (auto &arg : target.args)
|
2014-05-17 23:15:15 +02:00
|
|
|
cargs[i++] = const_cast<char *>(arg.c_str());
|
|
|
|
|
|
|
|
cargs[i] = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
time_type diff = b->getDiff();
|
|
|
|
|
|
|
|
if (rc == -1)
|
|
|
|
printCommand();
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
dbg << "=== time spent in wrapper: " << diff / 1000000.0 << " ms"
|
|
|
|
<< dbg.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
}
|
|
|
|
|
2015-05-03 21:59:40 +02:00
|
|
|
if (unittest == 2)
|
|
|
|
return 0;
|
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
if (rc == -1 && execvp(target.compilerpath.c_str(), cargs)) {
|
2015-05-02 21:49:23 +02:00
|
|
|
err << "invoking compiler failed" << err.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
|
|
|
|
if (!debug)
|
|
|
|
printCommand();
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|