This is an automated email from the ASF dual-hosted git repository.
kontinuation pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/sedona-db.git
The following commit(s) were added to refs/heads/main by this push:
new a8750988 refactor(c/sedona-proj): replace C dynamic loading with pure
Rust using libloading (#672)
a8750988 is described below
commit a8750988955f375304239adee580ff0af54abad8
Author: Kristin Cowalcijk <[email protected]>
AuthorDate: Tue Mar 3 18:46:03 2026 +0800
refactor(c/sedona-proj): replace C dynamic loading with pure Rust using
libloading (#672)
## Summary
Replace the C-based `dlopen`/`dlsym` dynamic PROJ loading
(`proj_dyn.c`/`proj_dyn.h`) with a pure Rust implementation using the
`libloading` crate. This eliminates ~250 lines of C code while maintaining the
same `ProjApi` struct-of-function-pointers architecture used by all existing
call sites.
## Approach
The `libloading` crate provides safe, cross-platform dynamic library
loading (`dlopen`/`LoadLibrary`). Each PROJ symbol is loaded via a `load_fn!`
macro that:
1. Loads the symbol as a raw `*const ()` pointer
2. Transmutes it to the expected function pointer type
3. Stores it in the existing `ProjApi` `#[repr(C)]` struct
The `Library` handle is stored as `_lib: Option<Library>` in the Rust
`ProjApi` wrapper — `Some` when loaded from a shared library, `None` when using
`proj-sys`. This ensures the library stays loaded for the lifetime of the
function pointers.
## Tests
Temporarily enabled python-wheels test and passed on all major platforms:
https://github.com/apache/sedona-db/actions/runs/22518558723
## Upcoming Changes
We'll implement c/sedona-gdal using similar approach.
Co-authored-by: Copilot <[email protected]>
---
Cargo.lock | 12 ++-
Cargo.toml | 1 +
c/sedona-proj/Cargo.toml | 4 +-
c/sedona-proj/build.rs | 22 -----
c/sedona-proj/src/dyn_load.rs | 99 ++++++++++++++++++++++
c/sedona-proj/src/lib.rs | 1 +
c/sedona-proj/src/proj.rs | 50 +++---------
c/sedona-proj/src/proj_dyn.c | 150 ----------------------------------
c/sedona-proj/src/proj_dyn.h | 97 ----------------------
c/sedona-proj/src/proj_dyn_bindgen.rs | 12 +--
10 files changed, 127 insertions(+), 321 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 7292f3dc..ac91274b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3700,6 +3700,16 @@ dependencies = [
"windows-link",
]
+[[package]]
+name = "libloading"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60"
+dependencies = [
+ "cfg-if",
+ "windows-link",
+]
+
[[package]]
name = "libm"
version = "0.2.15"
@@ -5466,12 +5476,12 @@ dependencies = [
"approx",
"arrow-array",
"arrow-schema",
- "cc",
"criterion",
"datafusion-common",
"datafusion-expr",
"geo-traits",
"geo-types",
+ "libloading 0.9.0",
"proj-sys",
"rstest",
"sedona-common",
diff --git a/Cargo.toml b/Cargo.toml
index 9ba32574..abe66917 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -105,6 +105,7 @@ geos = { version = "11.0.1", features = ["geo", "v3_12_0"] }
glam = "0.32.0"
libmimalloc-sys = { version = "0.1", default-features = false }
log = "^0.4"
+libloading = "0.9"
lru = "0.16"
mimalloc = { version = "0.1", default-features = false }
num-traits = { version = "0.2", default-features = false, features = ["libm"] }
diff --git a/c/sedona-proj/Cargo.toml b/c/sedona-proj/Cargo.toml
index 0a145fd1..072f15bb 100644
--- a/c/sedona-proj/Cargo.toml
+++ b/c/sedona-proj/Cargo.toml
@@ -28,9 +28,6 @@ readme.workspace = true
edition.workspace = true
rust-version.workspace = true
-[build-dependencies]
-cc = { version = "1" }
-
[dev-dependencies]
approx = { workspace = true }
geo-types = { workspace = true }
@@ -44,6 +41,7 @@ default = [ "proj-sys" ]
proj-sys = [ "dep:proj-sys" ]
[dependencies]
+libloading = { workspace = true }
serde_json = { workspace = true }
arrow-schema = { workspace = true }
arrow-array = { workspace = true }
diff --git a/c/sedona-proj/build.rs b/c/sedona-proj/build.rs
deleted file mode 100644
index f62fd8a6..00000000
--- a/c/sedona-proj/build.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-fn main() {
- println!("cargo:rerun-if-changed=src/proj_dyn.c");
-
- cc::Build::new().file("src/proj_dyn.c").compile("proj_dyn");
-}
diff --git a/c/sedona-proj/src/dyn_load.rs b/c/sedona-proj/src/dyn_load.rs
new file mode 100644
index 00000000..ee7f6495
--- /dev/null
+++ b/c/sedona-proj/src/dyn_load.rs
@@ -0,0 +1,99 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use std::path::Path;
+
+use libloading::Library;
+
+use crate::error::SedonaProjError;
+use crate::proj_dyn_bindgen::ProjApi;
+
+/// Load a single symbol from the library and write it into the given field.
+///
+/// We load as a raw `*const ()` pointer and transmute to the target function
pointer
+/// type. This is the standard pattern for dynamic symbol loading where the
loaded
+/// symbol's signature is known but cannot be expressed as a generic parameter
to
+/// `Library::get` (because each field has a different signature).
+///
+/// On failure returns a `SedonaProjError` with the symbol name and the
+/// underlying OS error message.
+macro_rules! load_fn {
+ ($lib:expr, $api:expr, $name:ident) => {
+ // The target types here are too verbose to annotate for each call site
+ #[allow(clippy::missing_transmute_annotations)]
+ {
+ $api.$name = Some(unsafe {
+ let sym = $lib
+ .get::<*const ()>(concat!(stringify!($name),
"\0").as_bytes())
+ .map_err(|e| {
+ SedonaProjError::LibraryError(format!(
+ "Failed to load symbol {}: {}",
+ stringify!($name),
+ e
+ ))
+ })?;
+ std::mem::transmute(sym.into_raw().into_raw())
+ });
+ }
+ };
+}
+
+/// Populate all 21 function-pointer fields of [`ProjApi`] from the given
+/// [`Library`] handle.
+fn load_all_symbols(lib: &Library, api: &mut ProjApi) -> Result<(),
SedonaProjError> {
+ load_fn!(lib, api, proj_area_create);
+ load_fn!(lib, api, proj_area_destroy);
+ load_fn!(lib, api, proj_area_set_bbox);
+ load_fn!(lib, api, proj_context_create);
+ load_fn!(lib, api, proj_context_destroy);
+ load_fn!(lib, api, proj_context_errno_string);
+ load_fn!(lib, api, proj_context_errno);
+ load_fn!(lib, api, proj_context_set_database_path);
+ load_fn!(lib, api, proj_context_set_search_paths);
+ load_fn!(lib, api, proj_create_crs_to_crs_from_pj);
+ load_fn!(lib, api, proj_create);
+ load_fn!(lib, api, proj_cs_get_axis_count);
+ load_fn!(lib, api, proj_destroy);
+ load_fn!(lib, api, proj_errno_reset);
+ load_fn!(lib, api, proj_errno);
+ load_fn!(lib, api, proj_info);
+ load_fn!(lib, api, proj_log_level);
+ load_fn!(lib, api, proj_normalize_for_visualization);
+ load_fn!(lib, api, proj_trans);
+ load_fn!(lib, api, proj_trans_array);
+ load_fn!(lib, api, proj_as_projjson);
+
+ Ok(())
+}
+
+/// Load a PROJ shared library from `path` and populate a [`ProjApi`] struct.
+///
+/// Returns the `(Library, ProjApi)` pair. The caller is responsible for
+/// keeping the `Library` alive for the lifetime of the function pointers.
+pub(crate) fn load_proj_from_path(path: &Path) -> Result<(Library, ProjApi),
SedonaProjError> {
+ let lib = unsafe { Library::new(path.as_os_str()) }.map_err(|e| {
+ SedonaProjError::LibraryError(format!(
+ "Failed to load PROJ library from {}: {}",
+ path.display(),
+ e
+ ))
+ })?;
+
+ let mut api = ProjApi::default();
+ load_all_symbols(&lib, &mut api)?;
+ Ok((lib, api))
+}
diff --git a/c/sedona-proj/src/lib.rs b/c/sedona-proj/src/lib.rs
index 6cc48eab..3cffe6fe 100644
--- a/c/sedona-proj/src/lib.rs
+++ b/c/sedona-proj/src/lib.rs
@@ -14,6 +14,7 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
+mod dyn_load;
pub mod error;
mod proj;
mod proj_dyn_bindgen;
diff --git a/c/sedona-proj/src/proj.rs b/c/sedona-proj/src/proj.rs
index e52eb295..b267af41 100644
--- a/c/sedona-proj/src/proj.rs
+++ b/c/sedona-proj/src/proj.rs
@@ -42,7 +42,9 @@ use std::{
sync::Arc,
};
-use crate::{error::SedonaProjError, proj_dyn_bindgen};
+use libloading::Library;
+
+use crate::{dyn_load, error::SedonaProjError, proj_dyn_bindgen};
/// A macro to safely call a function pointer from a ProjApi
///
@@ -449,24 +451,16 @@ impl Proj {
/// loaded using C code; however, this could be migrated to Rust which also
/// provides dynamic library loading capabilities.
///
-/// This API is thread safe and is marked as such; however, clients must not
-/// call the inner release callback. Doing so will set function pointers to
-/// null, which will cause subsequent calls to panic.
-#[derive(Default)]
+/// This API is thread safe and is marked as such. When loading PROJ from a
+/// shared library, the `_lib` field holds the `Library` handle, ensuring that
+/// the underlying library and its function pointers remain valid for the
+/// lifetime of this `ProjApi` instance.
struct ProjApi {
inner: proj_dyn_bindgen::ProjApi,
name: String,
-}
-
-unsafe impl Send for ProjApi {}
-unsafe impl Sync for ProjApi {}
-
-impl Drop for ProjApi {
- fn drop(&mut self) {
- if let Some(releaser) = self.inner.release {
- unsafe { releaser(&mut self.inner) }
- }
- }
+ /// Keep the dynamically loaded library alive for the lifetime of the
function pointers.
+ /// `None` when using `proj-sys` (statically linked), `Some` when loaded
from a shared library.
+ _lib: Option<Library>,
}
impl Debug for ProjApi {
@@ -477,31 +471,12 @@ impl Debug for ProjApi {
impl ProjApi {
fn try_from_shared_library(shared_library: PathBuf) -> Result<Arc<Self>,
SedonaProjError> {
- let mut inner = proj_dyn_bindgen::ProjApi::default();
- let mut err_message = (0..1024).map(|_| 0).collect::<Vec<u8>>();
- let shared_library_c =
CString::new(shared_library.to_string_lossy().to_string())
- .map_err(|_| SedonaProjError::Invalid("embedded nul in Rust
string".to_string()))?;
-
- let err = unsafe {
- proj_dyn_bindgen::proj_dyn_api_init(
- &mut inner as _,
- shared_library_c.as_ptr(),
- err_message.as_mut_ptr() as _,
- err_message.len().try_into().unwrap(),
- )
- };
-
- let c_err_message = CStr::from_bytes_until_nul(&err_message)
- .map_err(|_| SedonaProjError::Invalid("embedded nul in C
string".to_string()))?;
- if err != 0 {
- return Err(SedonaProjError::LibraryError(
- c_err_message.to_string_lossy().to_string(),
- ));
- }
+ let (lib, inner) = dyn_load::load_proj_from_path(&shared_library)?;
Ok(Arc::new(Self {
inner,
name: shared_library.to_string_lossy().to_string(),
+ _lib: Some(lib),
}))
}
@@ -624,6 +599,7 @@ impl ProjApi {
Self {
inner,
name: "proj_sys".to_string(),
+ _lib: None,
}
}
}
diff --git a/c/sedona-proj/src/proj_dyn.c b/c/sedona-proj/src/proj_dyn.c
deleted file mode 100644
index 69c54217..00000000
--- a/c/sedona-proj/src/proj_dyn.c
+++ /dev/null
@@ -1,150 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-#include "proj_dyn.h"
-
-// Original source:
-//
https://github.com/apache/sedona/blob/670bb4c4a6fea49f0b0159ebdf2a92f00d3ed07a/python/src/geos_c_dyn.c
-
-#if defined(_WIN32)
-#define TARGETING_WINDOWS
-#include <tchar.h>
-#include <windows.h>
-#else
-#include <dlfcn.h>
-#include <errno.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef TARGETING_WINDOWS
-static void win32_get_last_error(char* err_msg, int len) {
- wchar_t info[256];
- unsigned int error_code = GetLastError();
- int info_length = FormatMessageW(
- FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, /* flags */
- NULL, /* message
source*/
- error_code, /* the message (error) ID */
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* default language */
- info, /* the buffer */
- sizeof(info) / sizeof(wchar_t), /* size in wchars */
- NULL);
- int num_bytes =
- WideCharToMultiByte(CP_UTF8, 0, info, info_length, err_msg, len, NULL,
NULL);
- num_bytes = (num_bytes < (len - 1)) ? num_bytes : (len - 1);
- err_msg[num_bytes] = '\0';
-}
-#endif
-
-static void* try_load_proj_symbol(void* handle, const char* func_name) {
-#ifndef TARGETING_WINDOWS
- return dlsym(handle, func_name);
-#else
- return GetProcAddress((HMODULE)handle, func_name);
-#endif
-}
-
-static int load_proj_symbol(void* handle, const char* func_name, void** p_func,
- char* err_msg, int len) {
- void* func = try_load_proj_symbol(handle, func_name);
- if (func == NULL) {
-#ifndef TARGETING_WINDOWS
- snprintf(err_msg, len, "%s", dlerror());
-#else
- win32_get_last_error(err_msg, len);
-#endif
- return -1;
- }
- *p_func = func;
- return 0;
-}
-
-#define LOAD_PROJ_FUNCTION(api, func)
\
- if (load_proj_symbol(handle, #func, (void**)(&(api)->func), err_msg, len) !=
0) { \
- proj_dyn_release_api(api);
\
- return -1;
\
- }
-
-static void proj_dyn_release_api(struct ProjApi* api) {
-#ifdef TARGETING_WINDOWS
- FreeLibrary((HMODULE)api->private_data);
-#else
- dlclose(api->private_data);
-#endif
- memset(api, 0, sizeof(struct ProjApi));
-}
-
-static int load_proj_from_handle(struct ProjApi* api, void* handle, char*
err_msg,
- int len) {
- LOAD_PROJ_FUNCTION(api, proj_area_create);
- LOAD_PROJ_FUNCTION(api, proj_area_destroy);
- LOAD_PROJ_FUNCTION(api, proj_area_set_bbox);
- LOAD_PROJ_FUNCTION(api, proj_context_create);
- LOAD_PROJ_FUNCTION(api, proj_context_destroy);
- LOAD_PROJ_FUNCTION(api, proj_context_errno_string);
- LOAD_PROJ_FUNCTION(api, proj_context_errno);
- LOAD_PROJ_FUNCTION(api, proj_context_set_database_path);
- LOAD_PROJ_FUNCTION(api, proj_context_set_search_paths);
- LOAD_PROJ_FUNCTION(api, proj_create_crs_to_crs_from_pj);
- LOAD_PROJ_FUNCTION(api, proj_create);
- LOAD_PROJ_FUNCTION(api, proj_cs_get_axis_count);
- LOAD_PROJ_FUNCTION(api, proj_destroy);
- LOAD_PROJ_FUNCTION(api, proj_errno_reset);
- LOAD_PROJ_FUNCTION(api, proj_errno);
- LOAD_PROJ_FUNCTION(api, proj_info);
- LOAD_PROJ_FUNCTION(api, proj_log_level);
- LOAD_PROJ_FUNCTION(api, proj_normalize_for_visualization);
- LOAD_PROJ_FUNCTION(api, proj_trans);
- LOAD_PROJ_FUNCTION(api, proj_trans_array);
- LOAD_PROJ_FUNCTION(api, proj_as_projjson);
-
- api->release = &proj_dyn_release_api;
- api->private_data = handle;
-
- return 0;
-}
-
-#undef LOAD_PROJ_FUNCTION
-
-int proj_dyn_api_init(struct ProjApi* api, const char* shared_object_path,
char* err_msg,
- int len) {
-#ifndef TARGETING_WINDOWS
- void* handle = dlopen(shared_object_path, RTLD_LOCAL | RTLD_NOW);
- if (handle == NULL) {
- snprintf(err_msg, len, "%s", dlerror());
- return -1;
- }
-#else
- int num_chars = MultiByteToWideChar(CP_UTF8, 0, shared_object_path, -1,
NULL, 0);
- wchar_t* wpath = calloc(num_chars, sizeof(wchar_t));
- if (wpath == NULL) {
- snprintf(err_msg, len, "%s", "Cannot allocate memory for wpath");
- return -1;
- }
- MultiByteToWideChar(CP_UTF8, 0, shared_object_path, -1, wpath, num_chars);
- HMODULE module = LoadLibraryW(wpath);
- free(wpath);
- if (module == NULL) {
- win32_get_last_error(err_msg, len);
- return -1;
- }
- void* handle = module;
-#endif
- return load_proj_from_handle(api, handle, err_msg, len);
-}
diff --git a/c/sedona-proj/src/proj_dyn.h b/c/sedona-proj/src/proj_dyn.h
deleted file mode 100644
index 81e80503..00000000
--- a/c/sedona-proj/src/proj_dyn.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-#include <stddef.h>
-
-#ifndef PROJ_DYN_H_INCLUDED
-#define PROJ_DYN_H_INCLUDED
-
-// Type definitions copied from proj.h
-struct pj_ctx;
-typedef struct pj_ctx PJ_CONTEXT;
-
-struct PJ_AREA;
-typedef struct PJ_AREA PJ_AREA;
-
-struct PJconsts;
-typedef struct PJconsts PJ;
-
-typedef struct {
- double x, y, z, t;
-} PJ_XYZT;
-
-typedef union {
- double v[4];
- PJ_XYZT xyzt;
-} PJ_COORD;
-
-typedef enum { PJ_FWD = 1, PJ_IDENT = 0, PJ_INV = -1 } PJ_DIRECTION;
-
-typedef enum PJ_LOG_LEVEL {
- PJ_LOG_NONE = 0,
- PJ_LOG_ERROR = 1,
- PJ_LOG_DEBUG = 2,
- PJ_LOG_TRACE = 3,
- PJ_LOG_TELL = 4,
-} PJ_LOG_LEVEL;
-
-typedef struct {
- int major;
- int minor;
- int patch;
- const char* release;
- const char* version;
- const char* searchpath;
-} PJ_INFO;
-
-struct ProjApi {
- PJ_AREA* (*proj_area_create)(void);
- void (*proj_area_destroy)(PJ_AREA* area);
- int (*proj_area_set_bbox)(PJ_AREA* area, double west_lon_degree,
- double south_lat_degree, double east_lon_degree,
- double north_lat_degree);
- PJ_CONTEXT* (*proj_context_create)(void);
- void (*proj_context_destroy)(PJ_CONTEXT* ctx);
- int (*proj_context_errno)(PJ_CONTEXT* ctx);
- const char* (*proj_context_errno_string)(PJ_CONTEXT* ctx, int err);
- int (*proj_context_set_database_path)(PJ_CONTEXT* ctx, const char* dbPath,
- const char* const* auxDbPaths,
- const char* const* options);
- void (*proj_context_set_search_paths)(PJ_CONTEXT* ctx, int count_paths,
- const char* const* paths);
- PJ* (*proj_create)(PJ_CONTEXT* ctx, const char* definition);
- PJ* (*proj_create_crs_to_crs_from_pj)(PJ_CONTEXT* ctx, PJ* source_crs, PJ*
target_crs,
- PJ_AREA* area, const char* const*
options);
- int (*proj_cs_get_axis_count)(PJ_CONTEXT* ctx, const PJ* cs);
- void (*proj_destroy)(PJ* P);
- int (*proj_errno)(const PJ* P);
- void (*proj_errno_reset)(PJ* P);
- PJ_INFO (*proj_info)(void);
- PJ_LOG_LEVEL (*proj_log_level)(PJ_CONTEXT* ctx, PJ_LOG_LEVEL level);
- PJ* (*proj_normalize_for_visualization)(PJ_CONTEXT* ctx, const PJ* obj);
- PJ_COORD (*proj_trans)(PJ* P, PJ_DIRECTION direction, PJ_COORD coord);
- PJ_COORD (*proj_trans_array)(PJ* P, PJ_DIRECTION direction, size_t n,
PJ_COORD* coord);
- const char* (*proj_as_projjson)(PJ_CONTEXT* ctx, const PJ* obj,
- const char* const* options);
- void (*release)(struct ProjApi*);
- void* private_data;
-};
-
-int proj_dyn_api_init(struct ProjApi* api, const char* shared_object_path,
char* err_msg,
- int len);
-
-#endif
diff --git a/c/sedona-proj/src/proj_dyn_bindgen.rs
b/c/sedona-proj/src/proj_dyn_bindgen.rs
index 55ea2d9a..3e5c41b9 100644
--- a/c/sedona-proj/src/proj_dyn_bindgen.rs
+++ b/c/sedona-proj/src/proj_dyn_bindgen.rs
@@ -18,7 +18,7 @@
#![allow(non_snake_case)]
#![allow(dead_code)]
-use std::os::raw::{c_char, c_int, c_uint, c_void};
+use std::os::raw::{c_char, c_int, c_uint};
#[repr(C)]
#[derive(Debug, Copy, Clone)]
@@ -153,14 +153,4 @@ pub struct ProjApi {
) -> *const c_char,
>,
pub release: Option<unsafe extern "C" fn(arg1: *mut ProjApi)>,
- pub private_data: *mut c_void,
-}
-
-unsafe extern "C" {
- pub fn proj_dyn_api_init(
- api: *mut ProjApi,
- shared_object_path: *const c_char,
- err_msg: *mut c_char,
- len: c_int,
- ) -> c_int;
}