-
Notifications
You must be signed in to change notification settings - Fork 232
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
552 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
# Intro | ||
|
||
The main idea is to build the bindings with: | ||
|
||
python .\setup.py bdist_wheel --verbose ; | ||
$wheelFile = Get-ChildItem -Path .\dist\ -Recurse -Include * ; | ||
pip3 install $wheelFile --force-reinstall ; | ||
|
||
Then you must create a setup.py file. This file will include the command to generate python .py bindings, link .dll and then build to pipy. Requires python version greater than 3.6. | ||
|
||
|
||
The full example is available at this [address](https://github.com/mozilla/uniffi-rs/tree/main/examples/distributing/uniffi-rust-to-python-library/src/setup.py). In order to reproduce the issue, let's see some points about the setup.py file. | ||
|
||
|
||
# Create setup.py file. | ||
## rustc | ||
|
||
get rustc version from your setup.py file: | ||
|
||
```python | ||
def get_rustc_info(): | ||
""" | ||
Get the rustc info from `rustc --version --verbose`, parsed into a | ||
dictionary. | ||
""" | ||
regex = re.compile(r"(?P<key>[^:]+)(: *(?P<value>\S+))") | ||
|
||
output = subprocess.check_output(["rustc", "--version", "--verbose"]) | ||
|
||
data = {} | ||
for line in output.decode("utf-8").splitlines(): | ||
match = regex.match(line) | ||
if match: | ||
d = match.groupdict() | ||
data[d["key"]] = d["value"] | ||
|
||
return data | ||
``` | ||
|
||
## Macos compatibility | ||
|
||
The macos compatibility depends of the files generated with the command. | ||
|
||
```python | ||
def macos_compat(target): | ||
if target.startswith("aarch64-"): | ||
return "11.0" | ||
return "10.7" | ||
``` | ||
|
||
|
||
|
||
## target | ||
|
||
The uniffy-bindgen command will generate different output that you will need to guess for future operations: | ||
|
||
```python | ||
# The logic for specifying wheel tags in setuptools/wheel is very complex, hard | ||
# to override, and is really meant for extensions that are compiled against | ||
# libpython.so, not this case where we have a fairly portable Rust-compiled | ||
# binary that should work across a number of Python versions. Therefore, we | ||
# just skip all of its logic be overriding the `get_tag` method with something | ||
# simple that only handles the cases we need. | ||
class bdist_wheel(wheel.bdist_wheel.bdist_wheel): | ||
def get_tag(self): | ||
cpu, _, __ = target.partition("-") | ||
impl, abi_tag = "cp36", "abi3" | ||
if "-linux" in target: | ||
plat_name = f"linux_{cpu}" | ||
elif "-darwin" in target: | ||
compat = macos_compat(target).replace(".", "_") | ||
if cpu == "aarch64": | ||
cpu = "arm64" | ||
plat_name = f"macosx_{compat}_{cpu}" | ||
elif "-windows" in target: | ||
impl, abi_tag = "py3", "none" | ||
if cpu == "i686": | ||
plat_name = "win32" | ||
elif cpu == "x86_64": | ||
plat_name = "win_amd64" | ||
else: | ||
raise ValueError("Unsupported Windows platform") | ||
else: | ||
# Keep local wheel build on BSD/etc. working | ||
_, __, plat_name = super().get_tag() | ||
|
||
return (impl, abi_tag, plat_name) | ||
``` | ||
|
||
|
||
|
||
## Get extension name | ||
|
||
Guess extension from command target flag: | ||
|
||
```python | ||
target = get_rustc_info()["host"] | ||
|
||
extension = "" | ||
file_start = "" | ||
if "-darwin" in target: | ||
shared_object = "libmath.dylib" | ||
extension = ".dylib" | ||
file_start = "lib" | ||
elif "-windows" in target: | ||
shared_object = "mymath.dll" | ||
extension = ".dll" | ||
file_start = "" | ||
else: | ||
# Anything else must be an ELF platform - Linux, *BSD, Solaris/illumos | ||
shared_object = "libmath.so" | ||
extension = ".so" | ||
file_start = "lib" | ||
|
||
new_shared_object_name = file_start + "uniffi_mymath" + extension | ||
``` | ||
|
||
|
||
|
||
```python | ||
class InstallPlatlib(install): | ||
def finalize_options(self): | ||
install.finalize_options(self) | ||
if self.distribution.has_ext_modules(): | ||
self.install_lib = self.install_platlib | ||
``` | ||
|
||
# Build | ||
|
||
```python | ||
class build(_build): | ||
def run(self): | ||
try: | ||
# Use `check_output` to suppress output | ||
subprocess.check_output(["cargo"]) | ||
except subprocess.CalledProcessError: | ||
print("Install Rust and Cargo through Rustup: https://rustup.rs/.") | ||
sys.exit(1) | ||
|
||
env = os.environ.copy() | ||
|
||
# For `musl`-based targets (e.g. Alpine Linux), we need to set a flag | ||
# to produce a shared object Python extension. | ||
if "-musl" in target: | ||
env["RUSTFLAGS"] = ( | ||
env.get("RUSTFLAGS", "") + " -C target-feature=-crt-static" | ||
) | ||
if target == "i686-pc-windows-gnu": | ||
env["RUSTFLAGS"] = env.get("RUSTFLAGS", "") + " -C panic=abort" | ||
|
||
command = [ | ||
"cargo", | ||
"build", | ||
#"--package", | ||
#"math", | ||
"--target", | ||
target, | ||
] | ||
|
||
if buildvariant != "debug": | ||
command.append(f"--{buildvariant}") | ||
|
||
if "-darwin" in target: | ||
env["MACOSX_DEPLOYMENT_TARGET"] = macos_compat(target) | ||
|
||
subprocess.check_call(command, env=env) | ||
|
||
shutil.copyfile( | ||
SRC_ROOT / "uniffi-rust-to-python-library" / "target" / target / buildvariant / "deps" / shared_object, | ||
SRC_ROOT / "uniffi-rust-to-python-library" / "out" / new_shared_object_name, | ||
) | ||
|
||
command = [ | ||
"cargo", | ||
"run", | ||
"--features=uniffi/cli", | ||
"--bin", | ||
"uniffi-bindgen", | ||
"generate", | ||
"src/math.udl", | ||
"--language", | ||
"python", | ||
"--out-dir", | ||
SRC_ROOT / "uniffi-rust-to-python-library" / "target", | ||
] | ||
|
||
subprocess.check_call(command, env=env) | ||
|
||
shutil.copyfile( | ||
SRC_ROOT / "uniffi-rust-to-python-library" / "target" / "mymath.py", SRC_ROOT / "uniffi-rust-to-python-library" / "out" / "mymath.py" | ||
) | ||
|
||
return _build.run(self) | ||
``` | ||
|
||
|
||
## setup() | ||
|
||
```python | ||
setup( | ||
author="gogo2464", | ||
author_email="[email protected]", | ||
classifiers=[ | ||
"Intended Audience :: Developers", | ||
"Natural Language :: English", | ||
"Programming Language :: Python :: 3" | ||
], | ||
description="Example project in order to complete a uniffi-rs tutorial.", | ||
long_description="example", | ||
install_requires=requirements, | ||
long_description_content_type="text/markdown", | ||
include_package_data=True, | ||
keywords="example", | ||
name="mymath", | ||
version="0.1.0", | ||
packages=[ | ||
"mymath" | ||
], | ||
package_dir={ | ||
"mymath": "out" | ||
}, | ||
setup_requires=requirements, | ||
url="no_url", | ||
zip_safe=False, | ||
package_data={"mymath": [new_shared_object_name]}, | ||
distclass=BinaryDistribution, | ||
cmdclass={"install": InstallPlatlib, "bdist_wheel": bdist_wheel, "build": build}, | ||
) | ||
|
||
``` | ||
|
||
|
||
|
||
## COngratulation. | ||
|
||
It was not easy but you did it! In case of issue, fell free to consul the next chapter for real life example. |
23 changes: 23 additions & 0 deletions
23
examples/distributing/uniffi-rust-to-python-library/Cargo.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
[package] | ||
name = "uniffi-rust-to-python-library" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
uniffi = {version = "*", features = [ "cli" ]} | ||
uniffi_macros = "*" | ||
uniffi_bindgen = "*" | ||
|
||
[build-dependencies] | ||
uniffi = { version = "*", features = [ "build", "cli" ] } | ||
|
||
[[bin]] | ||
# This can be whatever name makes sense for your project, but the rest of this tutorial assumes uniffi-bindgen. | ||
name = "uniffi-bindgen" | ||
path = "uniffi-bindgen.rs" | ||
|
||
[lib] | ||
crate-type = ["cdylib"] | ||
name = "mymath" |
5 changes: 5 additions & 0 deletions
5
examples/distributing/uniffi-rust-to-python-library/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
## Minimal example of uniffi-rs with setup.py | ||
|
||
# Building | ||
|
||
.\run.bat |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
fn main() { | ||
uniffi::generate_scaffolding("src/math.udl").unwrap(); | ||
} |
1 change: 1 addition & 0 deletions
1
examples/distributing/uniffi-rust-to-python-library/out/file.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Empty file in order to keep this folder in github. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
cargo run --features=uniffi/cli --bin uniffi-bindgen generate .\src\math.udl --language python --out-dir out | ||
python -m venv venv3 | ||
call ".\venv3\Scripts\activate" | ||
pip install yapf | ||
python .\src\setup.py install | ||
python .\testing\testing.py |
16 changes: 16 additions & 0 deletions
16
examples/distributing/uniffi-rust-to-python-library/src/lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
pub fn add(left: u32, right: u32) -> u32 { | ||
left + right | ||
} | ||
|
||
uniffi::include_scaffolding!("math"); | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn it_works() { | ||
let result = add(2, 2); | ||
assert_eq!(result, 4); | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
examples/distributing/uniffi-rust-to-python-library/src/math.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/*pub fn add(left: u32, right: u32) -> u32 { | ||
left + right | ||
} | ||
uniffi::include_scaffolding!("math"); | ||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
#[test] | ||
fn it_works() { | ||
let result = add(2, 2); | ||
assert_eq!(result, 4); | ||
} | ||
} | ||
*/ |
3 changes: 3 additions & 0 deletions
3
examples/distributing/uniffi-rust-to-python-library/src/math.udl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
namespace mymath { | ||
u32 add(u32 left, u32 right); | ||
}; |
Oops, something went wrong.