mirror of
https://gitee.com/openharmony/third_party_rust_cxx
synced 2024-11-23 07:10:29 +00:00
Split cxx runtime and build components
This commit is contained in:
parent
1f56702490
commit
f8ed07327b
@ -20,15 +20,15 @@ matrix:
|
||||
rust: nightly-x86_64-pc-windows-gnu
|
||||
before_script:
|
||||
# windows is bad at symlinks
|
||||
- rm cmd/src/gen cmd/src/syntax gen/include macro/src/syntax src/gen src/syntax
|
||||
- cp -r include gen; cp -r gen cmd/src; cp -r syntax cmd/src; cp -r syntax macro/src; cp -r gen src; cp -r syntax src
|
||||
- rm gen/build/src/gen gen/build/src/syntax gen/cmd/src/gen gen/cmd/src/syntax gen/src/include macro/src/syntax
|
||||
- cp -r include gen/src; cp -r gen/src gen/build/src/gen; cp -r gen/src gen/cmd/src/gen; cp -r syntax gen/build/src; cp -r syntax gen/cmd/src; cp -r syntax macro/src
|
||||
|
||||
- name: Windows (msvc)
|
||||
os: windows
|
||||
rust: nightly-x86_64-pc-windows-msvc
|
||||
before_script:
|
||||
- rm cmd/src/gen cmd/src/syntax gen/include macro/src/syntax src/gen src/syntax
|
||||
- cp -r include gen; cp -r gen cmd/src; cp -r syntax cmd/src; cp -r syntax macro/src; cp -r gen src; cp -r syntax src
|
||||
- rm gen/build/src/gen gen/build/src/syntax gen/cmd/src/gen gen/cmd/src/syntax gen/src/include macro/src/syntax
|
||||
- cp -r include gen/src; cp -r gen/src gen/build/src/gen; cp -r gen/src gen/cmd/src/gen; cp -r syntax gen/build/src; cp -r syntax gen/cmd/src; cp -r syntax macro/src
|
||||
|
||||
- name: Buck
|
||||
rust: nightly
|
||||
|
22
BUCK
22
BUCK
@ -5,19 +5,13 @@ rust_library(
|
||||
deps = [
|
||||
":core",
|
||||
":macro",
|
||||
"//third-party:anyhow",
|
||||
"//third-party:cc",
|
||||
"//third-party:codespan-reporting",
|
||||
"//third-party:link-cplusplus",
|
||||
"//third-party:proc-macro2",
|
||||
"//third-party:quote",
|
||||
"//third-party:syn",
|
||||
],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "codegen",
|
||||
srcs = glob(["cmd/src/**"]),
|
||||
srcs = glob(["gen/cmd/src/**"]),
|
||||
crate = "cxxbridge",
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
@ -52,3 +46,17 @@ rust_library(
|
||||
"//third-party:syn",
|
||||
],
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "build",
|
||||
srcs = glob(["gen/build/src/**"]),
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
"//third-party:anyhow",
|
||||
"//third-party:cc",
|
||||
"//third-party:codespan-reporting",
|
||||
"//third-party:proc-macro2",
|
||||
"//third-party:quote",
|
||||
"//third-party:syn",
|
||||
],
|
||||
)
|
||||
|
26
BUILD
26
BUILD
@ -3,25 +3,18 @@ load("//tools/bazel:rust.bzl", "rust_binary", "rust_library")
|
||||
rust_library(
|
||||
name = "cxx",
|
||||
srcs = glob(["src/**/*.rs"]),
|
||||
data = ["src/gen/include/cxx.h"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":core-lib",
|
||||
":cxxbridge-macro",
|
||||
"//third-party:anyhow",
|
||||
"//third-party:cc",
|
||||
"//third-party:codespan-reporting",
|
||||
"//third-party:link-cplusplus",
|
||||
"//third-party:proc-macro2",
|
||||
"//third-party:quote",
|
||||
"//third-party:syn",
|
||||
],
|
||||
)
|
||||
|
||||
rust_binary(
|
||||
name = "codegen",
|
||||
srcs = glob(["cmd/src/**/*.rs"]),
|
||||
data = ["cmd/src/gen/include/cxx.h"],
|
||||
srcs = glob(["gen/cmd/src/**/*.rs"]),
|
||||
data = ["gen/cmd/src/gen/include/cxx.h"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//third-party:anyhow",
|
||||
@ -57,3 +50,18 @@ rust_library(
|
||||
"//third-party:syn",
|
||||
],
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "build",
|
||||
srcs = glob(["gen/build/src/**/*.rs"]),
|
||||
data = ["gen/build/src/gen/include/cxx.h"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//third-party:anyhow",
|
||||
"//third-party:cc",
|
||||
"//third-party:codespan-reporting",
|
||||
"//third-party:proc-macro2",
|
||||
"//third-party:quote",
|
||||
"//third-party:syn",
|
||||
],
|
||||
)
|
||||
|
@ -15,25 +15,20 @@ exclude = ["/demo-cxx", "/gen", "/syntax", "/third-party"]
|
||||
travis-ci = { repository = "dtolnay/cxx" }
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
cc = "1.0.49"
|
||||
codespan-reporting = "0.9"
|
||||
cxxbridge-macro = { version = "=0.2.12", path = "macro" }
|
||||
link-cplusplus = "1.0"
|
||||
proc-macro2 = { version = "1.0", features = ["span-locations"] }
|
||||
quote = "1.0"
|
||||
syn = { version = "1.0", features = ["full"] }
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0.49"
|
||||
|
||||
[dev-dependencies]
|
||||
cxx-build = { version = "=0.2.12", path = "gen/build" }
|
||||
cxx-test-suite = { version = "0", path = "tests/ffi" }
|
||||
rustversion = "1.0"
|
||||
trybuild = { version = "1.0.21", features = ["diff"] }
|
||||
|
||||
[workspace]
|
||||
members = ["cmd", "demo-rs", "macro", "tests/ffi"]
|
||||
members = ["demo-rs", "gen/build", "gen/cmd", "macro", "tests/ffi"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@ -219,8 +219,7 @@ set up any additional source files and compiler flags as normal.
|
||||
// build.rs
|
||||
|
||||
fn main() {
|
||||
cxx::Build::new()
|
||||
.bridge("src/main.rs") // returns a cc::Build
|
||||
cxx_build::bridge("src/main.rs") // returns a cc::Build
|
||||
.file("../demo-cxx/demo.cc")
|
||||
.flag("-std=c++11")
|
||||
.compile("cxxbridge-demo");
|
||||
|
@ -1 +0,0 @@
|
||||
../LICENSE-APACHE
|
@ -1 +0,0 @@
|
||||
../LICENSE-MIT
|
@ -1 +0,0 @@
|
||||
../../gen
|
@ -1 +0,0 @@
|
||||
../../syntax
|
@ -9,4 +9,4 @@ publish = false
|
||||
cxx = { path = ".." }
|
||||
|
||||
[build-dependencies]
|
||||
cxx = { path = ".." }
|
||||
cxx-build = { path = "../gen/build" }
|
||||
|
@ -1,6 +1,5 @@
|
||||
fn main() {
|
||||
cxx::Build::new()
|
||||
.bridge("src/main.rs")
|
||||
cxx_build::bridge("src/main.rs")
|
||||
.file("../demo-cxx/demo.cc")
|
||||
.flag("-std=c++11")
|
||||
.compile("cxxbridge-demo");
|
||||
|
4
gen/README.md
Normal file
4
gen/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
This directory contains CXX's C++ code generator. This code generator has two
|
||||
public frontends, one a command-line application (binary) in the *cmd* directory
|
||||
and the other a library intended to be used from a build.rs in the *build*
|
||||
directory.
|
22
gen/build/Cargo.toml
Normal file
22
gen/build/Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "cxx-build"
|
||||
version = "0.2.12"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "C++ code generator for integrating `cxx` crate into a Cargo build."
|
||||
repository = "https://github.com/dtolnay/cxx"
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "dtolnay/cxx" }
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
cc = "1.0.49"
|
||||
codespan-reporting = "0.9"
|
||||
proc-macro2 = { version = "1.0", features = ["span-locations"] }
|
||||
quote = "1.0"
|
||||
syn = { version = "1.0", features = ["full"] }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
1
gen/build/LICENSE-APACHE
Symbolic link
1
gen/build/LICENSE-APACHE
Symbolic link
@ -0,0 +1 @@
|
||||
../../LICENSE-APACHE
|
1
gen/build/LICENSE-MIT
Symbolic link
1
gen/build/LICENSE-MIT
Symbolic link
@ -0,0 +1 @@
|
||||
../../LICENSE-MIT
|
1
gen/build/src/gen
Symbolic link
1
gen/build/src/gen
Symbolic link
@ -0,0 +1 @@
|
||||
../../src
|
96
gen/build/src/lib.rs
Normal file
96
gen/build/src/lib.rs
Normal file
@ -0,0 +1,96 @@
|
||||
//! The CXX code generator for constructing and compiling C++ code.
|
||||
//!
|
||||
//! This is intended to be used from Cargo build scripts to execute CXX's
|
||||
//! C++ code generator, set up any additional compiler flags depending on
|
||||
//! the use case, and make the C++ compiler invocation.
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! Example of a canonical Cargo build script that builds a CXX bridge:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! // build.rs
|
||||
//!
|
||||
//! fn main() {
|
||||
//! cxx_build::bridge("src/main.rs")
|
||||
//! .file("../demo-cxx/demo.cc")
|
||||
//! .flag("-std=c++11")
|
||||
//! .compile("cxxbridge-demo");
|
||||
//!
|
||||
//! println!("cargo:rerun-if-changed=src/main.rs");
|
||||
//! println!("cargo:rerun-if-changed=../demo-cxx/demo.h");
|
||||
//! println!("cargo:rerun-if-changed=../demo-cxx/demo.cc");
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! A runnable working setup with this build script is shown in the
|
||||
//! *demo-rs* and *demo-cxx* directories of [https://github.com/dtolnay/cxx].
|
||||
//!
|
||||
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! # Alternatives
|
||||
//!
|
||||
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
|
||||
//! alternate way of invoking the C++ code generator as a standalone command
|
||||
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
|
||||
//!
|
||||
//! ```bash
|
||||
//! $ cargo install cxxbridge-cmd # or build it from the repo
|
||||
//!
|
||||
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
|
||||
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
|
||||
//! ```
|
||||
|
||||
mod error;
|
||||
mod gen;
|
||||
mod paths;
|
||||
mod syntax;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::gen::Opt;
|
||||
use anyhow::anyhow;
|
||||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
|
||||
/// This returns a [`cc::Build`] on which you should continue to set up any
|
||||
/// additional source files or compiler flags, and lastly call its [`compile`]
|
||||
/// method to execute the C++ build.
|
||||
///
|
||||
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
|
||||
#[must_use]
|
||||
pub fn bridge(rust_source_file: impl AsRef<Path>) -> cc::Build {
|
||||
match try_generate_bridge(rust_source_file.as_ref()) {
|
||||
Ok(build) => build,
|
||||
Err(err) => {
|
||||
let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {:?}\n\n", anyhow!(err));
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_generate_bridge(rust_source_file: &Path) -> Result<cc::Build> {
|
||||
let header = gen::do_generate_header(rust_source_file, Opt::default());
|
||||
let header_path = paths::out_with_extension(rust_source_file, ".h")?;
|
||||
fs::create_dir_all(header_path.parent().unwrap())?;
|
||||
fs::write(&header_path, header)?;
|
||||
paths::symlink_header(&header_path, rust_source_file);
|
||||
|
||||
let bridge = gen::do_generate_bridge(rust_source_file, Opt::default());
|
||||
let bridge_path = paths::out_with_extension(rust_source_file, ".cc")?;
|
||||
fs::write(&bridge_path, bridge)?;
|
||||
let mut build = paths::cc_build();
|
||||
build.file(&bridge_path);
|
||||
|
||||
let ref cxx_h = paths::include_dir()?.join("rust").join("cxx.h");
|
||||
let _ = fs::create_dir_all(cxx_h.parent().unwrap());
|
||||
let _ = fs::remove_file(cxx_h);
|
||||
let _ = fs::write(cxx_h, gen::include::HEADER);
|
||||
|
||||
Ok(build)
|
||||
}
|
1
gen/build/src/syntax
Symbolic link
1
gen/build/src/syntax
Symbolic link
@ -0,0 +1 @@
|
||||
../../../syntax
|
1
gen/cmd/LICENSE-APACHE
Symbolic link
1
gen/cmd/LICENSE-APACHE
Symbolic link
@ -0,0 +1 @@
|
||||
../../LICENSE-APACHE
|
1
gen/cmd/LICENSE-MIT
Symbolic link
1
gen/cmd/LICENSE-MIT
Symbolic link
@ -0,0 +1 @@
|
||||
../../LICENSE-MIT
|
1
gen/cmd/src/gen
Symbolic link
1
gen/cmd/src/gen
Symbolic link
@ -0,0 +1 @@
|
||||
../../src
|
1
gen/cmd/src/syntax
Symbolic link
1
gen/cmd/src/syntax
Symbolic link
@ -0,0 +1 @@
|
||||
../../../syntax
|
@ -1 +0,0 @@
|
||||
../include
|
1
gen/src/include
Symbolic link
1
gen/src/include
Symbolic link
@ -0,0 +1 @@
|
||||
../../include
|
@ -6,6 +6,7 @@ edition = "2018"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "Implementation detail of the `cxx` crate."
|
||||
repository = "https://github.com/dtolnay/cxx"
|
||||
exclude = ["README.md"]
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
3
macro/README.md
Normal file
3
macro/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
This directory contains CXX's Rust code generator, which is a procedural macro.
|
||||
Users won't depend on this crate directly. Instead they'll invoke its macro
|
||||
through the reexport in the main `cxx` crate.
|
111
src/lib.rs
111
src/lib.rs
@ -224,8 +224,7 @@
|
||||
//! // build.rs
|
||||
//!
|
||||
//! fn main() {
|
||||
//! cxx::Build::new()
|
||||
//! .bridge("src/main.rs") // returns a cc::Build
|
||||
//! cxx_build::bridge("src/main.rs") // returns a cc::Build
|
||||
//! .file("../demo-cxx/demo.cc")
|
||||
//! .flag("-std=c++11")
|
||||
//! .compile("cxxbridge-demo");
|
||||
@ -363,18 +362,14 @@ mod concat;
|
||||
|
||||
mod cxx_string;
|
||||
mod cxx_vector;
|
||||
mod error;
|
||||
mod exception;
|
||||
mod function;
|
||||
mod gen;
|
||||
mod opaque;
|
||||
mod paths;
|
||||
mod result;
|
||||
mod rust_sliceu8;
|
||||
mod rust_str;
|
||||
mod rust_string;
|
||||
mod rust_vec;
|
||||
mod syntax;
|
||||
mod unique_ptr;
|
||||
mod unwind;
|
||||
|
||||
@ -398,107 +393,3 @@ pub mod private {
|
||||
pub use crate::unique_ptr::UniquePtrTarget;
|
||||
pub use crate::unwind::catch_unwind;
|
||||
}
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::gen::Opt;
|
||||
use anyhow::anyhow;
|
||||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
|
||||
/// The CXX code generator for constructing and compiling C++ code.
|
||||
///
|
||||
/// This is intended to be used from Cargo build scripts to execute CXX's
|
||||
/// C++ code generator, set up any additional compiler flags depending on
|
||||
/// the use case, and make the C++ compiler invocation.
|
||||
///
|
||||
/// <br>
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Example of a canonical Cargo build script that builds a CXX bridge:
|
||||
///
|
||||
/// ```no_run
|
||||
/// // build.rs
|
||||
///
|
||||
/// fn main() {
|
||||
/// cxx::Build::new()
|
||||
/// .bridge("src/main.rs")
|
||||
/// .file("../demo-cxx/demo.cc")
|
||||
/// .flag("-std=c++11")
|
||||
/// .compile("cxxbridge-demo");
|
||||
///
|
||||
/// println!("cargo:rerun-if-changed=src/main.rs");
|
||||
/// println!("cargo:rerun-if-changed=../demo-cxx/demo.h");
|
||||
/// println!("cargo:rerun-if-changed=../demo-cxx/demo.cc");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// A runnable working setup with this build script is shown in the
|
||||
/// *demo-rs* and *demo-cxx* directories of [https://github.com/dtolnay/cxx].
|
||||
///
|
||||
/// [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
|
||||
///
|
||||
/// <br>
|
||||
///
|
||||
/// # Alternatives
|
||||
///
|
||||
/// For use in non-Cargo builds like Bazel or Buck, CXX provides an
|
||||
/// alternate way of invoking the C++ code generator as a standalone command
|
||||
/// line tool. The tool is packaged as the `cxxbridge-cmd` crate.
|
||||
///
|
||||
/// ```bash
|
||||
/// $ cargo install cxxbridge-cmd # or build it from the repo
|
||||
///
|
||||
/// $ cxxbridge src/main.rs --header > path/to/mybridge.h
|
||||
/// $ cxxbridge src/main.rs > path/to/mybridge.cc
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub struct Build {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl Build {
|
||||
/// Begin with a [`cc::Build`] in its default configuration.
|
||||
pub fn new() -> Self {
|
||||
Build { _private: () }
|
||||
}
|
||||
|
||||
/// This returns a [`cc::Build`] on which you should continue to set up
|
||||
/// any additional source files or compiler flags, and lastly call its
|
||||
/// [`compile`] method to execute the C++ build.
|
||||
///
|
||||
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
|
||||
#[must_use]
|
||||
pub fn bridge(&self, rust_source_file: impl AsRef<Path>) -> cc::Build {
|
||||
match try_generate_bridge(rust_source_file.as_ref()) {
|
||||
Ok(build) => build,
|
||||
Err(err) => {
|
||||
let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {:?}\n\n", anyhow!(err));
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_generate_bridge(rust_source_file: &Path) -> Result<cc::Build> {
|
||||
let header = gen::do_generate_header(rust_source_file, Opt::default());
|
||||
let header_path = paths::out_with_extension(rust_source_file, ".h")?;
|
||||
fs::create_dir_all(header_path.parent().unwrap())?;
|
||||
fs::write(&header_path, header)?;
|
||||
paths::symlink_header(&header_path, rust_source_file);
|
||||
|
||||
let bridge = gen::do_generate_bridge(rust_source_file, Opt::default());
|
||||
let bridge_path = paths::out_with_extension(rust_source_file, ".cc")?;
|
||||
fs::write(&bridge_path, bridge)?;
|
||||
let mut build = paths::cc_build();
|
||||
build.file(&bridge_path);
|
||||
|
||||
let ref cxx_h = paths::include_dir()?.join("rust").join("cxx.h");
|
||||
let _ = fs::create_dir_all(cxx_h.parent().unwrap());
|
||||
let _ = fs::remove_file(cxx_h);
|
||||
let _ = fs::write(cxx_h, gen::include::HEADER);
|
||||
|
||||
Ok(build)
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
../syntax
|
@ -11,4 +11,4 @@ path = "lib.rs"
|
||||
cxx = { path = "../.." }
|
||||
|
||||
[build-dependencies]
|
||||
cxx = { path = "../.." }
|
||||
cxx-build = { path = "../../gen/build" }
|
||||
|
@ -3,8 +3,7 @@ fn main() {
|
||||
return;
|
||||
}
|
||||
|
||||
cxx::Build::new()
|
||||
.bridge("lib.rs")
|
||||
cxx_build::bridge("lib.rs")
|
||||
.file("tests.cc")
|
||||
.flag("-std=c++11")
|
||||
.compile("cxx-test-suite");
|
||||
|
18
third-party/Cargo.lock
generated
vendored
18
third-party/Cargo.lock
generated
vendored
@ -67,17 +67,25 @@ dependencies = [
|
||||
name = "cxx"
|
||||
version = "0.2.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
"cxx-build",
|
||||
"cxx-test-suite",
|
||||
"cxxbridge-macro",
|
||||
"link-cplusplus",
|
||||
"rustversion",
|
||||
"trybuild",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "0.2.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
"trybuild",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -85,6 +93,7 @@ name = "cxx-test-suite"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -104,6 +113,7 @@ name = "cxxbridge-demo"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
Loading…
Reference in New Issue
Block a user