Skip to content

Commit 003165c

Browse files
committed
Go for musl and default to debug
1 parent 6f57592 commit 003165c

13 files changed

+232
-185
lines changed

.travis.yml

+23-13
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,33 @@ addons:
1111
apt:
1212
packages:
1313
- libdbus-1-dev
14+
- musl-tools
1415

1516
matrix:
1617
fast_finish: true
1718
include:
1819
# These create deployments; Apparently there is not 32 bit mac os
1920
- os: linux
2021
rust: stable
21-
env: TARGET=x86_64-unknown-linux-gnu
22+
env: TARGET=x86_64-unknown-linux-musl
2223
- os: osx
2324
rust: stable
2425
env: TARGET=x86_64-apple-darwin
2526
- os: linux
2627
rust: stable
27-
env: TARGET=i686-unknown-linux-gnu
28+
env: TARGET=i686-unknown-linux-musl
2829
addons:
2930
apt:
3031
packages:
3132
- libdbus-1-dev:i386
32-
- libc6-dev-i386
33-
- linux-libc-dev:i386
34-
- libssl-dev:i386
3533
- libgmp-dev:i386
36-
- gcc-multilib
34+
- binutils:i386
35+
# We actually only need musl-tools:i386 and gcc-multilib, but we need the others to get apt to install them
36+
- cpp-4.8:i386
37+
- musl:i386
38+
- musl-tools:i386
39+
- gcc-multilib:i386
40+
- cpp:i386
3741

3842
# Those are tested
3943
- os: linux
@@ -64,17 +68,24 @@ install:
6468
fi
6569
6670
script:
67-
- if [ "$TARGET" == "i686-unknown-linux-gnu" ]; then rustup target add $TARGET; fi
68-
- cargo build --target $TARGET
69-
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then cargo test --target $TARGET -- --nocapture; fi
71+
- if [[ "$TARGET" == *musl ]]; then rustup target add $TARGET; fi
72+
- if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then cargo test -- --nocapture; fi
7073

7174
before_deploy:
72-
- cargo build --release --target $TARGET
73-
- cargo run --target $TARGET -- publish -b bin --cargo-extra-args="--target=$TARGET" --skip-auditwheel -u konstin
75+
# We don't care for manylinux compliance for the downloads, so we can use the keyring.
76+
# The stack protector story is a weird one; On 32 bit, you get errors such as the following without the option
77+
# /usr/bin/ld: apps/openssl: hidden symbol `__stack_chk_fail_local' isn't defined
78+
# I assume that this is a musl bug fixed in 2015 that didn't make into ubuntu 14.04, but that special
79+
# case seems to be documented nowhere else:
80+
# http://git.musl-libc.org/cgit/musl/commit/?id=55d061f031085f24d138664c897791aebe9a2fab
81+
# We can't have a more recent musl on 14.04 (there's no ppa), so we have to disable that feature
82+
- CFLAGS="-fno-stack-protector" cargo build --release --target $TARGET --features "password-storage musl"
7483
- cd target/$TARGET/release/
7584
# You can add more file to the archive by adding them to this line
7685
- tar czf ../../../${BINARY_NAME}-$TRAVIS_TAG-$TARGET.tar.gz ${BINARY_NAME}
7786
- cd ../../..
87+
# We do care for manylinux compliance, so we use the musl feature to get static binaries for pypi
88+
- CFLAGS="-fno-stack-protector" cargo run --release --target $TARGET --features musl -- publish -u konstin --release -b bin --target $TARGET --cargo-extra-args="--features=musl"
7889

7990
deploy:
8091
- # Add zipped binary to the github release
@@ -99,5 +110,4 @@ branches:
99110
- /^v\d+\.\d+\.\d+.*$/
100111

101112
notifications:
102-
email:
103-
on_success: never
113+
email: false

Cargo.toml

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
authors = ["konstin <[email protected]>"]
33
name = "pyo3-pack"
4-
version = "0.3.3"
4+
version = "0.3.4"
55
description = "Build and publish crates with pyo3 bindings as python packages"
66
exclude = ["get-fourtytwo/**/*", "integration-test/**/*", "sysconfig/*"]
77
readme = "Readme.md"
@@ -50,13 +50,16 @@ openssl = { version = "0.10", features = ["vendored"], optional = true }
5050
indoc = "0.2.8"
5151

