Skip to content

Commit

Permalink
Best-effort build
Browse files Browse the repository at this point in the history
  • Loading branch information
ijl committed Jul 19, 2022
1 parent 8512f7f commit 7426f60
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 58 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,9 @@ unstable-simd = [
"simdutf8/aarch64_neon",
]

# Build yyjson as a backend.
yyjson = [
"cc",
]
# Build yyjson as a backend and panic if it fails. The default is to attempt
# to build and on failure fall back to another backend.
yyjson = []

[dependencies]
ahash = { version = "0.7", default_features = false }
Expand All @@ -85,8 +84,9 @@ simdutf8 = { version = "0.1", default_features = false, features = ["std"] }
smallvec = { version = "^1.8", default_features = false, features = ["union", "write"] }

[build-dependencies]
cc = { version = "1", optional = true }
cc = { version = "1" }
pyo3-build-config = "^0.16.5"
version_check = { version = "0.9" }

[profile.release]
codegen-units = 1
Expand Down
15 changes: 6 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1146,19 +1146,16 @@ Probably not.
## Packaging

To package orjson requires at least [Rust](https://www.rust-lang.org/) 1.54
and the [maturin](https://github.com/PyO3/maturin) build tool. It benefits
from also having `clang`. The recommended build command is:
and the [maturin](https://github.com/PyO3/maturin) build tool. The recommended
build command is:

```sh
maturin build --release --strip --features=yyjson
maturin build --release --strip
```

To build without use of `clang`, do not specify `--features=yyjson`.
Deserialization is much faster if built with this feature.

There is a minor performance benefit on at least amd64 to building on `nightly`
with `--features=unstable-simd`. It may be more significant on other
architectures.
It benefits from also having a C build environment to compile a faster
deserialization backend. See this project's `manylinux_2_28` builds for an
example using clang and LTO.

The project's own CI tests against `nightly-2022-06-22` and stable 1.54. It
is prudent to pin the nightly version because that channel can introduce
Expand Down
51 changes: 38 additions & 13 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,44 @@
// SPDX-License-Identifier: (Apache-2.0 OR MIT)

#[allow(dead_code)]
#[cfg(feature = "yyjson")]
fn build_yyjson() {
cc::Build::new()
.file("include/yyjson/yyjson.c")
.include("include/yyjson")
.define("YYJSON_DISABLE_WRITER", "1")
.define("YYJSON_DISABLE_NON_STANDARD", "1")
.compile("yyjson");
}

fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=include/yyjson/*");
println!("cargo:rerun-if-env-changed=CC");
println!("cargo:rerun-if-env-changed=CFLAGS");
println!("cargo:rerun-if-env-changed=LDFLAGS");
println!("cargo:rerun-if-env-changed=RUSTFLAGS");
println!("cargo:rerun-if-env-changed=ORJSON_DISABLE_YYJSON");

pyo3_build_config::use_pyo3_cfgs();

#[cfg(feature = "yyjson")]
build_yyjson();
if let Some(true) = version_check::supports_feature("core_intrinsics") {
println!("cargo:rustc-cfg=feature=\"intrinsics\"");
}

if let Some(true) = version_check::supports_feature("optimize_attribute") {
println!("cargo:rustc-cfg=feature=\"optimize\"");
}

if std::env::var("ORJSON_DISABLE_YYJSON").is_ok() {
if std::env::var("CARGO_FEATURE_YYJSON").is_ok() {
panic!("ORJSON_DISABLE_YYJSON and --features=yyjson both enabled.")
}
} else {
match cc::Build::new()
.file("include/yyjson/yyjson.c")
.include("include/yyjson")
.define("YYJSON_DISABLE_WRITER", "1")
.define("YYJSON_DISABLE_NON_STANDARD", "1")
.try_compile("yyjson")
{
Ok(_) => {
println!("cargo:rustc-cfg=feature=\"yyjson\"");
}
Err(_) => {
if std::env::var("CARGO_FEATURE_YYJSON").is_ok() {
panic!("yyjson was enabled but the build failed. To build with a different backend do not specify the feature.")
}
}
}
}
}
7 changes: 1 addition & 6 deletions src/deserialize/utf8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,11 @@ fn is_valid_utf8(buf: &[u8]) -> bool {
}
}

#[cfg(all(target_arch = "aarch64", feature = "unstable-simd"))]
#[cfg(target_arch = "aarch64")]
fn is_valid_utf8(buf: &[u8]) -> bool {
simdutf8::basic::from_utf8(buf).is_ok()
}

#[cfg(all(target_arch = "aarch64", not(feature = "unstable-simd")))]
fn is_valid_utf8(buf: &[u8]) -> bool {
std::str::from_utf8(buf).is_ok()
}

#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
fn is_valid_utf8(buf: &[u8]) -> bool {
std::str::from_utf8(buf).is_ok()
Expand Down
12 changes: 6 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: (Apache-2.0 OR MIT)

#![cfg_attr(feature = "unstable-simd", feature(core_intrinsics))]
#![cfg_attr(feature = "unstable-simd", feature(optimize_attribute))]
#![cfg_attr(feature = "intrinsics", feature(core_intrinsics))]
#![cfg_attr(feature = "optimize", feature(optimize_attribute))]
#![allow(unused_unsafe)]
#![allow(clippy::missing_safety_doc)]
#![allow(clippy::redundant_field_names)]
Expand Down Expand Up @@ -60,7 +60,7 @@ macro_rules! opt {
#[allow(non_snake_case)]
#[no_mangle]
#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
pub unsafe extern "C" fn orjson_init_exec(mptr: *mut PyObject) -> c_int {
typeref::init_typerefs();
{
Expand Down Expand Up @@ -193,7 +193,7 @@ pub unsafe extern "C" fn orjson_init_exec(mptr: *mut PyObject) -> c_int {
#[allow(non_snake_case)]
#[no_mangle]
#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
pub unsafe extern "C" fn PyInit_orjson() -> *mut PyModuleDef {
let mod_slots: Box<[PyModuleDef_Slot; 2]> = Box::new([
PyModuleDef_Slot {
Expand Down Expand Up @@ -224,7 +224,7 @@ pub unsafe extern "C" fn PyInit_orjson() -> *mut PyModuleDef {

#[cold]
#[inline(never)]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
fn raise_loads_exception(err: deserialize::DeserializeError) -> *mut PyObject {
let pos = err.pos();
let msg = err.message;
Expand All @@ -246,7 +246,7 @@ fn raise_loads_exception(err: deserialize::DeserializeError) -> *mut PyObject {

#[cold]
#[inline(never)]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
fn raise_dumps_exception(msg: Cow<str>) -> *mut PyObject {
unsafe {
let err_msg =
Expand Down
2 changes: 1 addition & 1 deletion src/serialize/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub enum SerializeError {

impl std::fmt::Display for SerializeError {
#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
SerializeError::DatetimeLibraryUnsupported => write!(f, "datetime's timezone library is not supported: use datetime.timezone.utc, pendulum, pytz, or dateutil"),
Expand Down
4 changes: 2 additions & 2 deletions src/serialize/numpy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ pub enum NumpyDatetimeUnit {

impl fmt::Display for NumpyDatetimeUnit {
#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let unit = match self {
Self::NaT => "NaT",
Expand Down Expand Up @@ -693,7 +693,7 @@ enum NumpyDateTimeError {

impl NumpyDateTimeError {
#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
fn into_serde_err<T: ser::Error>(self) -> T {
let err = match self {
Self::UnsupportedUnit(unit) => format!("unsupported numpy.datetime64 unit: {}", unit),
Expand Down
2 changes: 1 addition & 1 deletion src/serialize/serializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ macro_rules! is_subclass {
}

#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
#[inline(never)]
pub fn pyobject_to_obtype_unlikely(obj: *mut pyo3_ffi::PyObject, opts: Opt) -> ObType {
unsafe {
Expand Down
22 changes: 11 additions & 11 deletions src/typeref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ pub static mut JsonDecodeError: *mut PyObject = 0 as *mut PyObject;
static INIT: Once = Once::new();

#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
pub fn init_typerefs() {
INIT.call_once(|| unsafe {
assert!(crate::deserialize::KEY_MAP
Expand Down Expand Up @@ -171,7 +171,7 @@ pub fn init_typerefs() {
}

#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
unsafe fn look_up_json_exc() -> *mut PyObject {
let module = PyImport_ImportModule("json\0".as_ptr() as *const c_char);
let module_dict = PyObject_GenericGetDict(module, std::ptr::null_mut());
Expand All @@ -190,7 +190,7 @@ unsafe fn look_up_json_exc() -> *mut PyObject {
}

#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
unsafe fn look_up_numpy_type(numpy_module: *mut PyObject, np_type: &str) -> *mut PyTypeObject {
let mod_dict = PyObject_GenericGetDict(numpy_module, std::ptr::null_mut());
let ptr = PyMapping_GetItemString(mod_dict, np_type.as_ptr() as *const c_char);
Expand All @@ -200,7 +200,7 @@ unsafe fn look_up_numpy_type(numpy_module: *mut PyObject, np_type: &str) -> *mut
}

#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
unsafe fn load_numpy_types() -> Option<NumpyTypes> {
let numpy = PyImport_ImportModule("numpy\0".as_ptr() as *const c_char);
if numpy.is_null() {
Expand All @@ -226,7 +226,7 @@ unsafe fn load_numpy_types() -> Option<NumpyTypes> {
}

#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
unsafe fn look_up_field_type() -> NonNull<PyObject> {
let module = PyImport_ImportModule("dataclasses\0".as_ptr() as *const c_char);
let module_dict = PyObject_GenericGetDict(module, std::ptr::null_mut());
Expand All @@ -238,7 +238,7 @@ unsafe fn look_up_field_type() -> NonNull<PyObject> {
}

#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
unsafe fn look_up_enum_type() -> *mut PyTypeObject {
let module = PyImport_ImportModule("enum\0".as_ptr() as *const c_char);
let module_dict = PyObject_GenericGetDict(module, std::ptr::null_mut());
Expand All @@ -250,7 +250,7 @@ unsafe fn look_up_enum_type() -> *mut PyTypeObject {
}

#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
unsafe fn look_up_uuid_type() -> *mut PyTypeObject {
let uuid_mod = PyImport_ImportModule("uuid\0".as_ptr() as *const c_char);
let uuid_mod_dict = PyObject_GenericGetDict(uuid_mod, std::ptr::null_mut());
Expand All @@ -263,7 +263,7 @@ unsafe fn look_up_uuid_type() -> *mut PyTypeObject {
}

#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
unsafe fn look_up_datetime_type() -> *mut PyTypeObject {
let datetime = ((*PyDateTimeAPI()).DateTime_FromDateAndTime)(
1970,
Expand All @@ -282,7 +282,7 @@ unsafe fn look_up_datetime_type() -> *mut PyTypeObject {
}

#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
unsafe fn look_up_date_type() -> *mut PyTypeObject {
let date = ((*PyDateTimeAPI()).Date_FromDate)(1, 1, 1, (*(PyDateTimeAPI())).DateType);
let ptr = (*date).ob_type;
Expand All @@ -291,7 +291,7 @@ unsafe fn look_up_date_type() -> *mut PyTypeObject {
}

#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
unsafe fn look_up_time_type() -> *mut PyTypeObject {
let time = ((*PyDateTimeAPI()).Time_FromTime)(0, 0, 0, 0, NONE, (*(PyDateTimeAPI())).TimeType);
let ptr = (*time).ob_type;
Expand All @@ -301,7 +301,7 @@ unsafe fn look_up_time_type() -> *mut PyTypeObject {

#[cfg(Py_3_9)]
#[cold]
#[cfg_attr(feature = "unstable-simd", optimize(size))]
#[cfg_attr(feature = "optimize", optimize(size))]
unsafe fn look_up_zoneinfo_type() -> *mut PyTypeObject {
let module = PyImport_ImportModule("zoneinfo\0".as_ptr() as *const c_char);
let module_dict = PyObject_GenericGetDict(module, std::ptr::null_mut());
Expand Down
4 changes: 2 additions & 2 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ macro_rules! err {
};
}

#[cfg(feature = "unstable-simd")]
#[cfg(feature = "intrinsics")]
macro_rules! unlikely {
($exp:expr) => {
core::intrinsics::unlikely($exp)
};
}

#[cfg(not(feature = "unstable-simd"))]
#[cfg(not(feature = "intrinsics"))]
macro_rules! unlikely {
($exp:expr) => {
$exp
Expand Down

0 comments on commit 7426f60

Please sign in to comment.