#include <string>
#include <vector>
#include <iostream>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <string.h>
#include <algorithm>
using std::string;
using std::vector;
string GetPath(const char* argv0) {
char* path_c = realpath(argv0, nullptr);
string path = string(path_c);
free(path_c);
return path;
}
string FindJiriRoot(const string& self_path) {
string path = self_path;
while (true) {
size_t pos = path.rfind('/');
if (pos == string::npos) {
return "";
}
string basedir = path.substr(0, pos + 1);
string trial = basedir + ".jiri_root";
struct stat stat_buf;
int status = stat(trial.c_str(), &stat_buf);
if (status == 0) {
return basedir;
}
path = path.substr(0, pos);
}
}
string GetCmd(const char* argv0) {
string cmd = argv0;
size_t pos = cmd.rfind('/');
if (pos != string::npos) {
cmd = cmd.substr(pos + 1);
}
return cmd;
}
string TargetTriple(const string& cmd) {
size_t pos = cmd.rfind('-');
if (pos == string::npos) {
return "";
}
string triple = cmd.substr(0, pos);
if (triple.find("x86-64") == 0) {
triple[3] = '_';
}
return triple;
}
string SysrootPath(const string& self_path) {
const string out_dir_name = "out/";
size_t pos = self_path.find(out_dir_name);
if (pos != string::npos) {
size_t end_pos = self_path.find("/", pos+out_dir_name.length() + 1);
if (end_pos != string::npos) {
string sysroot_path = self_path.substr(0, end_pos) + "/sysroot";
struct stat stat_buf;
int status = stat(sysroot_path.c_str(), &stat_buf);
if (status == 0) {
return sysroot_path;
}
}
}
return "";
}
string HostDouble() {
struct utsname name;
int status = uname(&name);
if (status != 0) {
return "";
}
string dbl = string(name.machine) + "-" + string(name.sysname);
std::transform(dbl.begin(), dbl.end(), dbl.begin(), ::tolower);
return dbl;
}
string InferTool(const string& cmd) {
size_t pos = cmd.rfind('-');
string base;
if (pos != string::npos) {
base = cmd.substr(pos + 1);
} else {
base = cmd;
}
if (base == "cc" || base == "gcc") {
return "clang";
} else if (base == "ar") {
return "llvm-ar";
}
return base;
}
vector<string> CollectArgs(int argc, char** argv) {
vector<string> result;
for (int i = 0; i < argc; i++) {
result.push_back(argv[i]);
}
return result;
}
int DoExecv(const string& cmd, vector<string>& args) {
vector<const char*> argvec;
for (auto& it : args) {
argvec.push_back(it.c_str());
}
argvec.push_back(nullptr);
char* const* argv = const_cast<char* const*>(argvec.data());
return execv(cmd.c_str(), argv);
}
void Die(const string& message) {
std::cerr << message << std::endl;
exit(1);
}
int main(int argc, char** argv) {
string self_path = GetPath(argv[0]);
string root = FindJiriRoot(self_path);
if (root.empty()) {
Die("Can't find .jiri_root in any parent of " + self_path);
}
string host = HostDouble();
if (host.empty()) {
Die("Can't detect host (uname failed)");
}
string cmd = GetCmd(argv[0]);
string tool = InferTool(cmd);
string triple = TargetTriple(cmd);
vector<string> args = CollectArgs(argc, argv);
string newcmd = root + "buildtools/toolchain/clang+llvm-" + host + "/bin/" + tool;
string sysroot = SysrootPath(self_path);
if (sysroot.empty()) {
Die("Can't find sysroot from wrapper path");
}
vector<string> newargs;
newargs.push_back(newcmd);
if (tool != "llvm-ar") {
newargs.push_back("-target");
newargs.push_back(triple);
newargs.push_back("--sysroot=" + sysroot);
}
for (auto it = args.begin() + 1; it != args.end(); ++it) {
newargs.push_back(*it);
}
int status = DoExecv(newcmd, newargs);
if (status != 0) {
Die("error invoking " + newcmd + ": " + strerror(errno));
}
return 0;
}