5252
[features]
53-
default = ["auditwheel", "upload", "password-storage"]
53+
default = ["auditwheel", "upload"]
5454
auditwheel = ["goblin"]
55-
# sdists can be created, but they are currently useless (#2)
56-
sdist = ["tar", "libflate"]
5755
upload = ["reqwest"]
5856
password-storage = ["upload", "keyring"]
59-
musl_wip = ["openssl"]
57+
58+
# This will make rewquest use a statically linked version of openssl
59+
musl = ["openssl"]
60+
61+
# sdists can be created, but they are currently useless (#2)
62+
sdist = ["tar", "libflate"]
6063

6164
[workspace]
6265
members = [

Changelog.md

+17-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,18 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.3.4] - 2018-09-18
89

9-
## [Unreleased]
10+
### Added
11+
12+
* A `--target` option which behaves like cargo option of the same name
13+
14+
### Changed
15+
16+
* Musl and auditwheel compliance: Using the new `musl` feature combined with the musl target, you can build completely static binaries. The `password-storage`, which enables keyring integration, is now disabled by default. The Pypi packages are now statically linked with musl so that they are audtiwheel compliant.
17+
* Replaced `--debug` with `--release`. All builds are now debug by default
18+
19+
## [0.3.3] - 2018-09-17
1020

1121
### Added
1222

@@ -16,6 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1626
## Fixed
1727

1828
* Usage with stable
29+
* Wrong tags in WHEEL file on non-linux platforms
30+
* Uploading on windows
1931

2032
## [0.3.1] - 2017-09-14
2133

@@ -56,8 +68,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5668

5769
* Initial Release
5870

59-
[Unreleased]: https://github.com/pyo3/pyo3-pack/compare/v0.3.1...HEAD
60-
[0.3.0]: https://github.com/pyo3/pyo3-pack/compare/v0.3.0...v0.3.1
71+
[Unreleased]: https://github.com/pyo3/pyo3-pack/compare/v0.3.3...HEAD
72+
[0.3.4]: https://github.com/pyo3/pyo3-pack/compare/v0.3.3...v0.3.4
73+
[0.3.3]: https://github.com/pyo3/pyo3-pack/compare/v0.3.1...v0.3.3
74+
[0.3.1]: https://github.com/pyo3/pyo3-pack/compare/v0.3.0...v0.3.1
6175
[0.3.0]: https://github.com/pyo3/pyo3-pack/compare/v0.2.0...v0.3.0
6276
[0.2.0]: https://github.com/pyo3/pyo3-pack/compare/v0.1.0...v0.2.0
6377

Readme.md

