Skip to content

Improve pc-windows-gnu support #92

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jun 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ matrix:
- env: TARGET=x86_64-unknown-netbsd DYLIB=1 STD=1 OPENSSL=0.7.17

# Windows
- env: TARGET=x86_64-pc-windows-gnu CPP=1 DYLIB=1 STD=1
- env: TARGET=x86_64-pc-windows-gnu CPP=1 STD=1 RUN=1
- env: TARGET=i686-pc-windows-gnu CPP=1 STD=1 RUN=1

# Bare metal
- env: TARGET=thumbv6m-none-eabi RUN=1
Expand All @@ -58,9 +59,6 @@ install:
- curl https://sh.rustup.rs -sSf |
sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION
- source ~/.cargo/env
- test $TRAVIS_OS_NAME = osx ||
which cargo clone ||
cargo install cargo-clone --vers 0.1.0

script:
- bash ci/script.sh
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ worst, "hang" (never terminate).
| `armv7-unknown-linux-gnueabihf` | 2.15 | 4.6.2 | 1.0.2k | ✓ | 2.8.0 | ✓ |
| `armv7-unknown-linux-musleabihf` | 1.1.15 | 5.3.1 | N/A | | 2.8.0 | ✓ |
| `i686-linux-android` | N/A | 4.9 | 1.0.2k | ✓ | N/A | |
| `i686-pc-windows-gnu` | N/A | 6.2.0 | N/A | ✓ | N/A | ✓ |
| `i686-unknown-freebsd` [1] | 10.2 | 5.3.0 | 1.0.2k | | N/A | |
| `i686-unknown-linux-gnu` | 2.15 | 4.6.2 | 1.0.2k | ✓ | N/A | ✓ |
| `i686-unknown-linux-musl` | 1.1.15 | 5.3.1 | N/A | | N/A | ✓ |
Expand All @@ -182,7 +183,7 @@ worst, "hang" (never terminate).
| `thumbv7em-none-eabihf` [3] | 2.2.0 | 5.3.1 | N/A | | N/A | |
| `thumbv7m-none-eabi` [3] | 2.2.0 | 5.3.1 | N/A | | N/A | |
| `x86_64-linux-android` | N/A | 4.9 | 1.0.2k | ✓ | N/A | |
| `x86_64-pc-windows-gnu`[1] | N/A | 5.3.1 | | ✓ | N/A | |
| `x86_64-pc-windows-gnu` | N/A | 6.2.0 | N/A | ✓ | N/A | |
| `x86_64-unknown-dragonfly` [1] [2] | 4.6.0 | 5.3.0 | 1.0.2k | | N/A | ✓ |
| `x86_64-unknown-freebsd` [1] | 10.2 | 5.3.0 | 1.0.2k | | N/A | |
| `x86_64-unknown-linux-gnu` | 2.15 | 4.6.2 | 1.0.2k | ✓ | N/A | ✓ |
Expand Down
22 changes: 16 additions & 6 deletions ci/script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ set -ex
main() {
local td=

if [ $TRAVIS_OS_NAME = linux ]; then
if [ "$TRAVIS_OS_NAME" = linux ]; then
./build-docker-image.sh $TARGET
fi

if [ $TRAVIS_BRANCH = master ] || [ ! -z $TRAVIS_TAG ]; then
if [ "$TRAVIS_BRANCH" = master ] || [ ! -z "$TRAVIS_TAG" ]; then
return
fi

Expand All @@ -34,7 +34,7 @@ main() {
esac

# `cross build` test for targets where `std` is not available
if [ -z $STD ]; then
if [ -z "$STD" ]; then
td=$(mktemp -d)

git clone \
Expand Down Expand Up @@ -133,10 +133,20 @@ EOF
if [ $OPENSSL ]; then
td=$(mktemp -d)

# If tag name v$OPENSSL fails we try openssl-sys-v$OPENSSL
git clone \
--depth 1 \
--branch v$OPENSSL \
https://github.com/sfackler/rust-openssl $td || \
git clone \
--depth 1 \
--branch openssl-sys-v$OPENSSL \
https://github.com/sfackler/rust-openssl $td

pushd $td
cargo clone openssl-sys --vers $OPENSSL
cd openssl-sys
cross build --target $TARGET
# avoid problems building openssl-sys in a virtual workspace
rm -f Cargo.toml
cd openssl-sys && cross build --target $TARGET
popd

rm -rf $td
Expand Down
43 changes: 43 additions & 0 deletions docker/i686-pc-windows-gnu/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# wine in ubuntu versions less than 17.04 hangs in the tests
FROM ubuntu:17.04

RUN apt-get update && \
apt-get install -y --no-install-recommends \
ca-certificates \
cmake \
gcc \
libc6-dev \
make \
pkg-config

COPY xargo.sh /
RUN bash /xargo.sh

RUN dpkg --add-architecture i386 && apt-get update && \
apt-get install -y --no-install-recommends \
wine-stable \
wine64 \
wine32 \
libz-mingw-w64-dev

# Build mingw tools using dwarf exceptions
COPY mingw.sh /
RUN bash mingw.sh

# run-detectors are responsible for calling the correct interpreter for exe
# files. For some reason it does not work inside a docker container (it works
# fine in the host). So we replace the usual paths of run-detectors to run wine
# directly. This only affects the guest, we are not messing up with the host.
#
# See /usr/share/doc/binfmt-support/detectors
RUN mkdir -p /usr/lib/binfmt-support/ && \
rm -f /usr/lib/binfmt-support/run-detectors /usr/bin/run-detectors && \
ln -s /usr/bin/wine /usr/lib/binfmt-support/run-detectors && \
ln -s /usr/bin/wine /usr/bin/run-detectors

COPY windows-entry.sh /
ENTRYPOINT ["/windows-entry.sh"]

ENV CARGO_TARGET_I686_PC_WINDOWS_GNU_LINKER=i686-w64-mingw32-gcc \
CC_i686_pc_windows_gnu=i686-w64-mingw32-gcc \
CXX_i686_pc_windows_gnu=i686-w64-mingw32-g++
130 changes: 130 additions & 0 deletions docker/mingw.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
set -x

main() {
# Ubuntu mingw packages for i686 uses sjlj exceptions, but rust target
# i686-pc-windows-gnu uses dwarf exceptions. So we build mingw packages
# that are compatible with rust.

# Install mingw (with sjlj exceptions) to get the dependencies right
# Later we replace these packages with the new ones
apt-get install -y --no-install-recommends g++-mingw-w64-i686

local td=$(mktemp -d)

local dependencies=(
build-essential
$(apt-cache showsrc gcc-mingw-w64-i686 | grep Build | cut -d: -f2 | tr , '\n' | cut -d' ' -f2 | sort | uniq)
)

local purge_list=()
for dep in ${dependencies[@]}; do
if ! dpkg -L $dep > /dev/null; then
purge_list+=( $dep )
fi
done

# The build fails with the default gcc-6-source version (6.3.0-12ubuntu2)
# Downgrading to the previous version makes the build works
echo "deb http://archive.ubuntu.com/ubuntu yakkety main universe" >> /etc/apt/sources.list
apt-get update
apt-get install -y --no-install-recommends gcc-6-source=6.2.0-5ubuntu12 ${purge_list[@]}

pushd $td

apt-get source gcc-mingw-w64-i686
cd gcc-mingw-w64-*

# We are using dwarf exceptions instead of sjlj
sed -i -e 's/libgcc_s_sjlj-1/libgcc_s_dw2-1/g' debian/gcc-mingw-w64-i686.install

# Only build i686 packages (disable x86_64)
patch -p0 <<'EOF'
--- debian/control.template.ori 2017-06-02 15:58:53.965834005 -0300
+++ debian/control.template
@@ -1,7 +1,6 @@
Package: @@PACKAGE@@-mingw-w64
Architecture: all
Depends: @@PACKAGE@@-mingw-w64-i686,
- @@PACKAGE@@-mingw-w64-x86-64,
${misc:Depends}
Recommends: @@RECOMMENDS@@
Built-Using: gcc-@@VERSION@@ (= ${gcc:Version})
@@ -32,22 +31,3 @@
This package contains the @@LANGUAGE@@ compiler, supporting
cross-compiling to 32-bit MinGW-w64 targets.
Build-Profiles: <!stage1>
-
-Package: @@PACKAGE@@-mingw-w64-x86-64
-Architecture: any
-Depends: @@DEPENDS64@@,
- ${misc:Depends},
- ${shlibs:Depends}
-Suggests: gcc-@@VERSION@@-locales (>= ${local:Version})
-Breaks: @@BREAKS64@@
-Conflicts: @@CONFLICTS64@@
-Replaces: @@REPLACES64@@
-Built-Using: gcc-@@VERSION@@ (= ${gcc:Version})
-Description: GNU @@LANGUAGE@@ compiler for MinGW-w64 targeting Win64
- MinGW-w64 provides a development and runtime environment for 32- and
- 64-bit (x86 and x64) Windows applications using the Windows API and
- the GNU Compiler Collection (gcc).
- .
- This package contains the @@LANGUAGE@@ compiler, supporting
- cross-compiling to 64-bit MinGW-w64 targets.
-Build-Profiles: <!stage1>
EOF

# Disable build of fortran,objc,obj-c++ and use configure options
# --disable-sjlj-exceptions --with-dwarf2
patch -p0 <<'EOF'
--- debian/rules.ori 2016-08-20 15:24:54.000000000 +0000
+++ debian/rules
@@ -57,9 +57,7 @@
INSTALL_TARGET := install-gcc
else
# Build the full GCC.
- languages := c,c++,fortran,objc,obj-c++
- debian_extra_langs := ada
- export debian_extra_langs
+ languages := c,c++
BUILD_TARGET :=
INSTALL_TARGET := install install-lto-plugin
endif
@@ -86,7 +84,7 @@
sed -i 's/@@VERSION@@/$(target_version)/g' debian/control
touch $@

-targets := i686-w64-mingw32 x86_64-w64-mingw32
+targets := i686-w64-mingw32
threads := posix win32

# Hardening on the host, none on the target
@@ -213,6 +211,10 @@
# Enable libatomic
CONFFLAGS += \
--enable-libatomic
+# Enable dwarf exceptions
+CONFFLAGS += \
+ --disable-sjlj-exceptions \
+ --with-dwarf2

spelling = grep -rl "$(1)" $(upstream_dir) | xargs -r sed -i "s/$(1)/$(2)/g"

EOF

# Build the modified mingw packages
MAKEFLAGS=--silent dpkg-buildpackage -nc -B

# Replace installed mingw packages with the new ones
dpkg -i ../g*-mingw-w64-i686*.deb ../gcc-mingw-w64-base*.deb

# Clean up
apt-get purge --auto-remove -y ${purge_list[@]}

popd

rm -rf $td
rm $0
}

main "${@}"
19 changes: 19 additions & 0 deletions docker/windows-entry.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash

set -e

export HOME=/tmp/home
mkdir -p $HOME

# Initialize the wine prefix (virtual windows installation)
export WINEPREFIX=/tmp/wine
mkdir -p $WINEPREFIX
# FIXME: Make the wine prefix initialization faster
wineboot &> /dev/null

# Put libstdc++ and some other mingw dlls in WINEPATH
# This must work for x86_64 and i686
P1=$(dirname $(find /usr -name libwinpthread-1.dll))
export WINEPATH="$(ls -d /usr/lib/gcc/*-w64-mingw32/*win32);$P1"

exec "$@"
30 changes: 27 additions & 3 deletions docker/x86_64-pc-windows-gnu/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
FROM ubuntu:16.04
# wine in ubuntu versions less than 17.04 hangs in the tests
FROM ubuntu:17.04

RUN apt-get update && \
apt-get install -y --no-install-recommends \
Expand All @@ -9,8 +10,31 @@ RUN apt-get update && \
make \
pkg-config

RUN apt-get install -y --no-install-recommends \
g++-mingw-w64-x86-64
COPY xargo.sh /
RUN bash /xargo.sh

RUN dpkg --add-architecture i386 && apt-get update && \
apt-get install -y --no-install-recommends \
wine-stable \
wine64 \
wine32 \
libz-mingw-w64-dev

RUN apt-get install -y --no-install-recommends g++-mingw-w64-x86-64

# run-detectors are responsible for calling the correct interpreter for exe
# files. For some reason it does not work inside a docker container (it works
# fine in the host). So we replace the usual paths of run-detectors to run wine
# directly. This only affects the guest, we are not messing up with the host.
#
# See /usr/share/doc/binfmt-support/detectors
RUN mkdir -p /usr/lib/binfmt-support/ && \
rm -f /usr/lib/binfmt-support/run-detectors /usr/bin/run-detectors && \
ln -s /usr/bin/wine /usr/lib/binfmt-support/run-detectors && \
ln -s /usr/bin/wine /usr/bin/run-detectors

COPY windows-entry.sh /
ENTRYPOINT ["/windows-entry.sh"]

ENV CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER=x86_64-w64-mingw32-gcc \
CC_x86_64_pc_windows_gnu=x86_64-w64-mingw32-gcc \
Expand Down
2 changes: 1 addition & 1 deletion src/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ impl Subcommand {
}
}

pub fn needs_qemu(&self) -> bool {
pub fn needs_interpreter(&self) -> bool {
match *self {
Subcommand::Run | Subcommand::Test => true,
_ => false,
Expand Down
17 changes: 11 additions & 6 deletions src/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,22 @@ pub fn docker_command(subcommand: &str) -> Command {
docker
}

/// Register QEMU interpreters
pub fn register(verbose: bool) -> Result<()> {
/// Register binfmt interpreters
pub fn register(target: &Target, verbose: bool) -> Result<()> {
let cmd = if target.is_windows() {
// https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html
"mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc && \
echo ':wine:M::MZ::/usr/bin/run-detectors:' > /proc/sys/fs/binfmt_misc/register"
} else {
"apt-get update && apt-get install --no-install-recommends -y \
binfmt-support qemu-user-static"
};
docker_command("run")
.arg("--privileged")
.arg("--rm")
.arg("-it")
.arg("ubuntu:16.04")
.args(&["sh",
"-c",
"apt-get update && apt-get install --no-install-recommends \
-y binfmt-support qemu-user-static"])
.args(&["sh", "-c", cmd])
.run(verbose)
}

Expand Down
28 changes: 28 additions & 0 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use std::path::Path;

use errors::*;
use file;
use Target;

/// Checks if the interpreters have been registered in the host system
pub fn is_registered(target: &Target) -> Result<bool> {
if file::read("/proc/sys/fs/binfmt_misc/status")?.trim() != "enabled" {
Err("host system doesn't have binfmt_misc support")?
}

let ok = if target.is_windows() {
let wine = Path::new("/proc/sys/fs/binfmt_misc/wine");
wine.exists() &&
{
let f = file::read(wine)?;
f.contains("/usr/bin/run-detectors") ||
f.contains("/usr/lib/binfmt-support/run-detectors")
}
} else {
// NOTE checking any architecture will do, here we pick arm
let qemu = Path::new("/proc/sys/fs/binfmt_misc/qemu-arm");
qemu.exists() && file::read(qemu)?.contains("/usr/bin/qemu-arm-static")
};

Ok(ok)
}
Loading