内容简介:build.rs可实现正常项目编译前的额外操作,比如代码生成、编译所依赖的C/C++库等行为。为了让编程过程更可控,通常需要输出状态表示通过了某一阶段,或遇到什么错误,Cargo支持build.rs编译时输出不同类型的语句,比如info、warning、error等,以下为示例,参考自目前我看到比较完整的参考是官方的libstd/build.rs,编译我们业务所需的第三方库的命令几乎都可以从那找到“灵感”,下面贴出完整代码镇宅,关键操作是在Cargo.toml中添加
build.rs可实现正常项目编译前的额外操作,比如代码生成、编译所依赖的C/C++库等行为。为了让编程过程更可控,通常需要输出状态表示通过了某一阶段,或遇到什么错误,Cargo支持build.rs编译时输出不同类型的语句,比如info、warning、error等,以下为示例,参考自 rustdroid-native 。
println!("cargo:warning=Error executing process command <{:?}>: {}", cmd, e);
复制代码
调用C/C++编译器编译所依赖的第三方C/C++库
目前我看到比较完整的参考是官方的libstd/build.rs,编译我们业务所需的第三方库的命令几乎都可以从那找到“灵感”,下面贴出完整代码镇宅,关键操作是 build_libbacktrace()
,通过 cc::Build
实例把需要编译的C/C++代码声明起来, 理论上支持正则匹配
。
#![deny(warnings)]
extern crate build_helper;
extern crate cc;
use build_helper::native_lib_boilerplate;
use std::env;
use std::fs::File;
fn main() {
let target = env::var("TARGET").expect("TARGET was not set");
if cfg!(feature = "backtrace") &&
!target.contains("cloudabi") &&
!target.contains("emscripten") &&
!target.contains("msvc") &&
!target.contains("wasm32")
{
let _ = build_libbacktrace(&target);
}
if target.contains("linux") {
if target.contains("android") {
println!("cargo:rustc-link-lib=dl");
println!("cargo:rustc-link-lib=log");
println!("cargo:rustc-link-lib=gcc");
} else if !target.contains("musl") {
println!("cargo:rustc-link-lib=dl");
println!("cargo:rustc-link-lib=rt");
println!("cargo:rustc-link-lib=pthread");
}
} else if target.contains("freebsd") {
println!("cargo:rustc-link-lib=execinfo");
println!("cargo:rustc-link-lib=pthread");
} else if target.contains("dragonfly") || target.contains("bitrig") ||
target.contains("netbsd") || target.contains("openbsd") {
println!("cargo:rustc-link-lib=pthread");
} else if target.contains("solaris") {
println!("cargo:rustc-link-lib=socket");
println!("cargo:rustc-link-lib=posix4");
println!("cargo:rustc-link-lib=pthread");
println!("cargo:rustc-link-lib=resolv");
} else if target.contains("apple-darwin") {
println!("cargo:rustc-link-lib=System");
// res_init and friends require -lresolv on macOS/iOS.
// See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
println!("cargo:rustc-link-lib=resolv");
} else if target.contains("apple-ios") {
println!("cargo:rustc-link-lib=System");
println!("cargo:rustc-link-lib=objc");
println!("cargo:rustc-link-lib=framework=Security");
println!("cargo:rustc-link-lib=framework=Foundation");
println!("cargo:rustc-link-lib=resolv");
} else if target.contains("windows") {
println!("cargo:rustc-link-lib=advapi32");
println!("cargo:rustc-link-lib=ws2_32");
println!("cargo:rustc-link-lib=userenv");
println!("cargo:rustc-link-lib=shell32");
} else if target.contains("fuchsia") {
println!("cargo:rustc-link-lib=zircon");
println!("cargo:rustc-link-lib=fdio");
} else if target.contains("cloudabi") {
if cfg!(feature = "backtrace") {
println!("cargo:rustc-link-lib=unwind");
}
println!("cargo:rustc-link-lib=c");
println!("cargo:rustc-link-lib=compiler_rt");
}
}
fn build_libbacktrace(target: &str) -> Result<(), ()> {
let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", "")?;
let mut build = cc::Build::new();
build
.flag("-fvisibility=hidden")
.include("../libbacktrace")
.include(&native.out_dir)
.out_dir(&native.out_dir)
.warnings(false)
.file("../libbacktrace/alloc.c")
.file("../libbacktrace/backtrace.c")
.file("../libbacktrace/dwarf.c")
.file("../libbacktrace/fileline.c")
.file("../libbacktrace/posix.c")
.file("../libbacktrace/read.c")
.file("../libbacktrace/sort.c")
.file("../libbacktrace/state.c");
let any_debug = env::var("RUSTC_DEBUGINFO").unwrap_or_default() == "true" ||
env::var("RUSTC_DEBUGINFO_LINES").unwrap_or_default() == "true";
build.debug(any_debug);
if target.contains("darwin") {
build.file("../libbacktrace/macho.c");
} else if target.contains("windows") {
build.file("../libbacktrace/pecoff.c");
} else {
build.file("../libbacktrace/elf.c");
let pointer_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap();
if pointer_width == "64" {
build.define("BACKTRACE_ELF_SIZE", "64");
} else {
build.define("BACKTRACE_ELF_SIZE", "32");
}
}
File::create(native.out_dir.join("backtrace-supported.h")).unwrap();
build.define("BACKTRACE_SUPPORTED", "1");
build.define("BACKTRACE_USES_MALLOC", "1");
build.define("BACKTRACE_SUPPORTS_THREADS", "0");
build.define("BACKTRACE_SUPPORTS_DATA", "0");
File::create(native.out_dir.join("config.h")).unwrap();
if !target.contains("apple-ios") &&
!target.contains("solaris") &&
!target.contains("redox") &&
!target.contains("android") &&
!target.contains("haiku") {
build.define("HAVE_DL_ITERATE_PHDR", "1");
}
build.define("_GNU_SOURCE", "1");
build.define("_LARGE_FILES", "1");
build.compile("backtrace");
Ok(())
}
复制代码
条件编译
所有的条件编译都由通过cfg配置实现,cfg支持any、all、not等逻辑谓词组合。
基本用法
在Cargo.toml中添加 [features]
段,然后列举需要组合的feature名,大体上相当于 gcc -条件1 -条件2 -条件3 ...
。
[features] default = [] metal = ["gfx-backend-metal"] vulkan = ["gfx-backend-vulkan"] dx12 = ["gfx-backend-dx12"] 复制代码
mod级别条件编译
实现示例,参考 gl_generator.rs
#[cfg(feature = "unstable_generator_utils")] pub mod generators; #[cfg(not(feature = "unstable_generator_utils"))] mod generators; 复制代码
编译特定CPU架构
指定target_arch + CPU架构名称字符串,如 #[cfg(target_arch= "x86")]
, #[cfg(any(target_arch = "arm", target_arch = "x86"))]
。
参考 libstd/os/android/raw.rs
#[cfg(any(target_arch = "arm", target_arch = "x86"))]
mod arch {
use os::raw::{c_uint, c_uchar, c_ulonglong, c_longlong, c_ulong};
use os::unix::raw::{uid_t, gid_t};
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type dev_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type mode_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type blkcnt_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type blksize_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type nlink_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type off_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type time_t = i64;
复制代码
#[doc(include = "os/raw/char.md")]
#[cfg(any(all(target_os = "linux", any(target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "s390x")),
复制代码
[target.'cfg(any(target_os = "macos", all(target_os = "ios", target_arch = "aarch64")))'.dependencies.gfx-backend-metal] git = "https://github.com/gfx-rs/gfx" version = "0.1" optional = true [target.'cfg(target_os = "android")'.dependencies.gfx-backend-vulkan] git = "https://github.com/gfx-rs/gfx" version = "0.1" optional = true #[target.'cfg(windows)'.dependencies.gfx-backend-dx12] #git = "https://github.com/gfx-rs/gfx" #version = "0.1" #optional = true 复制代码
编译成指定类型二进制包(.a/.so/.r)
目前还没找到支持编译出macOS/iOS支持的 .framework
办法。
在Cargo.toml中添加 [lib]
段,
-
name表示输出的库名, 最终输出文件名为lib+name.a或lib+name.so , 比如libportability.so 。 -
crate-type表示输出的二进制包类型,比如-
staticlib= .a iOS只认Rust输出.a,Android可以.a和.so,配置成["staticlib", "cdylib"]在用cargo-lipo时会出警告不支持cdylib,忽略即可。 -
cdylib= .so -
rlib= 给Rust用的静态库 -
dylib= 给Rust用的动态库
-
-
path表示库项目的入口文件,通常是src/lib.rs,如果改动了这一位置,可通过path = 新位置实现,比如:
[lib] name = "portability" crate-type = ["staticlib", "cdylib"] path = "src/ios/lib.rs" 复制代码
SDK开发的“售后服务”
提供.a/.so给业务团队,这一过程可能会有人为失误导致大家对接失败,下面介绍些我们使用的小技巧。
读取.a静态库的iOS版本
在macOS terminal执行如下命令,用 /
查找 VERSION
。
otool -lv xyz.a | less 复制代码
参考: check-ios-deployment-target-of-a-static-library
nm查看导出符号
有时编码疏忽导致没给需要导出的C接口添加 #[no_mangle]
和 extern
等修饰,或者使用了不合理的优化attribute导致符号被优化掉,此时业务链接我们的库就会失败,因此,交付二进制包前用nm确认符号表是合格的工程师习惯。以下为示例代码。
nm -D ./target/release/libportability.so | grep fun_call_exported_to_c 0000000000003190 T fun_call_exported_to_c 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Learn Python the Hard Way
Zed Shaw / Example Product Manufacturer / 2011
This is a very beginner book for people who want to learn to code. If you can already code then the book will probably drive you insane. It's intended for people who have no coding chops to build up t......一起来看看 《Learn Python the Hard Way》 这本书的介绍吧!