From ad47efba7037b5baae760d36a430d35f67fbbb46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Wed, 26 Sep 2018 13:51:07 +0300 Subject: [PATCH] Implement clang-target-wrapper as an executable for windows This allows non-msys build systems to use the triplet prefixed compiler frontends on windows. Keep the old shell script version as well, for easier hackability on unix platforms. --- install-wrappers.sh | 17 +++- wrappers/clang-target-wrapper.c | 154 +++++++++++++++++++++++++++++++ wrappers/clang-target-wrapper.sh | 1 + 3 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 wrappers/clang-target-wrapper.c diff --git a/install-wrappers.sh b/install-wrappers.sh index 2369742..1af479d 100755 --- a/install-wrappers.sh +++ b/install-wrappers.sh @@ -15,13 +15,28 @@ if [ -n "$HOST" ] && [ -z "$CC" ]; then fi : ${CC:=cc} +case $(uname) in +MINGW*) + EXEEXT=.exe + ;; +esac + mkdir -p $PREFIX/bin cp wrappers/*-wrapper.sh $PREFIX/bin $CC wrappers/change-pe-arch.c -o $PREFIX/bin/change-pe-arch$EXEEXT +$CC wrappers/clang-target-wrapper.c -o $PREFIX/bin/clang-target-wrapper$EXEEXT -O2 -Wl,-s +if [ -n "$EXEEXT" ]; then + # For Windows, we should prefer the executable wrapper, which also works + # when invoked from outside of MSYS. + CTW_SUFFIX=$EXEEXT + CTW_LINK_SUFFIX=$EXEEXT +else + CTW_SUFFIX=.sh +fi cd $PREFIX/bin for arch in $ARCHS; do for exec in clang clang++ gcc g++; do - ln -sf clang-target-wrapper.sh $arch-w64-mingw32-$exec + ln -sf clang-target-wrapper$CTW_SUFFIX $arch-w64-mingw32-$exec$CTW_LINK_SUFFIX done for exec in ar ranlib nm strings; do ln -sf llvm-$exec$EXEEXT $arch-w64-mingw32-$exec || true diff --git a/wrappers/clang-target-wrapper.c b/wrappers/clang-target-wrapper.c new file mode 100644 index 0000000..be3d776 --- /dev/null +++ b/wrappers/clang-target-wrapper.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2018 Martin Storsjo + * + * This file is part of llvm-mingw. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef UNICODE +#define _UNICODE +#endif + +#include +#include +#include + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#define EXECVP_CAST +#else +#include +typedef char TCHAR; +#define _T(x) x +#define _tcsrchr strrchr +#define _tcschr strchr +#define _tcsdup strdup +#define _tcscpy strcpy +#define _tcslen strlen +#define _tcscmp strcmp +#define _tperror perror +#define _texecvp execvp +#define _tmain main +#define EXECVP_CAST (char **) +#endif + +int _tmain(int argc, TCHAR* argv[]) { + const TCHAR *argv0 = argv[0]; + const TCHAR *sep = _tcsrchr(argv0, '/'); + if (!sep) + sep = _tcsrchr(argv0, '\\'); + TCHAR *clang = _T("clang"); + const TCHAR *basename = argv0; + if (sep) { + int baselen = sep + 1 - argv0; + clang = malloc((_tcslen(argv0) + 50) * sizeof(*clang)); + memcpy(clang, argv0, baselen * sizeof(*clang)); + _tcscpy(clang + baselen, _T("clang")); + basename = sep + 1; + } +#ifdef _WIN32 + TCHAR module_path[8192]; + GetModuleFileName(NULL, module_path, sizeof(module_path)/sizeof(module_path[0])); + TCHAR *sep2 = _tcsrchr(module_path, '\\'); + if (sep2) { + _tcscpy(sep2 + 1, _T("clang")); + clang = module_path; + } +#endif + basename = _tcsdup(basename); + TCHAR *period = _tcschr(basename, '.'); + if (period) + *period = '\0'; + TCHAR *dash = _tcsrchr(basename, '-'); + const TCHAR *target = basename; + const TCHAR *exe = basename; + if (dash) { + *dash = '\0'; + exe = dash + 1; + } + TCHAR *arch = _tcsdup(target); + dash = _tcschr(arch, '-'); + if (dash) + *dash = '\0'; + + int max_arg = argc + 20; + const TCHAR **exec_argv = malloc(max_arg * sizeof(*exec_argv)); + int arg = 0; + if (getenv("CCACHE")) + exec_argv[arg++] = _T("ccache"); + exec_argv[arg++] = clang; + + // If changing this wrapper, change clang-target-wrapper.sh accordingly. + if (!_tcscmp(exe, _T("clang++")) || !_tcscmp(exe, _T("g++")) || !_tcscmp(exe, _T("c++"))) + exec_argv[arg++] = _T("--driver-mode=g++"); + + if (!_tcscmp(arch, _T("i686"))) { + // Dwarf is the default for i686, but libunwind sometimes fails to + // to unwind correctly on i686. The issue can be reproduced with + // test/exception-locale.cpp. The issue might be related to + // DW_CFA_GNU_args_size, since it goes away if building + // libunwind/libcxxabi/libcxx and the test example with + // -mstack-alignment=16 -mstackrealign. (libunwind SVN r337312 fixed + // some handling relating to this dwarf opcode, which made + // test/hello-exception.cpp work properly, but apparently there are + // still issues with it). + exec_argv[arg++] = _T("-fsjlj-exceptions"); + } else if (!_tcscmp(arch, _T("x86_64"))) { + // SEH is the default here. + } else if (!_tcscmp(arch, _T("armv7"))) { + // Dwarf is the default here. + } else if (!_tcscmp(arch, _T("aarch64"))) { + // Dwarf is the default here. + } + + exec_argv[arg++] = _T("-target"); + exec_argv[arg++] = target; + exec_argv[arg++] = _T("-rtlib=compiler-rt"); + exec_argv[arg++] = _T("-stdlib=libc++"); + exec_argv[arg++] = _T("-fuse-ld=lld"); + exec_argv[arg++] = _T("-fuse-cxa-atexit"); + exec_argv[arg++] = _T("-Qunused-arguments"); + + for (int i = 1; i < argc; i++) + exec_argv[arg++] = argv[i]; + + exec_argv[arg] = NULL; + if (arg > max_arg) { + fprintf(stderr, "Too many options added\n"); + abort(); + } + +#ifdef _WIN32 + int ret = _tspawnvp(_P_WAIT, exec_argv[0], exec_argv); + if (ret == -1) { + _tperror(exec_argv[0]); + return 1; + } + return ret; +#else + // On unix, exec() runs the target executable within this same process, + // making the return code propagate implicitly. + // Windows doesn't have such mechanisms, and the exec() family of functions + // makes the calling process exit immediately and always returning + // a zero return. This doesn't work for our case where we need the + // return code propagated. + _texecvp(exec_argv[0], EXECVP_CAST exec_argv); + + _tperror(exec_argv[0]); + return 1; +#endif +} diff --git a/wrappers/clang-target-wrapper.sh b/wrappers/clang-target-wrapper.sh index b839161..cfc6b10 100755 --- a/wrappers/clang-target-wrapper.sh +++ b/wrappers/clang-target-wrapper.sh @@ -9,6 +9,7 @@ if [ -n "$CCACHE" ]; then CCACHE=ccache fi +# If changing this wrapper, change clang-target-wrapper.c accordingly. CLANG="$DIR/clang" FLAGS="" case $EXE in