diff --git a/wrapper/Makefile b/wrapper/Makefile index de59a58..3350569 100644 --- a/wrapper/Makefile +++ b/wrapper/Makefile @@ -9,7 +9,9 @@ OSXCROSS_LINKER_VERSION ?= 134.9 OSXCROSS_LIBLTO_PATH ?= OSXCROSS_CXXFLAGS ?= -override CXXFLAGS=-std=c++0x -Wall -Wextra -pedantic -I. -O$(OPTIMIZE) -g +override CXXFLAGS=-std=c++0x -Wall -Wextra -pedantic +override CXXFLAGS+=-Wno-missing-field-initializers +override CXXFLAGS+=-I. -O$(OPTIMIZE) -g ifeq ($(LTO), 1) override CXXFLAGS+=-flto @@ -43,7 +45,8 @@ SRCS= \ programs/osxcross-conf.cpp \ programs/osxcross-cmp.cpp \ programs/sw_vers.cpp \ - programs/pkg-config.cpp + programs/pkg-config.cpp \ + programs/xcrun.cpp OBJS=$(subst .cpp,.o,$(SRCS)) diff --git a/wrapper/build.sh b/wrapper/build.sh index 7ff4644..a673e98 100755 --- a/wrapper/build.sh +++ b/wrapper/build.sh @@ -149,6 +149,7 @@ create_wrapper_link pkg-config if [ "$PLATFORM" != "Darwin" ]; then create_wrapper_link sw_vers 1 create_wrapper_link dsymutil 1 + create_wrapper_link xcrun 1 fi popd &>/dev/null diff --git a/wrapper/programs/xcrun.cpp b/wrapper/programs/xcrun.cpp new file mode 100644 index 0000000..24ce0e6 --- /dev/null +++ b/wrapper/programs/xcrun.cpp @@ -0,0 +1,207 @@ +/*********************************************************************** + * OSXCross Compiler Wrapper * + * Copyright (C) 2014, 2015 by Thomas Poechtrager * + * 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. * + ***********************************************************************/ + +#include "proginc.h" + +#ifndef _WIN32 +#include +#endif + +using namespace tools; +using namespace target; + +namespace program { + +static bool showCommand = false; + +bool getSDKPath(Target &target, std::string &SDKPath) { + if (!target.getSDKPath(SDKPath)) { + err << "xcrun: cannot find MacOSX SDK" << err.endl(); + return false; + } + return true; +} + +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; + + if (!fileExists(toolpath.c_str())) { + // Fall back to system executables so 'xcrun git status' etc. works. + toolpath.clear(); + + if (realPath(tool, toolpath)) + return true; + + err << "xcrun: cannot find '" << tool << "' executable" << err.endl(); + return false; + } + + return true; +} + +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 **) { + 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(); + return 1; + } + return 0; +} + +int log(Target&, char**) { + showCommand = true; + return 0; +} + +int find(Target &target, char **argv) { + if (argv[1]) + return 1; + std::string toolpath; + if (!getToolPath(target, toolpath, argv[0])) + return 1; + std::cout << toolpath << std::endl; + return 0; +} + +int run(Target &target, char **argv) { + std::string toolpath; + std::string command; + if (!getToolPath(target, toolpath, argv[0])) + exit(1); // Should never return. + 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]; + if (i != args.size() - 2) + std::cout << " "; + } + 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 **) { + std::string SDKPath; + if (!getSDKPath(target, SDKPath)) + return 1; + std::cout << SDKPath << std::endl; + return 0; +} + +int showSDKVersion(Target &target, char **) { + std::cout << target.getSDKOSNum().shortStr() << std::endl; + return 0; +} + +int xcrun(int argc, char **argv, Target &target) { + if (getenv("xcrun_log")) + showCommand = true; + + constexpr const char *ENVVARS[] = { + "DEVELOPER_DIR", "SDKROOT", "TOOLCHAINS", + "xcrun_verbose" + }; + + for (const char *evar : ENVVARS) { + if (getenv(evar)) { + warn << "xcrun: ignoring environment variable '" << evar << "'" + << warn.endl(); + } + } + + auto dummy = [](Target&, char**) { return 0; }; + + ArgParser argParser = {{ + {"h", help}, + {"help", help}, + {"version", version}, + {"v", dummy}, + {"verbose", dummy}, + {"k", dummy}, + {"kill-cache", dummy}, + {"n", dummy}, + {"no-cache", dummy}, + {"sdk", sdk, 1}, + {"toolchain", dummy, 1}, + {"l", log }, + {"log", log}, + {"f", find, 1}, + {"find", find, 1}, + {"r", run, 1}, + {"run", run, 1}, + {"show-sdk-path", showSDKPath}, + {"show-sdk-version", showSDKVersion} + }}; + + int retVal = 1; + + for (int i = 1; i < argc; ++i) { + auto b = argParser.parseArg(argc, argv, i); + + if (!b) { + if (argv[i][0] == '-') { + err << "xcrun: unknown argument: '" << argv[i] << "'" << err.endl(); + retVal = 2; + break; + } + + run(target, &argv[i]); + } + + retVal = b->fun(target, &argv[i + 1]); + + if (retVal != 0) + break; + + i += b->numArgs; + } + + return retVal; +} + +} // namespace program diff --git a/wrapper/progs.h b/wrapper/progs.h index d62cbfb..9d1b660 100644 --- a/wrapper/progs.h +++ b/wrapper/progs.h @@ -75,6 +75,7 @@ private: }; int sw_vers(int argc, char **argv, target::Target &target); +int xcrun(int argc, char **argv, Target &target); namespace osxcross { int version(); @@ -87,6 +88,7 @@ int pkg_config(int argc, char **argv, Target &target); static int dummy() { return 0; } constexpr prog programs[] = { { "sw_vers", sw_vers }, + { "xcrun", xcrun }, { "dsymutil", dummy }, { "osxcross", osxcross::version }, { "osxcross-env", osxcross::env }, diff --git a/wrapper/target.cpp b/wrapper/target.cpp index ea2ef05..8eef5fe 100644 --- a/wrapper/target.cpp +++ b/wrapper/target.cpp @@ -229,6 +229,15 @@ bool Target::isCXX11orNewer() const { return false; } +const std::string &Target::getDefaultTriple(std::string &triple) const { + triple = getArchName(Arch::x86_64); + triple += "-"; + triple += getDefaultVendor(); + triple += "-"; + triple += getDefaultTarget(); + return triple; +} + void Target::setCompilerPath() { if (isGCC()) { compilerpath = execpath; diff --git a/wrapper/target.h b/wrapper/target.h index 8682240..c2cec9c 100644 --- a/wrapper/target.h +++ b/wrapper/target.h @@ -73,9 +73,10 @@ constexpr OSVersion getDefaultMinTarget() { return OSVersion(); } struct Target { Target() - : vendor(getDefaultVendor()), target(getDefaultTarget()), - stdlib(StdLib::unset), usegcclibs(), nocodegen(), - compilername(getDefaultCompiler()), lang(), langstd(), sourcefile(), + : vendor(getDefaultVendor()), arch(Arch::x86_64), + target(getDefaultTarget()), stdlib(StdLib::unset), usegcclibs(), + nocodegen(), compilername(getDefaultCompiler()), lang(), langstd(), + sourcefile(), outputname() { if (!getExecutablePath(execpath, sizeof(execpath))) abort(); @@ -131,6 +132,7 @@ struct Target { const char *getLangName(); bool isCXX11orNewer() const; + const std::string &getDefaultTriple(std::string &triple) const; const std::string &getTriple() const { return triple; } void setCompilerPath(); diff --git a/wrapper/tools.h b/wrapper/tools.h index ddf87ee..b53c22f 100644 --- a/wrapper/tools.h +++ b/wrapper/tools.h @@ -163,6 +163,43 @@ inline const char *getFileExtension(const std::string &file) { return getFileExtension(file.c_str()); } +// +// Argument Parsing +// + +template 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; + } +}; + // // Time //