Skip to content

Commit

Permalink
generate bindings for non-public extern items
Browse files Browse the repository at this point in the history
Signed-off-by: Marin Veršić <marin.versic101@gmail.com>
  • Loading branch information
mversic authored and emilio committed Aug 25, 2023
1 parent acb1b8d commit 5f235ec
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 73 deletions.
10 changes: 6 additions & 4 deletions src/bindgen/ir/global.rs
Expand Up @@ -4,8 +4,6 @@

use std::io::Write;

use syn::ext::IdentExt;

use crate::bindgen::cdecl;
use crate::bindgen::config::Config;
use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver;
Expand All @@ -26,15 +24,19 @@ pub struct Static {
}

impl Static {
pub fn load(item: &syn::ItemStatic, mod_cfg: Option<&Cfg>) -> Result<Static, String> {
pub fn load(
path: Path,
item: &syn::ItemStatic,
mod_cfg: Option<&Cfg>,
) -> Result<Static, String> {
let ty = Type::load(&item.ty)?;

if ty.is_none() {
return Err("Cannot have a zero sized static definition.".to_owned());
}

Ok(Static::new(
Path::new(item.ident.unraw().to_string()),
path,
ty.unwrap(),
item.mutability.is_some(),
Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
Expand Down
96 changes: 30 additions & 66 deletions src/bindgen/parser.rs
Expand Up @@ -18,7 +18,7 @@ use crate::bindgen::ir::{
AnnotationSet, Cfg, Constant, Documentation, Enum, Function, GenericParam, GenericParams,
ItemMap, OpaqueItem, Path, Static, Struct, Type, Typedef, Union,
};
use crate::bindgen::utilities::{SynAbiHelpers, SynAttributeHelpers, SynItemFnHelpers};
use crate::bindgen::utilities::{SynAbiHelpers, SynAttributeHelpers, SynItemHelpers};

const STD_CRATES: &[&str] = &[
"std",
Expand Down Expand Up @@ -643,7 +643,6 @@ impl Parse {
item,
Some(self_type),
&item.sig,
&item.vis,
&item.attrs,
)
}
Expand All @@ -665,7 +664,6 @@ impl Parse {
item,
None,
&item.sig,
&item.vis,
&item.attrs,
);
}
Expand All @@ -677,10 +675,9 @@ impl Parse {
binding_crate_name: &str,
crate_name: &str,
mod_cfg: Option<&Cfg>,
named_symbol: &dyn SynItemFnHelpers,
named_symbol: &dyn SynItemHelpers,
self_type: Option<&Path>,
sig: &syn::Signature,
vis: &syn::Visibility,
attrs: &[syn::Attribute],
) {
if !config
Expand All @@ -707,53 +704,29 @@ impl Parse {
let is_extern_c = sig.abi.is_omitted() || sig.abi.is_c();
let exported_name = named_symbol.exported_name();

if let syn::Visibility::Public(_) = vis {
match (is_extern_c, exported_name) {
(true, Some(exported_name)) => {
let path = Path::new(exported_name);
match Function::load(path, self_type, sig, false, attrs, mod_cfg) {
Ok(func) => {
info!("Take {}.", loggable_item_name());
self.functions.push(func);
}
Err(msg) => {
error!("Cannot use fn {} ({}).", loggable_item_name(), msg);
}
match (is_extern_c, exported_name) {
(true, Some(exported_name)) => {
let path = Path::new(exported_name);
match Function::load(path, self_type, sig, false, attrs, mod_cfg) {
Ok(func) => {
info!("Take {}.", loggable_item_name());
self.functions.push(func);
}
Err(msg) => {
error!("Cannot use fn {} ({}).", loggable_item_name(), msg);
}
}
(true, None) => {
warn!(
"Skipping {} - (not `no_mangle`, and has no `export_name` attribute)",
loggable_item_name()
);
}
(false, Some(_exported_name)) => {
warn!("Skipping {} - (not `extern \"C\"`", loggable_item_name());
}
(false, None) => {}
}
} else {
match (is_extern_c, exported_name) {
(true, Some(..)) => {
warn!(
"Skipping {} - (not `pub` but is `extern \"C\"` and `no_mangle`)",
loggable_item_name()
);
}
(true, None) => {
warn!(
"Skipping {} - (not `pub` but is `extern \"C\"`)",
loggable_item_name()
);
}
(false, Some(..)) => {
warn!(
"Skipping {} - (not `pub` but is `no_mangle`)",
loggable_item_name()
);
}
(false, None) => {}
(true, None) => {
warn!(
"Skipping {} - (not `no_mangle`, and has no `export_name` attribute)",
loggable_item_name()
);
}
(false, Some(_exported_name)) => {
warn!("Skipping {} - (not `extern \"C\"`", loggable_item_name());
}
(false, None) => {}
}
}

Expand Down Expand Up @@ -892,27 +865,18 @@ impl Parse {
return;
}

if let syn::Visibility::Public(_) = item.vis {
if item.is_no_mangle() {
match Static::load(item, mod_cfg) {
Ok(constant) => {
info!("Take {}::{}.", crate_name, &item.ident);

self.globals.try_insert(constant);
}
Err(msg) => {
warn!("Skip {}::{} - ({})", crate_name, &item.ident, msg);
}
if let Some(exported_name) = item.exported_name() {
let path = Path::new(exported_name);
match Static::load(path, item, mod_cfg) {
Ok(constant) => {
info!("Take {}::{}.", crate_name, &item.ident);
self.globals.try_insert(constant);
}
Err(msg) => {
warn!("Skip {}::{} - ({})", crate_name, &item.ident, msg);
}
}
}

// TODO
if let syn::Visibility::Public(_) = item.vis {
} else {
warn!("Skip {}::{} - (not `pub`).", crate_name, &item.ident);
}
if !item.is_no_mangle() {
warn!("Skip {}::{} - (not `no_mangle`).", crate_name, &item.ident);
}
}
Expand Down
20 changes: 17 additions & 3 deletions src/bindgen/utilities.rs
Expand Up @@ -30,11 +30,11 @@ where
}
}

pub trait SynItemFnHelpers: SynAttributeHelpers {
pub trait SynItemHelpers: SynAttributeHelpers {
fn exported_name(&self) -> Option<String>;
}

impl SynItemFnHelpers for syn::ItemFn {
impl SynItemHelpers for syn::ItemFn {
fn exported_name(&self) -> Option<String> {
self.attrs
.attr_name_value_lookup("export_name")
Expand All @@ -48,7 +48,7 @@ impl SynItemFnHelpers for syn::ItemFn {
}
}

impl SynItemFnHelpers for syn::ImplItemMethod {
impl SynItemHelpers for syn::ImplItemMethod {
fn exported_name(&self) -> Option<String> {
self.attrs
.attr_name_value_lookup("export_name")
Expand All @@ -62,6 +62,20 @@ impl SynItemFnHelpers for syn::ImplItemMethod {
}
}

impl SynItemHelpers for syn::ItemStatic {
fn exported_name(&self) -> Option<String> {
self.attrs
.attr_name_value_lookup("export_name")
.or_else(|| {
if self.is_no_mangle() {
Some(self.ident.unraw().to_string())
} else {
None
}
})
}
}

/// Returns whether this attribute causes us to skip at item. This basically
/// checks for `#[cfg(test)]`, `#[test]`, `/// cbindgen::ignore` and
/// variations thereof.
Expand Down
12 changes: 12 additions & 0 deletions tests/expectations/non_pub_extern.c
@@ -0,0 +1,12 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

extern const uint32_t FIRST;

extern const uint32_t RENAMED;

void first(void);

void renamed(void);
20 changes: 20 additions & 0 deletions tests/expectations/non_pub_extern.compat.c
@@ -0,0 +1,20 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

extern const uint32_t FIRST;

extern const uint32_t RENAMED;

void first(void);

void renamed(void);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
17 changes: 17 additions & 0 deletions tests/expectations/non_pub_extern.cpp
@@ -0,0 +1,17 @@
#include <cstdarg>
#include <cstdint>
#include <cstdlib>
#include <ostream>
#include <new>

extern "C" {

extern const uint32_t FIRST;

extern const uint32_t RENAMED;

void first();

void renamed();

} // extern "C"
15 changes: 15 additions & 0 deletions tests/expectations/non_pub_extern.pyx
@@ -0,0 +1,15 @@
from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t
from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t
cdef extern from *:
ctypedef bint bool
ctypedef struct va_list

cdef extern from *:

extern const uint32_t FIRST;

extern const uint32_t RENAMED;

void first();

void renamed();
13 changes: 13 additions & 0 deletions tests/rust/non_pub_extern.rs
@@ -0,0 +1,13 @@
#[no_mangle]
static FIRST: u32 = 10;

#[export_name = "RENAMED"]
static SECOND: u32 = 42;

#[no_mangle]
extern "C" fn first()
{ }

#[export_name = "renamed"]
extern fn second()
{ }

0 comments on commit 5f235ec

Please sign in to comment.