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. *
|
|
|
|
***********************************************************************/
|
|
|
|
|
2015-05-30 21:04:51 +02:00
|
|
|
struct stat;
|
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
namespace tools {
|
|
|
|
|
2014-06-20 14:16:57 +02:00
|
|
|
//
|
|
|
|
// Misc helper tools
|
|
|
|
//
|
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
typedef std::vector<std::string> string_vector;
|
|
|
|
|
2015-08-22 23:15:27 +02:00
|
|
|
static inline void clear(std::stringstream &sstr) {
|
2014-06-20 14:16:57 +02:00
|
|
|
sstr.clear();
|
|
|
|
sstr.str(std::string());
|
|
|
|
}
|
|
|
|
|
2015-08-22 23:15:27 +02:00
|
|
|
static inline bool endsWith(std::string const &str, std::string const &end) {
|
|
|
|
if (end.size() > str.size())
|
|
|
|
return false;
|
|
|
|
return std::equal(end.rbegin(), end.rend(), str.rbegin());
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t constexpr slen(const char *str) {
|
|
|
|
return *str ? 1 + slen(str + 1) : 0;
|
|
|
|
}
|
|
|
|
|
2015-05-02 21:49:23 +02:00
|
|
|
//
|
|
|
|
// Terminal text colors
|
|
|
|
//
|
|
|
|
|
|
|
|
bool isTerminal();
|
|
|
|
|
|
|
|
// http://stackoverflow.com/a/17469726
|
|
|
|
|
|
|
|
enum ColorCode {
|
|
|
|
FG_DEFAULT = 39,
|
|
|
|
FG_BLACK = 30,
|
|
|
|
FG_RED = 31,
|
|
|
|
FG_GREEN = 32,
|
|
|
|
FG_YELLOW = 33,
|
|
|
|
FG_BLUE = 34,
|
|
|
|
FG_MAGENTA = 35,
|
|
|
|
FG_CYAN = 36,
|
|
|
|
FG_LIGHT_GRAY = 37,
|
|
|
|
FG_DARK_GRAY = 90,
|
|
|
|
FG_LIGHT_RED = 91,
|
|
|
|
FG_LIGHT_GREEN = 92,
|
|
|
|
FG_LIGHT_YELLOW = 93,
|
|
|
|
FG_LIGHT_BLUE = 94,
|
|
|
|
FG_LIGHT_MAGENTA = 95,
|
|
|
|
FG_LIGHT_CYAN = 96,
|
|
|
|
FG_WHITE = 97,
|
|
|
|
BG_RED = 41,
|
|
|
|
BG_GREEN = 42,
|
|
|
|
BG_BLUE = 44,
|
|
|
|
BG_DEFAULT = 49
|
|
|
|
};
|
|
|
|
|
|
|
|
class Color {
|
|
|
|
ColorCode cc;
|
|
|
|
public:
|
|
|
|
Color(ColorCode cc) : cc(cc) {}
|
|
|
|
friend std::ostream &
|
|
|
|
operator<<(std::ostream &os, const Color &color) {
|
|
|
|
if (isTerminal())
|
|
|
|
return os << "\033[" << color.cc << "m";
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//
|
|
|
|
// Error message helper
|
|
|
|
//
|
|
|
|
|
|
|
|
static class Message {
|
|
|
|
private:
|
|
|
|
const char *msg;
|
|
|
|
Color color;
|
|
|
|
std::ostream &os;
|
|
|
|
bool printprefix;
|
|
|
|
public:
|
|
|
|
static constexpr char endl() { return '\n'; }
|
|
|
|
bool isendl(char c) { return c == '\n'; }
|
|
|
|
template<typename T>
|
|
|
|
bool isendl(T&&) { return false; }
|
|
|
|
template<typename T>
|
|
|
|
Message &operator<<(T &&v) {
|
|
|
|
if (printprefix) {
|
|
|
|
os << Color(FG_DARK_GRAY) << "osxcross: " << color << msg << ": "
|
|
|
|
<< Color(FG_DEFAULT);
|
|
|
|
printprefix = false;
|
|
|
|
}
|
|
|
|
if (isendl(v)) {
|
|
|
|
printprefix = true;
|
|
|
|
os << std::endl;
|
|
|
|
} else {
|
|
|
|
os << v;
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
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),
|
2015-06-27 19:01:56 +02:00
|
|
|
info("info", FG_LIGHT_MAGENTA), warninfo("info", FG_LIGHT_MAGENTA);
|
2015-05-02 21:49:23 +02:00
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
//
|
|
|
|
// Executable path
|
|
|
|
//
|
|
|
|
|
|
|
|
char *getExecutablePath(char *buf, size_t len);
|
|
|
|
const std::string &getParentProcessName();
|
|
|
|
std::string &fixPathDiv(std::string &path);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Environment
|
|
|
|
//
|
|
|
|
|
2014-12-24 10:52:24 +01:00
|
|
|
void concatEnvVariable(const char *var, const std::string &val);
|
2015-07-19 22:28:10 +02:00
|
|
|
std::string &escapePath(const std::string &path, std::string &escapedpath);
|
|
|
|
void splitPath(const char *path, std::vector<std::string> &result);
|
|
|
|
std::string joinPath(const std::vector<std::string> &path);
|
|
|
|
bool hasPath(const std::vector<std::string> &path, const char *find);
|
2014-05-17 23:15:15 +02:00
|
|
|
|
|
|
|
//
|
2014-06-20 14:16:57 +02:00
|
|
|
// Files and directories
|
2014-05-17 23:15:15 +02:00
|
|
|
//
|
|
|
|
|
|
|
|
std::string *getFileContent(const std::string &file, std::string &content);
|
|
|
|
bool writeFileContent(const std::string &file, const std::string &content);
|
|
|
|
|
|
|
|
bool fileExists(const std::string &dir);
|
|
|
|
bool dirExists(const std::string &dir);
|
|
|
|
typedef bool (*listfilescallback)(const char *file);
|
|
|
|
bool isDirectory(const char *file, const char *prefix);
|
|
|
|
bool listFiles(const char *dir, std::vector<std::string> *files,
|
|
|
|
listfilescallback cmp);
|
|
|
|
|
|
|
|
typedef bool (*realpathcmp)(const char *file, const struct stat &st);
|
|
|
|
bool isExecutable(const char *f, const struct stat &);
|
2015-05-30 21:04:51 +02:00
|
|
|
bool ignoreCCACHE(const char *f, const struct stat &);
|
|
|
|
bool realPath(const char *file, std::string &result,
|
|
|
|
realpathcmp cmp1 = nullptr, realpathcmp cmp2 = nullptr);
|
|
|
|
bool getPathOfCommand(const char *command, std::string &result,
|
|
|
|
realpathcmp cmp = nullptr);
|
|
|
|
|
|
|
|
void stripFileName(std::string &path);
|
2014-05-17 23:15:15 +02:00
|
|
|
|
|
|
|
const char *getFileName(const char *file);
|
|
|
|
const char *getFileExtension(const char *file);
|
|
|
|
|
|
|
|
inline const char *getFileName(const std::string &file) {
|
|
|
|
return getFileName(file.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const char *getFileExtension(const std::string &file) {
|
|
|
|
return getFileExtension(file.c_str());
|
|
|
|
}
|
|
|
|
|
2015-06-21 11:46:01 +02:00
|
|
|
//
|
|
|
|
// Argument Parsing
|
|
|
|
//
|
|
|
|
|
|
|
|
template <typename T, size_t size = 0> struct ArgParser {
|
|
|
|
const struct Bind {
|
|
|
|
const char *name;
|
|
|
|
T fun;
|
|
|
|
int numArgs;
|
|
|
|
} binds[size];
|
|
|
|
|
|
|
|
const Bind *parseArg(int argc, char **argv, const int numArg = 1) {
|
|
|
|
const char *arg = argv[numArg];
|
|
|
|
|
|
|
|
if (*arg != '-')
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
while (*arg && *arg == '-')
|
|
|
|
++arg;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < size; ++i) {
|
|
|
|
const Bind &bind = binds[i];
|
|
|
|
|
|
|
|
if (!strcmp(arg, bind.name)) {
|
|
|
|
if (argc - numArg <= bind.numArgs) {
|
|
|
|
err << "too few arguments for '-" << bind.name << "'" << err.endl();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &bind;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-08-31 21:02:38 +02:00
|
|
|
//
|
|
|
|
// Shell Commands
|
|
|
|
//
|
|
|
|
|
|
|
|
constexpr size_t RUNCOMMAND_ERROR = -1;
|
|
|
|
|
|
|
|
size_t runcommand(const char *command, char *buf, size_t len);
|
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
//
|
|
|
|
// Time
|
|
|
|
//
|
|
|
|
|
|
|
|
typedef unsigned long long time_type;
|
|
|
|
time_type getNanoSeconds();
|
|
|
|
|
|
|
|
class benchmark {
|
|
|
|
public:
|
|
|
|
benchmark() { s = getTime(); }
|
|
|
|
|
|
|
|
time_type getDiff() { return getTime() - s; }
|
|
|
|
|
|
|
|
void halt() { h = getTime(); }
|
|
|
|
void resume() { s += getTime() - h; }
|
|
|
|
|
|
|
|
~benchmark() {
|
|
|
|
time_type diff = getTime() - s;
|
2015-05-02 21:49:23 +02:00
|
|
|
dbg << "took: " << diff / 1000000.0 << " ms" << dbg.endl();
|
2014-05-17 23:15:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
__attribute__((always_inline)) time_type getTime() {
|
|
|
|
return getNanoSeconds();
|
|
|
|
}
|
|
|
|
|
|
|
|
time_type h;
|
|
|
|
time_type s;
|
|
|
|
};
|
|
|
|
|
|
|
|
//
|
|
|
|
// OSVersion
|
|
|
|
//
|
|
|
|
|
|
|
|
#undef major
|
|
|
|
#undef minor
|
|
|
|
#undef patch
|
|
|
|
|
|
|
|
struct OSVersion {
|
|
|
|
constexpr OSVersion(int major, int minor, int patch = 0)
|
|
|
|
: major(major), minor(minor), patch(patch) {}
|
|
|
|
constexpr OSVersion() : major(), minor(), patch() {}
|
|
|
|
|
|
|
|
constexpr int Num() const {
|
|
|
|
return major * 10000 + minor * 100 + patch;
|
|
|
|
};
|
|
|
|
|
|
|
|
constexpr bool operator>(const OSVersion &OSNum) const {
|
|
|
|
return Num() > OSNum.Num();
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool operator>=(const OSVersion &OSNum) const {
|
|
|
|
return Num() >= OSNum.Num();
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool operator<(const OSVersion &OSNum) const {
|
|
|
|
return Num() < OSNum.Num();
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool operator<=(const OSVersion &OSNum) const {
|
|
|
|
return Num() <= OSNum.Num();
|
|
|
|
}
|
|
|
|
|
2014-06-20 14:16:57 +02:00
|
|
|
constexpr bool operator==(const OSVersion &OSNum) const {
|
|
|
|
return Num() == OSNum.Num();
|
|
|
|
}
|
|
|
|
|
2014-05-17 23:15:15 +02:00
|
|
|
constexpr bool operator!=(const OSVersion &OSNum) const {
|
|
|
|
return Num() != OSNum.Num();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const char *val) const {
|
|
|
|
size_t c = 0;
|
|
|
|
const char *p = val;
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
if (*p++ == '.')
|
|
|
|
++c;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case 1:
|
|
|
|
return shortStr() != val;
|
|
|
|
case 2:
|
|
|
|
return Str() != val;
|
|
|
|
default:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Str() const {
|
|
|
|
std::stringstream tmp;
|
|
|
|
tmp << major << "." << minor << "." << patch;
|
|
|
|
return tmp.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string shortStr() const {
|
|
|
|
std::stringstream tmp;
|
|
|
|
tmp << major << "." << minor;
|
|
|
|
return tmp.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
int major;
|
|
|
|
int minor;
|
|
|
|
int patch;
|
|
|
|
};
|
|
|
|
|
|
|
|
static_assert(OSVersion(10, 6) != OSVersion(10, 5), "");
|
|
|
|
|
|
|
|
OSVersion parseOSVersion(const char *OSVer);
|
|
|
|
|
|
|
|
typedef OSVersion GCCVersion;
|
2015-08-31 21:02:38 +02:00
|
|
|
static const auto &parseGCCVersion = parseOSVersion;
|
2014-05-17 23:15:15 +02:00
|
|
|
|
|
|
|
typedef OSVersion ClangVersion;
|
2015-08-31 21:02:38 +02:00
|
|
|
static const auto &parseClangVersion = parseOSVersion;
|
|
|
|
|
|
|
|
typedef OSVersion LLVMVersion;
|
|
|
|
static const auto &parseLLVMVersion = parseOSVersion;
|
2014-05-17 23:15:15 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// OS Compat
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
int setenv(const char *name, const char *value, int overwrite);
|
|
|
|
int unsetenv(const char *name);
|
2014-09-27 10:07:15 +02:00
|
|
|
constexpr char PATHDIV = '\\';
|
|
|
|
#else
|
|
|
|
constexpr char PATHDIV = '/';
|
2014-05-17 23:15:15 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
|
|
// Arch
|
|
|
|
//
|
|
|
|
|
|
|
|
enum Arch {
|
|
|
|
armv4t,
|
|
|
|
armv5,
|
|
|
|
armv6,
|
|
|
|
armv7,
|
|
|
|
armv7f,
|
|
|
|
armv7k,
|
|
|
|
armv7s,
|
|
|
|
armv6m,
|
|
|
|
armv7m,
|
|
|
|
armv7em,
|
|
|
|
armv8,
|
|
|
|
arm64,
|
|
|
|
arm64v8,
|
|
|
|
i386,
|
|
|
|
i486,
|
|
|
|
i586,
|
|
|
|
i686,
|
|
|
|
x86_64,
|
|
|
|
x86_64h, // Haswell
|
|
|
|
ppc,
|
|
|
|
ppc64,
|
|
|
|
unknown
|
|
|
|
};
|
|
|
|
|
|
|
|
constexpr const char *ArchNames[] = {
|
|
|
|
"armv4t", "armv5", "armv6", "armv7", "armv7f", "armv7k", "armv7s",
|
|
|
|
"amrv6m", "armv7m", "armv7em", "armv8", "arm64", "arm64v8", "i386",
|
|
|
|
"i486", "i586", "i686", "x86_64", "x86_64h", "ppc", "ppc64",
|
|
|
|
"unknown"
|
|
|
|
};
|
|
|
|
|
|
|
|
constexpr const char *getArchName(Arch arch) { return ArchNames[arch]; }
|
|
|
|
|
|
|
|
inline Arch parseArch(const char *arch) {
|
|
|
|
size_t i = 0;
|
|
|
|
for (auto archname : ArchNames) {
|
|
|
|
if (!strcmp(arch, archname)) {
|
|
|
|
return static_cast<Arch>(i);
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
return Arch::unknown;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
2014-06-20 14:16:57 +02:00
|
|
|
// Standard Library
|
2014-05-17 23:15:15 +02:00
|
|
|
//
|
|
|
|
|
|
|
|
enum StdLib {
|
|
|
|
unset,
|
|
|
|
libcxx,
|
|
|
|
libstdcxx
|
|
|
|
};
|
|
|
|
|
|
|
|
constexpr const char *StdLibNames[] = { "default", "libc++", "libstdc++" };
|
|
|
|
|
|
|
|
constexpr const char *getStdLibString(StdLib stdlib) {
|
|
|
|
return StdLibNames[stdlib];
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace tools
|