Skip to content

Commit a1d588b

Browse files
Rollup merge of rust-lang#150992 - cezarbbb:cstyle-export-rules2, r=bjorn3,petrochenkov
link modifier `export-symbols`: export all global symbols from selected uptream c static libraries In order to be able to export symbols from a specified upstream C static library, I redesigned a solution that, compared to a previous PR rust-lang#150335 I submitted, will not have any extra symbols leaking out. The following points should be noted: - This attribute will select and import the `Global` symbols of the first matching library it finds. - Developers should ensure that there are no libraries with the same name. - This modifier is only compatible with `static` linking kind - By default, upstream C static libraries will not export their `Global` symbols regardless of whether `LTO` optimization is enabled. However, after enabling this attribute, if the upstream C static library has `LTO` optimization enabled, the compiler will issue an error to inform the developer that the linked C library is invalid. The test code is the same as the PR rust-lang#150335. Here are the results: 1. `cargo +include-libs rustc --release -- -L. -lstatic:+export-symbols=c_add` (or you can use `#[link(name = "c_add", kind= "static", modifier = "+export-symbols")]` in the file) ```bash U abort@GLIBC_2.2.5 U bcmp@GLIBC_2.2.5 0000000000014f60 T c_add U calloc@GLIBC_2.2.5 U close@GLIBC_2.2.5 0000000000014f70 T c_sub w __cxa_finalize@GLIBC_2.2.5 w __cxa_thread_atexit_impl@GLIBC_2.18 U dl_iterate_phdr@GLIBC_2.2.5 0000000000014ee0 T downstream_add U __errno_location@GLIBC_2.2.5 U free@GLIBC_2.2.5 U fstat64@GLIBC_2.33 U getcwd@GLIBC_2.2.5 U getenv@GLIBC_2.2.5 w __gmon_start__ w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable U lseek64@GLIBC_2.2.5 U malloc@GLIBC_2.2.5 U memcpy@GLIBC_2.14 U memmove@GLIBC_2.2.5 U memset@GLIBC_2.2.5 U mmap64@GLIBC_2.2.5 U munmap@GLIBC_2.2.5 U open64@GLIBC_2.2.5 U posix_memalign@GLIBC_2.2.5 U pthread_key_create@GLIBC_2.34 U pthread_key_delete@GLIBC_2.34 U pthread_setspecific@GLIBC_2.34 U read@GLIBC_2.2.5 U readlink@GLIBC_2.2.5 U realloc@GLIBC_2.2.5 U realpath@GLIBC_2.3 U stat64@GLIBC_2.33 w statx@GLIBC_2.28 U strlen@GLIBC_2.2.5 U syscall@GLIBC_2.2.5 U __tls_get_addr@GLIBC_2.3 U _Unwind_Backtrace@GCC_3.3 U _Unwind_DeleteException@GCC_3.0 U _Unwind_GetDataRelBase@GCC_3.0 U _Unwind_GetIP@GCC_3.0 U _Unwind_GetIPInfo@GCC_4.2.0 U _Unwind_GetLanguageSpecificData@GCC_3.0 U _Unwind_GetRegionStart@GCC_3.0 U _Unwind_GetTextRelBase@GCC_3.0 U _Unwind_RaiseException@GCC_3.0 U _Unwind_Resume@GCC_3.0 U _Unwind_SetGR@GCC_3.0 U _Unwind_SetIP@GCC_3.0 U write@GLIBC_2.2.5 U writev@GLIBC_2.2.5 ``` 3. `cargo +nightly rustc --release -- -L ./` ```bash U abort@GLIBC_2.2.5 U bcmp@GLIBC_2.2.5 U calloc@GLIBC_2.2.5 U close@GLIBC_2.2.5 w __cxa_finalize@GLIBC_2.2.5 w __cxa_thread_atexit_impl@GLIBC_2.18 U dl_iterate_phdr@GLIBC_2.2.5 0000000000011e10 T downstream_add U __errno_location@GLIBC_2.2.5 U free@GLIBC_2.2.5 U fstat64@GLIBC_2.33 U getcwd@GLIBC_2.2.5 U getenv@GLIBC_2.2.5 w gettid@GLIBC_2.30 w __gmon_start__ w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable U lseek64@GLIBC_2.2.5 U malloc@GLIBC_2.2.5 U memcpy@GLIBC_2.14 U memmove@GLIBC_2.2.5 U memset@GLIBC_2.2.5 U mmap64@GLIBC_2.2.5 U munmap@GLIBC_2.2.5 U open64@GLIBC_2.2.5 U posix_memalign@GLIBC_2.2.5 U pthread_key_create@GLIBC_2.34 U pthread_key_delete@GLIBC_2.34 U pthread_setspecific@GLIBC_2.34 U read@GLIBC_2.2.5 U readlink@GLIBC_2.2.5 U realloc@GLIBC_2.2.5 U realpath@GLIBC_2.3 U stat64@GLIBC_2.33 w statx@GLIBC_2.28 U strlen@GLIBC_2.2.5 U syscall@GLIBC_2.2.5 U __tls_get_addr@GLIBC_2.3 U _Unwind_Backtrace@GCC_3.3 U _Unwind_GetDataRelBase@GCC_3.0 U _Unwind_GetIP@GCC_3.0 U _Unwind_GetIPInfo@GCC_4.2.0 U _Unwind_GetLanguageSpecificData@GCC_3.0 U _Unwind_GetRegionStart@GCC_3.0 U _Unwind_GetTextRelBase@GCC_3.0 U _Unwind_RaiseException@GCC_3.0 U _Unwind_Resume@GCC_3.0 U _Unwind_SetGR@GCC_3.0 U _Unwind_SetIP@GCC_3.0 U write@GLIBC_2.2.5 U writev@GLIBC_2.2.5 ``` r? @bjorn3
2 parents 930ecbc + dcdffe8 commit a1d588b