+39-35
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,55 @@ Pip allows adding so called console scripts, which are shell commands that execu
4141
get_42 = "get_fourtytwo:DummyClass.get_42"
4242
```
4343

44+
## pyo3 and rust-cpython
45+
4446
For pyo3 and rust-cpython, pyo3-pack can only build packages for installed python versions, so you might want to use pyenv, deadsnakes or docker for building. If you don't set your own interpreters with `-i`, a heuristic is used to search for python installations. You can get a list all found versions with the `list-python` subcommand.
4547

48+
49+
## Cffi
50+
51+
Cffi wheels are compatible with all python versions, but they need to have `cffi` installed for the python used for building (`pip install cffi`).
52+
53+
Until [eqrion/cbdingen#203](https://github.com/eqrion/cbindgen/issues/203) is resolved, you also need to use a build script that writes c headers to a file called `target/header.h`
54+
55+
```rust
56+
extern crate cbindgen;
57+
58+
use std::env;
59+
use std::path::Path;
60+
61+
fn main() {
62+
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
63+
64+
let mut config: cbindgen::Config = Default::default();
65+
config.language = cbindgen::Language::C;
66+
cbindgen::generate_with_config(&crate_dir, config)
67+
.expect("Unable to generate bindings")
68+
.write_to_file(Path::new("target").join("header.h"));
69+
}
70+
```
71+
72+
## Manylinux and auditwheel
73+
74+
For portability reasons, native python modules on linux must only dynamically link a set of very few libraries which are installed basically everywhere, hence the name manylinux. The pypa offers a special docker container and a tool called [auditwheel](https://github.com/pypa/auditwheel/) to ensure compliance with the [manylinux rules](https://www.python.org/dev/peps/pep-0513/#the-manylinux1-policy). pyo3-pack contains a reimplementation of the most important part of auditwheel that checks the generated library, so there's no need to use external tools. If you want to disable the manylinux compliance checks for some reason, use the `--skip-auditwheel` flag.
75+
76+
pyo3-pack itself is manylinux compliant when compiled with the `musl` feature and a musl target, which is true for the version published on pypi. The binaries on the release pages have keyring integration (though the `password-storage` feature), which is not manylinux compliant.
77+
4678
### Build
4779

4880
```
4981
USAGE:
5082
pyo3-pack build [FLAGS] [OPTIONS]
5183
5284
FLAGS:
53-
-d, --debug Do a debug build (don't pass --release to cargo)
5485
-h, --help Prints help information
86+
--release Pass --release to cargo
5587
--skip-auditwheel Don't check for manylinux compliance
5688
-V, --version Prints version information
5789
5890
OPTIONS:
91+
-m, --manifest-path <PATH> The path to the Cargo.toml [default: Cargo.toml]
92+
--target <TRIPLE> The --target option for cargo
5993
-b, --bindings-crate <bindings>
6094
The crate providing the python bindings. pyo3, rust-cpython and cffi are supported
6195
@@ -65,7 +99,6 @@ OPTIONS:
6599
-i, --interpreter <interpreter>...
66100
The python versions to build wheels for, given as the names of the interpreters. Uses autodiscovery if not
67101
explicitly set.
68-
-m, --manifest-path <manifest_path> The path to the Cargo.toml [default: Cargo.toml]
69102
-o, --out <out>
70103
The directory to store the built wheels in. Defaults to a new "wheels" directory in the project's target
71104
directory
@@ -80,12 +113,14 @@ USAGE:
80113
pyo3-pack publish [FLAGS] [OPTIONS]
81114
82115
FLAGS:
83-
-d, --debug Do a debug build (don't pass --release to cargo)
84116
-h, --help Prints help information
117+
--release Pass --release to cargo
85118
--skip-auditwheel Don't check for manylinux compliance
86119
-V, --version Prints version information
87120
88121
OPTIONS:
122+
-m, --manifest-path <PATH> The path to the Cargo.toml [default: Cargo.toml]
123+
--target <TRIPLE> The --target option for cargo
89124
-b, --bindings-crate <bindings>
90125
The crate providing the python bindings. pyo3, rust-cpython and cffi are supported
91126
@@ -95,7 +130,6 @@ OPTIONS:
95130
-i, --interpreter <interpreter>...
96131
The python versions to build wheels for, given as the names of the interpreters. Uses autodiscovery if not
97132
explicitly set.
98-
-m, --manifest-path <manifest_path> The path to the Cargo.toml [default: Cargo.toml]
99133
-o, --out <out>
100134
The directory to store the built wheels in. Defaults to a new "wheels" directory in the project's target
101135
directory
@@ -119,7 +153,7 @@ USAGE:
119153
120154
FLAGS:
121155
-h, --help Prints help information
122-
--release Compile in release mode. This is useful e.g. for benchmarking
156+
--release Pass --release to cargo
123157
-V, --version Prints version information
124158
125159
OPTIONS:
@@ -134,36 +168,6 @@ OPTIONS:
134168
Extra arguments that will be passed to rustc as `cargo rustc [...] -- [arg1] [arg2]`
135169
```
136170

137-
138-
## Cffi
139-
140-
Cffi wheels are compatible with all python versions, but they need to have `cffi` installed to build (`pip install cffi`). Until [eqrion/cbdingen#203](https://github.com/eqrion/cbindgen/issues/203) is resolved, you also need to use a build script that writes c headers to a file called `target/header.h`
141-
142-
```rust
143-
extern crate cbindgen;
144-
145-
use std::env;
146-
use std::path::Path;
147-
148-
fn main() {
149-
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
150-
151-
let mut config: cbindgen::Config = Default::default();
152-
config.language = cbindgen::Language::C;
153-
cbindgen::generate_with_config(&crate_dir, config)
154-
.expect("Unable to generate bindings")
155-
.write_to_file(Path::new("target").join("header.h"));
156-
}
157-
```
158-
159-
## Manylinux and auditwheel
160-
161-
For portability reasons, native python modules on linux must only dynamically link a set of very few libraries which are installed basically everywhere, hence the name manylinux. The pypa offers a special docker container and a tool called [auditwheel](https://github.com/pypa/auditwheel/) to ensure compliance with the [manylinux rules](https://www.python.org/dev/peps/pep-0513/#the-manylinux1-policy). pyo3-pack contains a reimplementation of the most important part of auditwheel that checks the generated library, so there's no need to use external tools. If you want to disable the manylinux compliance checks for some reason, use the `--skip-auditwheel` flag.
162-
163-
To ship a completely static binary with musl, you can use `pyo3-pack build -b bin --cargo-extra-args="--target=x86_64-unknown-linux-musl"`.
164-
165-
Note that the pyo3-pack pip package is not manylinux compliant (A compliant package, which you get with `--no-default-features --features auditwheel`, can neither upload nor use the keyring)
166-
167171
## Code
168172

169173
The main part is the pyo3-pack library, which is completely documented and should be well integratable. The accompanying `main.rs` takes care username and password for the pypi upload and otherwise calls into the library.

appveyor.yml

+5-4
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,16 @@ test_script:
5959
}
6060
6161
before_deploy:
62-
- cargo build --release
63-
# I don't know how I can create a script deployment like in travis in appveyor, so let's hijack before_deploy
64-
# Also we only need one version for win32 and one for win_amd64, so we only deploy to pypi for msvc
65-
- cargo run -- publish -b bin -u konstin
62+
- cargo build --release --features password-storage
6663
# Grab the binary and pack it into a zip archive
6764
- cd target\release\
6865
# You can add more file to the archive by adding them to this line
6966
- 7z a ../../%APPVEYOR_PROJECT_SLUG%-%APPVEYOR_REPO_TAG_NAME%-%TARGET%.zip %BINARY_NAME%
7067
- appveyor PushArtifact ../../%APPVEYOR_PROJECT_SLUG%-%APPVEYOR_REPO_TAG_NAME%-%TARGET%.zip
68+
- cd ../..
69+
# Publish pypi
70+
- cargo run -- publish -b bin -u konstin --release
71+
7172

7273
deploy:
7374
# Add zipped binary to the github release

src/build_context.rs

+23-23
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ use auditwheel_rs;
44
use build_source_distribution;
55
use compile;
66
use failure::{Context, Error, ResultExt};
7-
use Metadata21;
8-
use module_writer::{write_bin, write_bindings_module, write_cffi_module};
97
use module_writer::WheelWriter;
10-
use PythonInterpreter;
8+
use module_writer::{write_bin, write_bindings_module, write_cffi_module};
119
use std::collections::HashMap;
1210
use std::fs;
1311
use std::path::PathBuf;
12+
use Metadata21;
13+
use PythonInterpreter;
1414
use Target;
1515

1616
/// The way the rust code is bridged with python, i.e. either using extern c and cffi or
@@ -54,8 +54,8 @@ pub struct BuildContext {
5454
/// The directory to store the built wheels in. Defaults to a new "wheels"
5555
/// directory in the project's target directory
5656
pub out: PathBuf,
57-
/// Do a debug build (don't pass --release to cargo)
58-
pub debug: bool,
57+
/// Pass --release to cargo
58+
pub release: bool,
5959
/// Don't check for manylinux compliance
6060
pub skip_auditwheel: bool,
6161
/// Extra arguments that will be passed to cargo as `cargo rustc [...] [arg1] [arg2] --`
@@ -126,22 +126,22 @@ impl BuildContext {
126126
}
127127

128128
#[cfg(feature = "sdist")]
129-
{
130-
let sdist_path = wheel_dir.join(format!(
131-
"{}-{}.tar.gz",
132-
&self.metadata21.get_distribution_encoded(),
133-
&self.metadata21.get_version_encoded()
134-
));
135-
136-
println!(
137-
"Building the source distribution to {}",
138-
sdist_path.display()
139-
);
140-
build_source_distribution(&self, &self.metadata21, &self.scripts, &sdist_path)
141-
.context("Failed to build the source distribution")?;
142-
143-
wheels.push((sdist_path, None));
144-
}
129+
{
130+
let sdist_path = wheel_dir.join(format!(
131+
"{}-{}.tar.gz",
132+
&self.metadata21.get_distribution_encoded(),
133+
&self.metadata21.get_version_encoded()
134+
));
135+
136+
println!(
137+
"Building the source distribution to {}",
138+
sdist_path.display()
139+
);
140+
build_source_distribution(&self, &self.metadata21, &self.scripts, &sdist_path)
141+
.context("Failed to build the source distribution")?;
142+
143+
wheels.push((sdist_path, None));
144+
}
145145

146146
Ok(wheels)
147147
}
@@ -168,7 +168,7 @@ impl BuildContext {
168168

169169
if !self.skip_auditwheel && target.is_linux() {
170170
#[cfg(feature = "auditwheel")]
171-
auditwheel_rs(&artifact).context("Failed to ensure manylinux compliance")?;
171+
auditwheel_rs(&artifact).context("Failed to ensure manylinux compliance")?;
172172
}
173173

174174
Ok(artifact)
@@ -213,7 +213,7 @@ impl BuildContext {
213213

214214
if !self.skip_auditwheel && self.target.is_linux() {
215215
#[cfg(feature = "auditwheel")]
216-
auditwheel_rs(&artifact).context("Failed to ensure manylinux compliance")?;
216+
auditwheel_rs(&artifact).context("Failed to ensure manylinux compliance")?;
217217
}
218218

219219
let (tag, tags) = self.get_unversal_tags();

0 commit comments

Comments
 (0)