Skip to content

Commit

Permalink
Support building projects for FreeBSD
Browse files Browse the repository at this point in the history
This adds basic FreeBSD support. Basic, because it works for my few
cases. There are two major differences from how things works for Linux
and rest platforms:

The first is that there is no custom suffix for produced `.so` files
and `imp.get_suffixes()` confirms that.

The second is more complicated. There is no universal platform tag which
covers some OS release. In fact, it includes information about:
- OS version (11_2, 12_0),
- release type (RELEASE, STABLE)
- and patch set (p1, p7, etc).

While first two are pretty well known and could be simply hardcoded
to maintain support for a many years, patch set is very generic and
changes once any security or system fixes get issued for specific
release. From point of FreeBSD it's the same system with the same
compatibility guarantees. From point of Python it's a completely
different platform which is not compatible with the others patches
for the same OS version and release.

That means that wheels need to be rebuild (or just renamed) if system
receives any patch set update.
  • Loading branch information
kxepal committed Aug 3, 2019
1 parent 675d928 commit 12cff71
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/get_interpreter_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
"d": sysconfig.get_config_var("Py_DEBUG") == 1,
# This one isn't technically necessary, but still very useful for sanity checks
"platform": sys.platform,
# This one needs for FreeBSD to get correct platform tag
"release": platform.release().replace(".", '_').replace("-", "_"),
}

print(json.dumps(metadata))
31 changes: 27 additions & 4 deletions src/python_interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ struct IntepreterMetadataMessage {
d: bool,
platform: String,
abi_tag: Option<String>,
release: String,
}

/// The location and version of an interpreter
Expand All @@ -277,8 +278,8 @@ pub struct PythonInterpreter {
///
/// See PEP 261 and PEP 393 for details
pub abiflags: String,
/// Currently just the value of [Target::os()], i.e. "windows", "linux" or
/// "macos"
/// Currently just the value of [Target::os()], i.e. "windows", "linux",
/// "macos" or "freebsd"
pub target: Target,
/// Path to the python interpreter, e.g. /usr/bin/python3.6
///
Expand All @@ -292,6 +293,8 @@ pub struct PythonInterpreter {
///
/// Note that this always `None` on windows
pub abi_tag: Option<String>,
/// Release tag for FreeBSD. May be useful for other non Windows/Linux/Mac platforms.
pub release: String,
}

/// Returns the abiflags that are assembled through the message, with some
Expand All @@ -308,6 +311,7 @@ fn fun_with_abiflags(
"win32" | "win_amd64" => target.is_windows(),
"linux" | "linux2" | "linux3" => target.is_linux(),
"darwin" => target.is_macos(),
"freebsd11" | "freebsd12" | "freebsd13" => target.is_freebsd(),
_ => false,
};

Expand Down Expand Up @@ -359,7 +363,16 @@ impl PythonInterpreter {
match self.interpreter {
Interpreter::CPython => {
let platform = self.target.get_platform_tag(manylinux);
if self.target.is_unix() {
if self.target.is_freebsd() {
let platform_with_release: &str = &platform.replace("{release}", &self.release);
format!(
"cp{major}{minor}-cp{major}{minor}{abiflags}-{platform}",
major = self.major,
minor = self.minor,
abiflags = self.abiflags,
platform = platform_with_release
)
} else if self.target.is_unix() {
format!(
"cp{major}{minor}-cp{major}{minor}{abiflags}-{platform}",
major = self.major,
Expand Down Expand Up @@ -416,6 +429,7 @@ impl PythonInterpreter {
/// Linux: steinlaus.cpython-35m-x86_64-linux-gnu.so
/// Windows: steinlaus.cp35-win_amd64.pyd
/// Mac: steinlaus.cpython-35m-darwin.so
/// FreeBSD: steinlaus.cpython-35m.so
///
/// For pypy3, we read sysconfig.get_config_var("EXT_SUFFIX").
///
Expand All @@ -426,7 +440,15 @@ impl PythonInterpreter {
Interpreter::CPython => {
let platform = self.target.get_shared_platform_tag();

if self.target.is_unix() {
if self.target.is_freebsd() {
format!(
"{base}.cpython-{major}{minor}{abiflags}.so",
base = base,
major = self.major,
minor = self.minor,
abiflags = self.abiflags,
)
} else if self.target.is_unix() {
format!(
"{base}.cpython-{major}{minor}{abiflags}-{platform}.so",
base = base,
Expand Down Expand Up @@ -519,6 +541,7 @@ impl PythonInterpreter {
ext_suffix: message.ext_suffix,
interpreter,
abi_tag: message.abi_tag,
release: message.release,
}))
}

Expand Down
11 changes: 11 additions & 0 deletions src/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ enum OS {
Linux,
Windows,
Macos,
FreeBSD,
}

/// Decides how to handle manylinux compliance
Expand Down Expand Up @@ -60,6 +61,7 @@ impl Target {
"linux" => OS::Linux,
"windows" => OS::Windows,
"macos" => OS::Macos,
"freebsd" => OS::FreeBSD,
unsupported => panic!("The platform {} is not supported", unsupported),
};

Expand Down Expand Up @@ -89,6 +91,7 @@ impl Target {
platforms::target::OS::Linux => OS::Linux,
platforms::target::OS::Windows => OS::Windows,
platforms::target::OS::MacOS => OS::Macos,
platforms::target::OS::FreeBSD => OS::FreeBSD,
unsupported => bail!("The operating system {:?} is not supported", unsupported),
};

Expand Down Expand Up @@ -120,6 +123,11 @@ impl Target {
self.os == OS::Linux
}

/// Returns true if the current platform is freebsd
pub fn is_freebsd(&self) -> bool {
self.os == OS::FreeBSD
}

/// Returns true if the current platform is mac os
pub fn is_macos(&self) -> bool {
self.os == OS::Macos
Expand Down Expand Up @@ -147,6 +155,8 @@ impl Target {
(&OS::Windows, false, _) => "win32",
(&OS::Macos, true, _) => "macosx_10_7_x86_64",
(&OS::Macos, false, _) => panic!("32-bit wheels are not supported for mac os"),
(&OS::FreeBSD, true, _) => "freebsd_{release}_amd64",
(&OS::FreeBSD, false, _) => panic!("32-bit wheels are not supported for FreeBSD"),
}
}

Expand All @@ -169,6 +179,7 @@ impl Target {
}
}
OS::Macos => "darwin",
OS::FreeBSD => "", // according imp.get_suffixes(), there are no such
OS::Windows => {
if self.is_64_bit {
"win_amd64"
Expand Down

0 comments on commit 12cff71

Please sign in to comment.