22 files changed

Lines changed: 226 additions & 36 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/link_attrs.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ use super::prelude::*;
1212
use super::util::parse_single_integer;
1313
use crate::attributes::cfg::parse_cfg_entry;
1414
use crate::session_diagnostics::{
15-
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ImportNameTypeRaw, ImportNameTypeX86,
16-
IncompatibleWasmLink, InvalidLinkModifier, LinkFrameworkApple, LinkOrdinalOutOfRange,
17-
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
18-
WholeArchiveNeedsStatic,
15+
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
16+
ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
17+
LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers,
18+
NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, WholeArchiveNeedsStatic,
1919
};
2020

2121
pub(crate) struct LinkNameParser;
@@ -165,6 +165,14 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
165165
cx.emit_err(BundleNeedsStatic { span });
166166
}
167167

168+
(sym::export_symbols, Some(NativeLibKind::Static { export_symbols, .. })) => {
169+
assign_modifier(export_symbols)
170+
}
171+
172+
(sym::export_symbols, _) => {
173+
cx.emit_err(ExportSymbolsNeedsStatic { span });
174+
}
175+
168176
(sym::verbatim, _) => assign_modifier(&mut verbatim),
169177

170178
(
@@ -190,6 +198,7 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
190198
span,
191199
&[
192200
sym::bundle,
201+
sym::export_symbols,
193202
sym::verbatim,
194203
sym::whole_dash_archive,
195204
sym::as_dash_needed,
@@ -285,7 +294,9 @@ impl LinkParser {
285294
};
286295

287296
let link_kind = match link_kind {
288-
kw::Static => NativeLibKind::Static { bundle: None, whole_archive: None },
297+
kw::Static => {
298+
NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None }
299+
}
289300
sym::dylib => NativeLibKind::Dylib { as_needed: None },
290301
sym::framework => {
291302
if !sess.target.is_like_darwin {

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -909,7 +909,7 @@ pub(crate) struct RawDylibOnlyWindows {
909909

910910
#[derive(Diagnostic)]
911911
#[diag(
912-
"invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed"
912+
"invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed, export-symbols"
913913
)]
914914
pub(crate) struct InvalidLinkModifier {
915915
#[primary_span]
@@ -938,6 +938,13 @@ pub(crate) struct BundleNeedsStatic {
938938
pub span: Span,
939939
}
940940

941+
#[derive(Diagnostic)]
942+
#[diag("linking modifier `export-symbols` is only compatible with `static` linking kind")]
943+
pub(crate) struct ExportSymbolsNeedsStatic {
944+
#[primary_span]
945+
pub span: Span,
946+
}
947+
941948
#[derive(Diagnostic)]
942949
#[diag("linking modifier `whole-archive` is only compatible with `static` linking kind")]
943950
pub(crate) struct WholeArchiveNeedsStatic {

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 88 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ use std::{env, fmt, fs, io, mem, str};
1111

1212
use find_msvc_tools;
1313
use itertools::Itertools;
14+
use object::{Object, ObjectSection, ObjectSymbol};
1415
use regex::Regex;
1516
use rustc_arena::TypedArena;
1617
use rustc_attr_parsing::eval_config_entry;
17-
use rustc_data_structures::fx::FxIndexSet;
18+
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
1819
use rustc_data_structures::memmap::Mmap;
1920
use rustc_data_structures::temp_dir::MaybeTempDir;
2021
use rustc_errors::{DiagCtxtHandle, LintDiagnostic};
@@ -2185,6 +2186,71 @@ fn add_rpath_args(
21852186
}
21862187
}
21872188

2189+
fn add_c_staticlib_symbols(
2190+
sess: &Session,
2191+
lib: &NativeLib,
2192+
out: &mut Vec<(String, SymbolExportKind)>,
2193+
) -> io::Result<()> {
2194+
let file_path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess);
2195+
2196+
let archive_map = unsafe { Mmap::map(File::open(&file_path)?)? };
2197+
2198+
let archive = object::read::archive::ArchiveFile::parse(&*archive_map)
2199+
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2200+
2201+
for member in archive.members() {
2202+
let member = member.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2203+
2204+
let data = member
2205+
.data(&*archive_map)
2206+
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2207+
2208+
// clang LTO: raw LLVM bitcode
2209+
if data.starts_with(b"BC\xc0\xde") {
2210+
return Err(io::Error::new(
2211+
io::ErrorKind::InvalidData,
2212+
"LLVM bitcode object in C static library (LTO not supported)",
2213+
));
2214+
}
2215+
2216+
let object = object::File::parse(&*data)
2217+
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2218+
2219+
// gcc / clang ELF / Mach-O LTO
2220+
if object.sections().any(|s| {
2221+
s.name().map(|n| n.starts_with(".gnu.lto_") || n == ".llvm.lto").unwrap_or(false)
2222+
}) {
2223+
return Err(io::Error::new(
2224+
io::ErrorKind::InvalidData,
2225+
"LTO object in C static library is not supported",
2226+
));
2227+
}
2228+
2229+
for symbol in object.symbols() {
2230+
if symbol.scope() != object::SymbolScope::Dynamic {
2231+
continue;
2232+
}
2233+
2234+
let name = match symbol.name() {
2235+
Ok(n) => n,
2236+
Err(_) => continue,
2237+
};
2238+
2239+
let export_kind = match symbol.kind() {
2240+
object::SymbolKind::Text => SymbolExportKind::Text,
2241+
object::SymbolKind::Data => SymbolExportKind::Data,
2242+
_ => continue,
2243+
};
2244+
2245+
// FIXME:The symbol mangle rules are slightly different in Windows(32-bit) and Apple.
2246+
// Need to be resolved.
2247+
out.push((name.to_string(), export_kind));
2248+
}
2249+
}
2250+
2251+
Ok(())
2252+
}
2253+
21882254
/// Produce the linker command line containing linker path and arguments.
21892255
///
21902256
/// When comments in the function say "order-(in)dependent" they mean order-dependence between
@@ -2217,18 +2283,33 @@ fn linker_with_args(
22172283
);
22182284
let link_output_kind = link_output_kind(sess, crate_type);
22192285

2286+
let mut export_symbols = codegen_results.crate_info.exported_symbols[&crate_type].clone();
2287+
2288+
if crate_type == CrateType::Cdylib {
2289+
let mut seen = FxHashSet::default();
2290+
2291+
for lib in &codegen_results.crate_info.used_libraries {
2292+
if let NativeLibKind::Static { export_symbols: Some(true), .. } = lib.kind
2293+
&& seen.insert((lib.name, lib.verbatim))
2294+
{
2295+
if let Err(err) = add_c_staticlib_symbols(&sess, lib, &mut export_symbols) {
2296+
sess.dcx().fatal(format!(
2297+
"failed to process C static library `{}`: {}",
2298+
lib.name, err
2299+
));
2300+
}
2301+
}
2302+
}
2303+
}
2304+
22202305
// ------------ Early order-dependent options ------------
22212306

22222307
// If we're building something like a dynamic library then some platforms
22232308
// need to make sure that all symbols are exported correctly from the
22242309
// dynamic library.
22252310
// Must be passed before any libraries to prevent the symbols to export from being thrown away,
22262311
// at least on some platforms (e.g. windows-gnu).
2227-
cmd.export_symbols(
2228-
tmpdir,
2229-
crate_type,
2230-
&codegen_results.crate_info.exported_symbols[&crate_type],
2231-
);
2312+
cmd.export_symbols(tmpdir, crate_type, &export_symbols);
22322313

22332314
// Can be used for adding custom CRT objects or overriding order-dependent options above.
22342315
// FIXME: In practice built-in target specs use this for arbitrary order-independent options,
@@ -2678,7 +2759,7 @@ fn add_native_libs_from_crate(
26782759
let name = lib.name.as_str();
26792760
let verbatim = lib.verbatim;
26802761
match lib.kind {
2681-
NativeLibKind::Static { bundle, whole_archive } => {
2762+
NativeLibKind::Static { bundle, whole_archive, .. } => {
26822763
if link_static {
26832764
let bundle = bundle.unwrap_or(true);
26842765
let whole_archive = whole_archive == Some(true);

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,8 @@ pub enum NativeLibKind {
331331
bundle: Option<bool>,
332332
/// Whether to link static library without throwing any object files away
333333
whole_archive: Option<bool>,
334+
/// Whether to export c static library symbols
335+
export_symbols: Option<bool>,
334336
},
335337
/// Dynamic library (e.g. `libfoo.so` on Linux)
336338
/// or an import library corresponding to a dynamic library (e.g. `foo.lib` on Windows/MSVC).
@@ -363,8 +365,8 @@ pub enum NativeLibKind {
363365
impl NativeLibKind {
364366
pub fn has_modifiers(&self) -> bool {
365367
match self {
366-
NativeLibKind::Static { bundle, whole_archive } => {
367-
bundle.is_some() || whole_archive.is_some()
368+
NativeLibKind::Static { bundle, whole_archive, export_symbols } => {
369+
bundle.is_some() || whole_archive.is_some() || export_symbols.is_some()
368370
}
369371
NativeLibKind::Dylib { as_needed }
370372
| NativeLibKind::Framework { as_needed }

compiler/rustc_interface/src/tests.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ fn test_native_libs_tracking_hash_different_values() {
379379
NativeLib {
380380
name: String::from("a"),
381381
new_name: None,
382-
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
382+
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
383383
verbatim: None,
384384
},
385385
NativeLib {
@@ -401,7 +401,7 @@ fn test_native_libs_tracking_hash_different_values() {
401401
NativeLib {
402402
name: String::from("a"),
403403
new_name: None,
404-
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
404+
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
405405
verbatim: None,
406406
},
407407
NativeLib {
@@ -423,13 +423,13 @@ fn test_native_libs_tracking_hash_different_values() {
423423
NativeLib {
424424
name: String::from("a"),
425425
new_name: None,
426-
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
426+
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
427427
verbatim: None,
428428
},
429429
NativeLib {
430430
name: String::from("b"),
431431
new_name: None,
432-
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
432+
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
433433
verbatim: None,
434434
},
435435
NativeLib {
@@ -445,7 +445,7 @@ fn test_native_libs_tracking_hash_different_values() {
445445
NativeLib {
446446
name: String::from("a"),
447447
new_name: None,
448-
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
448+
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
449449
verbatim: None,
450450
},
451451
NativeLib {
@@ -467,7 +467,7 @@ fn test_native_libs_tracking_hash_different_values() {
467467
NativeLib {
468468
name: String::from("a"),
469469
new_name: None,
470-
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
470+
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
471471
verbatim: None,
472472
},
473473
NativeLib {
@@ -501,7 +501,7 @@ fn test_native_libs_tracking_hash_different_order() {
501501
NativeLib {
502502
name: String::from("a"),
503503
new_name: None,
504-
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
504+
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
505505
verbatim: None,
506506
},
507507
NativeLib {
@@ -528,7 +528,7 @@ fn test_native_libs_tracking_hash_different_order() {
528528
NativeLib {
529529
name: String::from("a"),
530530
new_name: None,
531-
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
531+
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
532532
verbatim: None,
533533
},
534534
NativeLib {
@@ -549,7 +549,7 @@ fn test_native_libs_tracking_hash_different_order() {
549549
NativeLib {
550550
name: String::from("a"),
551551
new_name: None,
552-
kind: NativeLibKind::Static { bundle: None, whole_archive: None },
552+
kind: NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None },
553553
verbatim: None,
554554
},
555555
NativeLib {

compiler/rustc_metadata/src/native_libs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ fn find_bundled_library(
161161
tcx: TyCtxt<'_>,
162162
) -> Option<Symbol> {
163163
let sess = tcx.sess;
164-
if let NativeLibKind::Static { bundle: Some(true) | None, whole_archive } = kind
164+
if let NativeLibKind::Static { bundle: Some(true) | None, whole_archive, .. } = kind
165165
&& tcx.crate_types().iter().any(|t| matches!(t, &CrateType::Rlib | CrateType::StaticLib))
166166
&& (sess.opts.unstable_opts.packed_bundled_libs || has_cfg || whole_archive == Some(true))
167167
{

compiler/rustc_session/src/config/native_libs.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ fn parse_native_lib(cx: &ParseNativeLibCx<'_>, value: &str) -> NativeLib {
5353
let NativeLibParts { kind, modifiers, name, new_name } = split_native_lib_value(value);
5454

5555
let kind = kind.map_or(NativeLibKind::Unspecified, |kind| match kind {
56-
"static" => NativeLibKind::Static { bundle: None, whole_archive: None },
56+
"static" => {
57+
NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None }
58+
}
5759
"dylib" => NativeLibKind::Dylib { as_needed: None },
5860
"framework" => NativeLibKind::Framework { as_needed: None },
5961
"link-arg" => {
@@ -105,7 +107,7 @@ fn parse_and_apply_modifier(cx: &ParseNativeLibCx<'_>, modifier: &str, native_li
105107
Some(("-", m)) => (m, false),
106108
_ => cx.early_dcx.early_fatal(
107109
"invalid linking modifier syntax, expected '+' or '-' prefix \
108-
before one of: bundle, verbatim, whole-archive, as-needed",
110+
before one of: bundle, verbatim, whole-archive, as-needed, export-symbols",
109111
),
110112
};
111113

@@ -125,6 +127,13 @@ fn parse_and_apply_modifier(cx: &ParseNativeLibCx<'_>, modifier: &str, native_li
125127
("bundle", _) => early_dcx
126128
.early_fatal("linking modifier `bundle` is only compatible with `static` linking kind"),
127129

130+
("export-symbols", NativeLibKind::Static { export_symbols, .. }) => {
131+
assign_modifier(export_symbols)
132+
}
133+
("export-symbols", _) => early_dcx.early_fatal(
134+
"linking modifier `export-symbols` is only compatible with `static` linking kind",
135+
),
136+
128137
("verbatim", _) => assign_modifier(&mut native_lib.verbatim),
129138

130139
("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
@@ -151,7 +160,7 @@ fn parse_and_apply_modifier(cx: &ParseNativeLibCx<'_>, modifier: &str, native_li
151160

152161
_ => early_dcx.early_fatal(format!(
153162
"unknown linking modifier `{modifier}`, expected one \
154-
of: bundle, verbatim, whole-archive, as-needed"
163+
of: bundle, verbatim, whole-archive, as-needed, export-symbols"
155164
)),
156165
}
157166
}

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,7 @@ symbols! {
10021002
explicit_tail_calls,
10031003
export_name,
10041004
export_stable,
1005+
export_symbols: "export-symbols",
10051006
expr,
10061007
expr_2021,
10071008
expr_fragment_specifier_2024,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
void my_function() {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
extern "C" {
2+
pub fn my_function();
3+
}
4+
5+
#[no_mangle]
6+
pub extern "C" fn rust_entry() {
7+
unsafe {
8+
my_function();
9+
}
10+
}

0 commit comments

Comments
 (0)