From 18d2d38ba4c03d48a772174f3de856d81ff39a4f Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 6 Jun 2016 18:17:33 +0200 Subject: Major redesign of wrappers --- TODO | 13 +++++ cl-11 | 20 ++------ cl-12 | 20 ++------ cl-14 | 32 ++---------- lib-11 | 6 +++ lib-12 | 6 +++ lib-14 | 6 +++ link-11 | 6 +++ link-12 | 6 +++ link-14 | 6 +++ msvc-11 | 18 +++++++ msvc-12 | 18 +++++++ msvc-14 | 26 ++++++++++ msvc-cl-common | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ msvc-common | 121 ++++++++++++++++++++++++++++++++++++++++++++++ msvc-lib-common | 95 ++++++++++++++++++++++++++++++++++++ msvc-link-common | 80 ++++++++++++++++++++++++++++++ 17 files changed, 562 insertions(+), 62 deletions(-) create mode 100644 TODO create mode 100755 lib-11 create mode 100755 lib-12 create mode 100755 lib-14 create mode 100755 link-11 create mode 100755 link-12 create mode 100755 link-14 create mode 100755 msvc-11 create mode 100755 msvc-12 create mode 100755 msvc-14 create mode 100755 msvc-cl-common create mode 100755 msvc-common create mode 100755 msvc-lib-common create mode 100755 msvc-link-common diff --git a/TODO b/TODO new file mode 100644 index 0000000..83d5769 --- /dev/null +++ b/TODO @@ -0,0 +1,13 @@ +@@ link.exe option translation. + +@@ Requires GNU sed 4.2.2 or later (-z), realpath dirpath + +@@ Still need wineserver for /EP, etc. otherwise long pause. + +@@ Redirection of /EP to /dev/null is slow, to file is much faster. + +@@ What about 64-bit? cl-64 or some such? + +@@ I think options are not case-sensitive. + +@@ There is link command. link.exe? cl-14.exe? diff --git a/cl-11 b/cl-11 index 5dc651e..7f6b85e 100755 --- a/cl-11 +++ b/cl-11 @@ -1,20 +1,6 @@ #! /usr/bin/env bash -trap 'exit 1' ERR +src="$(dirname $(realpath ${BASH_SOURCE[0]}))" -SDK="C:\Program Files (x86)\Windows Kits\8.0" - -INCLUDE="$SDK\include\shared;$SDK\include\um;$SDK\include\winrt" -LIB="$SDK\lib\win8\um\x86" - -VC="C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC" - -INCLUDE="$VC\include;$INCLUDE" -LIB="$VC\lib;$LIB" - -export INCLUDE -export LIB - -export WINEDEBUG=fixme-all - -wine "$VC\bin\cl.exe" $* +source "$src/msvc-11" +source "$src/msvc-cl-common" diff --git a/cl-12 b/cl-12 index 8bda7ff..29490fc 100755 --- a/cl-12 +++ b/cl-12 @@ -1,20 +1,6 @@ #! /usr/bin/env bash -trap 'exit 1' ERR +src="$(dirname $(realpath ${BASH_SOURCE[0]}))" -SDK="C:\Program Files (x86)\Windows Kits\8.1" - -INCLUDE="$SDK\include\shared;$SDK\include\um;$SDK\include\winrt" -LIB="$SDK\lib\winv6.3\um\x86" - -VC="C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC" - -INCLUDE="$VC\include;$INCLUDE" -LIB="$VC\lib;$LIB" - -export INCLUDE -export LIB - -export WINEDEBUG=fixme-all - -wine "$VC\bin\cl.exe" $* +source "$src/msvc-12" +source "$src/msvc-cl-common" diff --git a/cl-14 b/cl-14 index 43175d1..9190b9a 100755 --- a/cl-14 +++ b/cl-14 @@ -1,30 +1,6 @@ -#!/bin/sh +#! /usr/bin/env bash -# SDK -# -SDK="C:\Program Files (x86)\Windows Kits\8.1" +src="$(dirname $(realpath ${BASH_SOURCE[0]}))" -INCLUDE="$SDK\include\shared;$SDK\include\um;$SDK\include\winrt" -LIB="$SDK\lib\winv6.3\um\x86" - -# CRT -# -CRT="C:\Program Files (x86)\Windows Kits\10" -VER="10.0.10150.0" - -INCLUDE="$CRT\include\\$VER\ucrt;$INCLUDE" -LIB="$CRT\lib\\$VER\ucrt\x86;$LIB" - -# VC -# -VC="C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC" - -INCLUDE="$VC\include;$INCLUDE" -LIB="$VC\lib;$LIB" - -export INCLUDE -export LIB - -export WINEDEBUG=fixme-all - -exec wine "$VC\bin\cl.exe" $* +source "$src/msvc-14" +source "$src/msvc-cl-common" diff --git a/lib-11 b/lib-11 new file mode 100755 index 0000000..87d3625 --- /dev/null +++ b/lib-11 @@ -0,0 +1,6 @@ +#! /usr/bin/env bash + +src="$(dirname $(realpath ${BASH_SOURCE[0]}))" + +source "$src/msvc-11" +source "$src/msvc-lib-common" diff --git a/lib-12 b/lib-12 new file mode 100755 index 0000000..f047635 --- /dev/null +++ b/lib-12 @@ -0,0 +1,6 @@ +#! /usr/bin/env bash + +src="$(dirname $(realpath ${BASH_SOURCE[0]}))" + +source "$src/msvc-12" +source "$src/msvc-lib-common" diff --git a/lib-14 b/lib-14 new file mode 100755 index 0000000..050a9bc --- /dev/null +++ b/lib-14 @@ -0,0 +1,6 @@ +#! /usr/bin/env bash + +src="$(dirname $(realpath ${BASH_SOURCE[0]}))" + +source "$src/msvc-14" +source "$src/msvc-lib-common" diff --git a/link-11 b/link-11 new file mode 100755 index 0000000..14267fc --- /dev/null +++ b/link-11 @@ -0,0 +1,6 @@ +#! /usr/bin/env bash + +src="$(dirname $(realpath ${BASH_SOURCE[0]}))" + +source "$src/msvc-11" +source "$src/msvc-link-common" diff --git a/link-12 b/link-12 new file mode 100755 index 0000000..d901cd3 --- /dev/null +++ b/link-12 @@ -0,0 +1,6 @@ +#! /usr/bin/env bash + +src="$(dirname $(realpath ${BASH_SOURCE[0]}))" + +source "$src/msvc-12" +source "$src/msvc-link-common" diff --git a/link-14 b/link-14 new file mode 100755 index 0000000..07e24db --- /dev/null +++ b/link-14 @@ -0,0 +1,6 @@ +#! /usr/bin/env bash + +src="$(dirname $(realpath ${BASH_SOURCE[0]}))" + +source "$src/msvc-14" +source "$src/msvc-link-common" diff --git a/msvc-11 b/msvc-11 new file mode 100755 index 0000000..d1ccc99 --- /dev/null +++ b/msvc-11 @@ -0,0 +1,18 @@ +#! /usr/bin/env bash + +# MSVC 11 setup/configuration. Should set VC, INCLUDE, and LIB variables. +# + +# SDK +# +SDK="C:\\Program Files (x86)\\Windows Kits\\8.0" + +INCLUDE="$SDK\\include\\shared;$SDK\\include\\um;$SDK\\include\\winrt" +LIB="$SDK\\lib\\win8\\um\\x86" + +# VC +# +VC="C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC" + +INCLUDE="$VC\\include;$INCLUDE" +LIB="$VC\\lib;$LIB" diff --git a/msvc-12 b/msvc-12 new file mode 100755 index 0000000..2674215 --- /dev/null +++ b/msvc-12 @@ -0,0 +1,18 @@ +#! /usr/bin/env bash + +# MSVC 12 setup/configuration. Should set VC, INCLUDE, and LIB variables. +# + +# SDK +# +SDK="C:\\Program Files (x86)\\Windows Kits\\8.1" + +INCLUDE="$SDK\\include\\shared;$SDK\\include\\um;$SDK\\include\\winrt" +LIB="$SDK\\lib\\winv6.3\\um\\x86" + +# VC +# +VC="C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC" + +INCLUDE="$VC\\include;$INCLUDE" +LIB="$VC\\lib;$LIB" diff --git a/msvc-14 b/msvc-14 new file mode 100755 index 0000000..31242c6 --- /dev/null +++ b/msvc-14 @@ -0,0 +1,26 @@ +#! /usr/bin/env bash + +# MSVC 14 setup/configuration. Should set VC, INCLUDE, and LIB variables. +# + +# SDK +# +SDK="C:\\Program Files (x86)\\Windows Kits\\8.1" + +INCLUDE="$SDK\\include\\shared;$SDK\\include\\um;$SDK\\include\\winrt" +LIB="$SDK\\lib\\winv6.3\\um\\x86" + +# CRT +# +CRT="C:\\Program Files (x86)\\Windows Kits\\10" +VER="10.0.10150.0" + +INCLUDE="$CRT\\include\\$VER\\ucrt;$INCLUDE" +LIB="$CRT\\lib\\$VER\\ucrt\\x86;$LIB" + +# VC +# +VC="C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC" + +INCLUDE="$VC\\include;$INCLUDE" +LIB="$VC\\lib;$LIB" diff --git a/msvc-cl-common b/msvc-cl-common new file mode 100755 index 0000000..ce76fc8 --- /dev/null +++ b/msvc-cl-common @@ -0,0 +1,145 @@ +#! /usr/bin/env bash + +# Common cl.exe driver that expects the VC, INCLUDE, and LIB variables to +# be set for the specific MSVC version/configuration set. + +trap "{ exit 1; }" ERR +set -o errtrace # Trap in functions. + +function info () { echo "$*" 1>&2; } +function error () { info "$*"; exit 1; } + +source $(dirname $(realpath ${BASH_SOURCE[0]}))/msvc-common + +# File descriptor where the diagnostics will be sent. Unless STDOUT is used +# for something else (e.g., /E), cl.exe sends the diagnostics there. +# Otherwise it goes to STDERR. +# +diag=1 + +# Translate absolute paths from POSIX to Windows. Use bash array to store +# arguments in case they contain spaces. +# +# This needs to be done for both certain option values and arguments. +# Arguments are tricky in that unless we recognize every option, and option +# may look a lot like an absolute POSIX path (e.g., /nologo). The heuristics +# that we are going to use here is that if the argument starts with / and +# contains at least one more /, then we consider it an argument. Otherwise -- +# an options. We will also explicitly recognize certain options, like /D, +# which may not fit this scheme well. +# +# Note that the order of the cases is important. Specifically, we want, e.g., +# /D before /D*. +# +args=() + +while [ $# -gt 0 ]; do + case $1 in + + # /I , /AI + # + [/-]I | \ + [/-]AI) + args=("${args[@]}" "$1") + shift + args=("${args[@]}" "$(translate $1)") + shift + ;; + + # /I + # + [/-]I*) + args=("${args[@]}" "$(split_translate 2 $1)") + shift + ;; + + # /AI + # + [/-]AI*) + args=("${args[@]}" "$(split_translate 3 $1)") + shift + ;; + + # /F*: + # + [/-]F[adeimoprR]:) + args=("${args[@]}" "$1") + shift + args=("${args[@]}" "$(translate $1)") + shift + ;; + + # /F*, /T{p,c}, /Yu. + # + [/-]F[adeimoprRUI]* | \ + [/-]Tp* | \ + [/-]Tc* | \ + [/-]Yu*) + args=("${args[@]}" "$(split_translate 3 $1)") + shift + ;; + + # /doc + # + [/-]doc*) + args=("${args[@]}" "$(split_translate 4 $1)") + shift + ;; + + # @ + # + @*) + args=("${args[@]}" "$(split_translate 1 $1)") + shift + ;; + + # Handle other options with separate values. This makes sure we don't try + # to path-translate them. + # + [/-]D | \ + [/-]U | \ + [/-]link) + args=("${args[@]}" "$1") + shift + args=("${args[@]}" "$1") + shift + ;; + + # Handle other options with combined values that could possibly be + # interpreted as paths, for example /DFOO=foo/bar. + # + [/-]D* | \ + [/-]V* | \ + [/-]Yl*) + args=("${args[@]}" "$1") + shift + ;; + + # Detect /E and /EP -- they change where the diagnostics is sent. + # + [/-]E | \ + [/-]EP) + diag=2 + args=("${args[@]}" "$1") + shift + ;; + + # Option or argument. + # + *) + # If contains at least two slashes, treat it as a path. + # + if [[ "$1" == /*/* ]]; then + args=("${args[@]}" "$(translate $1)") + else + args=("${args[@]}" "$1") + fi + shift + ;; + esac +done + +export INCLUDE +export LIB + +msvc_exec $diag "$VC\\bin\\cl.exe" "${args[@]}" diff --git a/msvc-common b/msvc-common new file mode 100755 index 0000000..b3969e8 --- /dev/null +++ b/msvc-common @@ -0,0 +1,121 @@ +#! /usr/bin/env bash + +# Note: shouldn't be executed directly. + +# Translate absolute POSIX path to a Windows path with winepath. +# +function translate () # +{ + if [[ "$1" == /* ]]; then + winepath -w "$1" + else + echo "$1" + fi +} + +# Split the combined option and path value, translate the path component +# to a Windows path if absolute, then recombine the option and path. +# +function split_translate () # +{ + local o="${2:0:$1}" # First characters from $1. + local v="${2:$1}" # The rest. + + # If the path is absolute, map it with winepath. + # + if [[ "$v" == /* ]]; then + v="$(winepath -w "$v")" + fi + + echo "$o$v" +} + +# The argument should be 1 or 2. It indicates whether the diagnostics +# is sent to stdout (1) or stderr (2). +# +# Note that if returns non-zero exit status, then this function calls +# exit, not return. It also clears the ERR trap and overrides the EXIT trap. +# All this pretty much means it should be the last statement in a call. +# +function msvc_exec () # ... +{ + local diag=$1 + shift + + local exe="$1" + shift + + # Assemble the arguments in an array to store in case they contain spaces. + # + local args=() + + while [ $# -gt 0 ]; do + args=("${args[@]}" "$1") + shift + done + + # Translate absolute Windows paths back to POSIX. The hard part here is to + # determing the end of the path. For example, the error location has the + # 'X:\...\foo(10):' form. However, we cannot assume that '(' ends the path; + # remember 'Program Files (x86)'. + # + # To sidestep this whole mess we are going to use this trick: instead of + # translating the whole path we will only translate its directory part, that + # is the longest part that still ends with the directory separator. We will + # also still recognize ':' and ''' as path terminators as well as space if + # it is the first character in the component. + # + # We also pass the path through realpath in order to get the actual path + # rather than Wine's dosdevices links. + # + + # First delimit paths that we need to translate with NUL characters. + # + local s1="s#[A-Z]:[\\/]([^ ':][^':]*[\\/])*#\x00&\x00#g" + + # Next translate the paths (note the -z sed option). The last xargs call + # does two things: it removes the newline added by realpath and adds the + # trailing slash removed by realpath. + # + # Substitution useful for debugging: #/bin/echo -n '&'# + # + local s2="s#^[A-Z]:[\\/]([^ ':][^':]*[\\/])*#winepath -u0 '&' | \ +xargs -0 realpath -z | xargs -0 -I{} /bin/echo -n {}/#e" + + # Finally, get rid of the NUL characters. While at it, also kill Windows + # CR (0x0d). + # + local s3="s#\x00##g;s#\x0d##g" + + # For testing/debugging: + # + #cat input | sed -re "$s1" | sed -z -re "$s2" | sed -re "$s3" + + # Suppress Wine noise. + # + export WINEDEBUG=fixme-all + + # Create a temporary named pipe. + # + local pipe="$(mktemp -u)" + mkfifo $pipe + trap "{ rm $pipe; }" EXIT + + if [ $diag -eq 1 ]; then + wine "$exe" "${args[@]}" 2>&1 1>$pipe & + sed -re "$s1" $pipe | sed -z -re "$s2" | sed -re "$s3" + else + wine "$exe" "${args[@]}" 2>$pipe & + sed -re "$s1" $pipe | sed -z -re "$s2" | sed -re "$s3" 1>&2 + fi + + # Wait for the wine process and exit with its exit status if it's not + # zero. Don't you just hate bash sometimes? I sure do. + # + trap - ERR + wait $! + local r=$? + if [ $r -ne 0 ]; then + exit $r + fi +} diff --git a/msvc-lib-common b/msvc-lib-common new file mode 100755 index 0000000..5d11ba1 --- /dev/null +++ b/msvc-lib-common @@ -0,0 +1,95 @@ +#! /usr/bin/env bash + +# @@ Do we really need LIB? What's /LIBPATH for? +# +# Common lib.exe driver that expects the VC and LIB variables to be set for +# the specific MSVC version/configuration set. + +trap "{ exit 1; }" ERR +set -o errtrace # Trap in functions. + +function info () { echo "$*" 1>&2; } +function error () { info "$*"; exit 1; } + +source $(dirname $(realpath ${BASH_SOURCE[0]}))/msvc-common + +# Translate absolute paths from POSIX to Windows. Use bash array to store +# arguments in case they contain spaces. +# +# This needs to be done for both certain option values and arguments. +# Arguments are tricky in that unless we recognize every option, and option +# may look a lot like an absolute POSIX path (e.g., /nologo). The heuristics +# that we are going to use here is that if the argument starts with / and +# contains at least one more /, then we consider it an argument. Otherwise -- +# an options. We will also explicitly recognize certain options which may +# not fit this scheme well. +# +args=() + +while [ $# -gt 0 ]; do + case $1 in + + # /DEF[:filename] + # /OUT:filename + # + [/-]DEF:* | \ + [/-]OUT:*) + args=("${args[@]}" "$(split_translate 5 $1)") + shift + ;; + + # /LIST[:filename] + # /NAME:filename + # + [/-]LIST:* | \ + [/-]NAME:*) + args=("${args[@]}" "$(split_translate 6 $1)") + shift + ;; + + # /LIBPATH:dir + # + [/-]LIBPATH:*) + args=("${args[@]}" "$(split_translate 9 $1)") + shift + ;; + + # Handle other options with separate values. This makes sure we don't try + # to path-translate them. + # + + # Aren't any. + + # Handle other options with combined values that could possibly be + # interpreted as paths, for example /EXTRACT:foo/bar.obj. + # + [/-]EXPORT:* | \ + [/-]EXTRACT:* | \ + [/-]INCLUDE:* | \ + [/-]REMOVE:*) + args=("${args[@]}" "$1") + shift + ;; + + # Option or argument. + # + *) + # If contains at least two slashes, treat it as a path. + # + if [[ "$1" == /*/* ]]; then + args=("${args[@]}" "$(translate $1)") + else + args=("${args[@]}" "$1") + fi + shift + ;; + esac +done + +# @@ Do we need this? +# +export LIB + +# Lib.exe always sends diagnostics to stdout. +# +msvc_exec 1 "$VC\\bin\\lib.exe" "${args[@]}" diff --git a/msvc-link-common b/msvc-link-common new file mode 100755 index 0000000..64c8a0c --- /dev/null +++ b/msvc-link-common @@ -0,0 +1,80 @@ +#! /usr/bin/env bash + +# Common link.exe driver that expects the VC and LIB variables to be set for +# the specific MSVC version/configuration set. + +trap "{ exit 1; }" ERR +set -o errtrace # Trap in functions. + +function info () { echo "$*" 1>&2; } +function error () { info "$*"; exit 1; } + +source $(dirname $(realpath ${BASH_SOURCE[0]}))/msvc-common + +# Translate absolute paths from POSIX to Windows. Use bash array to store +# arguments in case they contain spaces. +# +# This needs to be done for both certain option values and arguments. +# Arguments are tricky in that unless we recognize every option, and option +# may look a lot like an absolute POSIX path (e.g., /nologo). The heuristics +# that we are going to use here is that if the argument starts with / and +# contains at least one more /, then we consider it an argument. Otherwise -- +# an options. We will also explicitly recognize certain options which may +# not fit this scheme well. +# +args=() + +while [ $# -gt 0 ]; do + case $1 in + + # /DEF[:filename] + # /OUT:filename + # + [/-]DEF:* | \ + [/-]OUT:*) + args=("${args[@]}" "$(split_translate 5 $1)") + shift + ;; + + # @@ TODO + # + + # /LIBPATH:dir + # + [/-]LIBPATH:*) + args=("${args[@]}" "$(split_translate 9 $1)") + shift + ;; + + # Handle other options with separate values. This makes sure we don't try + # to path-translate them. + # + + # @@ TODO + + # Handle other options with combined values that could possibly be + # interpreted as paths, for example /EXTRACT:foo/bar.obj. + # + + # @@ TODO + + # Option or argument. + # + *) + # If contains at least two slashes, treat it as a path. + # + if [[ "$1" == /*/* ]]; then + args=("${args[@]}" "$(translate $1)") + else + args=("${args[@]}" "$1") + fi + shift + ;; + esac +done + +export LIB + +# Link.exe always sends diagnostics to stdout. +# +msvc_exec 1 "$VC\\bin\\link.exe" "${args[@]}" -- cgit v1.1