mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-04-24 22:30:03 +00:00
Refactor: Extract new crate detect-targets
and improve code quality (#307)
* Refactor: Extract new crate `detect-targets` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Refactor: Extract new mod `detect` for `detect-targets` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Refactor: Extract `desired_targets` in crate `detect-targets` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Refactor: Extract `detect::linux` in crate `detect-targets` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Refactor: Extract `detect::macos` in crate `detect-targets` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Refactor: Extract `detect::windows` in crate `detect-targets` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Add new dep cfg-if v1.0.0 for `detect-targets` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Refactor: Simplify mod declaration in `detect` using `cfg_if!` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Refactor: Simplify `detect_targets` using `cfg_if!` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Add crate doc for `detect-targets` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Enable feature "macros" of tokio in `detect-targets` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Enable feature "io-util" of dep tokio Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Rm unused feature "io-util" & "macros" of dep tokio Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Set stdin & stderr to null in `get_target_from_rustc` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Improve doc of `get_desired_targets` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Improve `detect_targets_linux`: Run `ldd` with stdin set to null Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Fix potential panic in `windows::detect_alternative_targets` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * FIx fmt of `detect_targets_linux` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Do not re-export dep `detect-targets` in `crates/lib` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Fix typo in crate doc for `detect-targets` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Enable feature "macros" of tokio in dev mode Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Add example to crate doc of `detect-targets` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Improve API `get_desired_targets`: Take `Option<&str>` instead of `&Option<String>` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
parent
1102284684
commit
62f9450d2d
20 changed files with 574 additions and 263 deletions
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
|
@ -28,3 +28,7 @@ updates:
|
||||||
directory: "/crates/normalize-path"
|
directory: "/crates/normalize-path"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
|
- package-ecosystem: "cargo"
|
||||||
|
directory: "/crates/detect-target"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
|
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -86,11 +86,11 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"compact_str",
|
"compact_str",
|
||||||
"crates_io_api",
|
"crates_io_api",
|
||||||
|
"detect-targets",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"flate2",
|
"flate2",
|
||||||
"flock",
|
"flock",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"guess_host_triple",
|
|
||||||
"home",
|
"home",
|
||||||
"itertools",
|
"itertools",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
|
@ -350,6 +350,15 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "detect-targets"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"guess_host_triple",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "detect-wasi"
|
name = "detect-wasi"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
|
@ -5,6 +5,7 @@ members = [
|
||||||
"crates/detect-wasi",
|
"crates/detect-wasi",
|
||||||
"crates/flock",
|
"crates/flock",
|
||||||
"crates/normalize-path",
|
"crates/normalize-path",
|
||||||
|
"crates/detect-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::{fs, path::Path, sync::Arc, time::Duration};
|
||||||
|
|
||||||
use binstall::{
|
use binstall::{
|
||||||
errors::BinstallError,
|
errors::BinstallError,
|
||||||
|
get_desired_targets,
|
||||||
helpers::{
|
helpers::{
|
||||||
jobserver_client::LazyJobserverClient, remote::create_reqwest_client,
|
jobserver_client::LazyJobserverClient, remote::create_reqwest_client,
|
||||||
tasks::AutoAbortJoinHandle,
|
tasks::AutoAbortJoinHandle,
|
||||||
|
@ -13,7 +14,6 @@ use binstall::{
|
||||||
self,
|
self,
|
||||||
resolve::{CrateName, Resolution, VersionReqExt},
|
resolve::{CrateName, Resolution, VersionReqExt},
|
||||||
},
|
},
|
||||||
targets::get_desired_targets,
|
|
||||||
};
|
};
|
||||||
use log::{debug, error, info, warn, LevelFilter};
|
use log::{debug, error, info, warn, LevelFilter};
|
||||||
use miette::{miette, Result, WrapErr};
|
use miette::{miette, Result, WrapErr};
|
||||||
|
@ -29,7 +29,7 @@ pub async fn install_crates(mut args: Args, jobserver_client: LazyJobserverClien
|
||||||
};
|
};
|
||||||
|
|
||||||
// Launch target detection
|
// Launch target detection
|
||||||
let desired_targets = get_desired_targets(&args.targets);
|
let desired_targets = get_desired_targets(args.targets.as_deref());
|
||||||
|
|
||||||
// Initialize reqwest client
|
// Initialize reqwest client
|
||||||
let client = create_reqwest_client(args.secure, args.min_tls_version.map(|v| v.into()))?;
|
let client = create_reqwest_client(args.secure, args.min_tls_version.map(|v| v.into()))?;
|
||||||
|
|
20
crates/detect-targets/Cargo.toml
Normal file
20
crates/detect-targets/Cargo.toml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
[package]
|
||||||
|
name = "detect-targets"
|
||||||
|
description = "Detect the target of the env at runtime"
|
||||||
|
repository = "https://github.com/cargo-bins/cargo-binstall"
|
||||||
|
documentation = "https://docs.rs/detect-target"
|
||||||
|
version = "0.1.0"
|
||||||
|
rust-version = "1.61.0"
|
||||||
|
authors = ["Jiahao XU <Jiahao_XU@outlook.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
license = "Apache-2.0 OR MIT"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tokio = { version = "1.20.1", features = ["rt", "process", "sync"], default-features = false }
|
||||||
|
cfg-if = "1.0.0"
|
||||||
|
|
||||||
|
[target.'cfg(any(target_os = "macos", target_os = "windows"))'.dependencies]
|
||||||
|
guess_host_triple = "0.1.3"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tokio = { version = "1.20.1", features = ["macros"], default-features = false }
|
176
crates/detect-targets/LICENSE-APACHE
Normal file
176
crates/detect-targets/LICENSE-APACHE
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
23
crates/detect-targets/LICENSE-MIT
Normal file
23
crates/detect-targets/LICENSE-MIT
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
Permission is hereby granted, free of charge, to any
|
||||||
|
person obtaining a copy of this software and associated
|
||||||
|
documentation files (the "Software"), to deal in the
|
||||||
|
Software without restriction, including without
|
||||||
|
limitation the rights to use, copy, modify, merge,
|
||||||
|
publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software
|
||||||
|
is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice
|
||||||
|
shall be included in all copies or substantial portions
|
||||||
|
of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||||
|
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||||
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
59
crates/detect-targets/src/desired_targets.rs
Normal file
59
crates/detect-targets/src/desired_targets.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use crate::detect_targets;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use tokio::sync::OnceCell;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum DesiredTargetsInner {
|
||||||
|
AutoDetect(Arc<OnceCell<Vec<String>>>),
|
||||||
|
Initialized(Vec<String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DesiredTargets(DesiredTargetsInner);
|
||||||
|
|
||||||
|
impl DesiredTargets {
|
||||||
|
fn initialized(targets: Vec<String>) -> Self {
|
||||||
|
Self(DesiredTargetsInner::Initialized(targets))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn auto_detect() -> Self {
|
||||||
|
let arc = Arc::new(OnceCell::new());
|
||||||
|
|
||||||
|
let once_cell = arc.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
once_cell.get_or_init(detect_targets).await;
|
||||||
|
});
|
||||||
|
|
||||||
|
Self(DesiredTargetsInner::AutoDetect(arc))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get(&self) -> &[String] {
|
||||||
|
use DesiredTargetsInner::*;
|
||||||
|
|
||||||
|
match &self.0 {
|
||||||
|
Initialized(targets) => targets,
|
||||||
|
|
||||||
|
// This will mostly just wait for the spawned task,
|
||||||
|
// on rare occausion though, it will poll the future
|
||||||
|
// returned by `detect_targets`.
|
||||||
|
AutoDetect(once_cell) => once_cell.get_or_init(detect_targets).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If opts_targets is `Some`, then it will be parsed in the format of
|
||||||
|
/// `$target1,$target2,...`.
|
||||||
|
/// Otherwise, call `detect_targets` using `tokio::spawn` to detect targets.
|
||||||
|
///
|
||||||
|
/// Since `detect_targets` internally spawns a process and wait for it,
|
||||||
|
/// it's pretty costy, it is recommended to run this fn ASAP and
|
||||||
|
/// reuse the result.
|
||||||
|
pub fn get_desired_targets(opts_targets: Option<&str>) -> DesiredTargets {
|
||||||
|
if let Some(targets) = opts_targets {
|
||||||
|
DesiredTargets::initialized(targets.split(',').map(|t| t.to_string()).collect())
|
||||||
|
} else {
|
||||||
|
DesiredTargets::auto_detect()
|
||||||
|
}
|
||||||
|
}
|
88
crates/detect-targets/src/detect.rs
Normal file
88
crates/detect-targets/src/detect.rs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
use std::{
|
||||||
|
io::{BufRead, Cursor},
|
||||||
|
process::{Output, Stdio},
|
||||||
|
};
|
||||||
|
|
||||||
|
use cfg_if::cfg_if;
|
||||||
|
use tokio::process::Command;
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(target_os = "linux")] {
|
||||||
|
mod linux;
|
||||||
|
} else if #[cfg(target_os = "macos")] {
|
||||||
|
mod macos;
|
||||||
|
} else if #[cfg(target_os = "windows")] {
|
||||||
|
mod windows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Detect the targets supported at runtime,
|
||||||
|
/// which might be different from `TARGET` which is detected
|
||||||
|
/// at compile-time.
|
||||||
|
///
|
||||||
|
/// Return targets supported in the order of preference.
|
||||||
|
/// If target_os is linux and it support gnu, then it is preferred
|
||||||
|
/// to musl.
|
||||||
|
///
|
||||||
|
/// If target_os is mac and it is aarch64, then aarch64 is preferred
|
||||||
|
/// to x86_64.
|
||||||
|
///
|
||||||
|
/// Check [this issue](https://github.com/ryankurte/cargo-binstall/issues/155)
|
||||||
|
/// for more information.
|
||||||
|
pub async fn detect_targets() -> Vec<String> {
|
||||||
|
if let Some(target) = get_target_from_rustc().await {
|
||||||
|
let mut v = vec![target];
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(target_os = "linux")] {
|
||||||
|
if v[0].contains("gnu") {
|
||||||
|
v.push(v[0].replace("gnu", "musl"));
|
||||||
|
}
|
||||||
|
} else if #[cfg(target_os = "macos")] {
|
||||||
|
if &*v[0] == macos::AARCH64 {
|
||||||
|
v.push(macos::X86.into());
|
||||||
|
}
|
||||||
|
} else if #[cfg(target_os = "windows")] {
|
||||||
|
v.extend(windows::detect_alternative_targets(&v[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v
|
||||||
|
} else {
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(target_os = "linux")] {
|
||||||
|
linux::detect_targets_linux().await
|
||||||
|
} else if #[cfg(target_os = "macos")] {
|
||||||
|
macos::detect_targets_macos()
|
||||||
|
} else if #[cfg(target_os = "windows")] {
|
||||||
|
windows::detect_targets_windows()
|
||||||
|
} else {
|
||||||
|
vec![TARGET.into()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Figure out what the host target is using `rustc`.
|
||||||
|
/// If `rustc` is absent, then it would return `None`.
|
||||||
|
async fn get_target_from_rustc() -> Option<String> {
|
||||||
|
let Output { status, stdout, .. } = Command::new("rustc")
|
||||||
|
.arg("-vV")
|
||||||
|
.stdin(Stdio::null())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::null())
|
||||||
|
.spawn()
|
||||||
|
.ok()?
|
||||||
|
.wait_with_output()
|
||||||
|
.await
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cursor::new(stdout)
|
||||||
|
.lines()
|
||||||
|
.filter_map(|line| line.ok())
|
||||||
|
.find_map(|line| line.strip_prefix("host: ").map(|host| host.to_owned()))
|
||||||
|
}
|
86
crates/detect-targets/src/detect/linux.rs
Normal file
86
crates/detect-targets/src/detect/linux.rs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
use crate::TARGET;
|
||||||
|
|
||||||
|
use std::process::{Output, Stdio};
|
||||||
|
|
||||||
|
use tokio::process::Command;
|
||||||
|
|
||||||
|
pub(super) async fn detect_targets_linux() -> Vec<String> {
|
||||||
|
let (abi, libc) = parse_abi_and_libc();
|
||||||
|
|
||||||
|
if let Libc::Glibc = libc {
|
||||||
|
// Glibc can only be dynamically linked.
|
||||||
|
// If we can run this binary, then it means that the target
|
||||||
|
// supports both glibc and musl.
|
||||||
|
return create_targets_str(&["gnu", "musl"], abi);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(Output {
|
||||||
|
status: _,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
}) = Command::new("ldd")
|
||||||
|
.arg("--version")
|
||||||
|
.stdin(Stdio::null())
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
let libc_version = if let Some(libc_version) = parse_libc_version_from_ldd_output(&stdout) {
|
||||||
|
libc_version
|
||||||
|
} else if let Some(libc_version) = parse_libc_version_from_ldd_output(&stderr) {
|
||||||
|
libc_version
|
||||||
|
} else {
|
||||||
|
return vec![create_target_str("musl", abi)];
|
||||||
|
};
|
||||||
|
|
||||||
|
if libc_version == "gnu" {
|
||||||
|
return create_targets_str(&["gnu", "musl"], abi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to using musl
|
||||||
|
vec![create_target_str("musl", abi)]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_libc_version_from_ldd_output(output: &[u8]) -> Option<&'static str> {
|
||||||
|
let s = String::from_utf8_lossy(output);
|
||||||
|
if s.contains("musl libc") {
|
||||||
|
Some("musl")
|
||||||
|
} else if s.contains("GLIBC") {
|
||||||
|
Some("gnu")
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Libc {
|
||||||
|
Glibc,
|
||||||
|
Musl,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_abi_and_libc() -> (&'static str, Libc) {
|
||||||
|
let last = TARGET.rsplit_once('-').unwrap().1;
|
||||||
|
|
||||||
|
if let Some(libc_version) = last.strip_prefix("musl") {
|
||||||
|
(libc_version, Libc::Musl)
|
||||||
|
} else if let Some(libc_version) = last.strip_prefix("gnu") {
|
||||||
|
(libc_version, Libc::Glibc)
|
||||||
|
} else {
|
||||||
|
panic!("Unrecognized libc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_target_str(libc_version: &str, abi: &str) -> String {
|
||||||
|
let prefix = TARGET
|
||||||
|
.rsplit_once('-')
|
||||||
|
.expect("unwrap: TARGET always has a -")
|
||||||
|
.0;
|
||||||
|
|
||||||
|
format!("{prefix}-{libc_version}{abi}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_targets_str(libc_versions: &[&str], abi: &str) -> Vec<String> {
|
||||||
|
libc_versions
|
||||||
|
.iter()
|
||||||
|
.map(|libc_version| create_target_str(libc_version, abi))
|
||||||
|
.collect()
|
||||||
|
}
|
15
crates/detect-targets/src/detect/macos.rs
Normal file
15
crates/detect-targets/src/detect/macos.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
use crate::TARGET;
|
||||||
|
use guess_host_triple::guess_host_triple;
|
||||||
|
|
||||||
|
pub(super) const AARCH64: &str = "aarch64-apple-darwin";
|
||||||
|
pub(super) const X86: &str = "x86_64-apple-darwin";
|
||||||
|
|
||||||
|
pub(super) fn detect_targets_macos() -> Vec<String> {
|
||||||
|
let mut targets = vec![guess_host_triple().unwrap_or(TARGET).to_string()];
|
||||||
|
|
||||||
|
if targets[0] == AARCH64 {
|
||||||
|
targets.push(X86.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
targets
|
||||||
|
}
|
17
crates/detect-targets/src/detect/windows.rs
Normal file
17
crates/detect-targets/src/detect/windows.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
use crate::TARGET;
|
||||||
|
use guess_host_triple::guess_host_triple;
|
||||||
|
|
||||||
|
pub(super) fn detect_alternative_targets(target: &str) -> Option<String> {
|
||||||
|
let (prefix, abi) = target.rsplit_once('-')?;
|
||||||
|
|
||||||
|
// detect abi in ["gnu", "gnullvm", ...]
|
||||||
|
(abi != "msvc").then(|| format!("{prefix}-msvc"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn detect_targets_windows() -> Vec<String> {
|
||||||
|
let mut targets = vec![guess_host_triple().unwrap_or(TARGET).to_string()];
|
||||||
|
|
||||||
|
targets.extend(detect_alternative_targets(&targets[0]));
|
||||||
|
|
||||||
|
targets
|
||||||
|
}
|
65
crates/detect-targets/src/lib.rs
Normal file
65
crates/detect-targets/src/lib.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
//! Detect the target at the runtime.
|
||||||
|
//!
|
||||||
|
//! Example use cases:
|
||||||
|
//! - The binary is built with musl libc to run on anywhere, but
|
||||||
|
//! the runtime supports glibc.
|
||||||
|
//! - The binary is built for x86_64-apple-darwin, but run on
|
||||||
|
//! aarch64-apple-darwin.
|
||||||
|
//!
|
||||||
|
//! This crate provides two API:
|
||||||
|
//! - [`detect_targets`] provides the API to get the target
|
||||||
|
//! at runtime, but the code is run on the current thread.
|
||||||
|
//! - [`get_desired_targets`] provides the API to either
|
||||||
|
//! parse `$target1,$target2,...` override provided by the users,
|
||||||
|
//! or run [`detect_targets`] in the background using [`tokio::spawn`].
|
||||||
|
//!
|
||||||
|
//! # Example
|
||||||
|
//!
|
||||||
|
//! `detect_targets`:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use detect_targets::detect_targets;
|
||||||
|
//! # #[tokio::main(flavor = "current_thread")]
|
||||||
|
//! # async fn main() {
|
||||||
|
//!
|
||||||
|
//! let targets = detect_targets().await;
|
||||||
|
//! eprintln!("Your platform supports targets: {targets:#?}");
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! `get_desired_targets` with user override:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use detect_targets::get_desired_targets;
|
||||||
|
//! # #[tokio::main(flavor = "current_thread")]
|
||||||
|
//! # async fn main() {
|
||||||
|
//!
|
||||||
|
//! assert_eq!(
|
||||||
|
//! get_desired_targets(Some("x86_64-apple-darwin,aarch64-apple-darwin")).get().await,
|
||||||
|
//! &["x86_64-apple-darwin", "aarch64-apple-darwin"],
|
||||||
|
//! );
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! `get_desired_targets` without user override:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use detect_targets::get_desired_targets;
|
||||||
|
//! # #[tokio::main(flavor = "current_thread")]
|
||||||
|
//! # async fn main() {
|
||||||
|
//!
|
||||||
|
//! eprintln!(
|
||||||
|
//! "Your platform supports targets: {:#?}",
|
||||||
|
//! get_desired_targets(None).get().await
|
||||||
|
//! );
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
mod detect;
|
||||||
|
pub use detect::detect_targets;
|
||||||
|
|
||||||
|
mod desired_targets;
|
||||||
|
pub use desired_targets::{get_desired_targets, DesiredTargets};
|
||||||
|
|
||||||
|
/// Compiled target triple, used as default for binary fetching
|
||||||
|
pub const TARGET: &str = env!("TARGET");
|
|
@ -17,6 +17,7 @@ cargo_toml = "0.11.5"
|
||||||
clap = { version = "3.2.17", features = ["derive"] }
|
clap = { version = "3.2.17", features = ["derive"] }
|
||||||
compact_str = { version = "0.5.2", features = ["serde"] }
|
compact_str = { version = "0.5.2", features = ["serde"] }
|
||||||
crates_io_api = { version = "0.8.0", default-features = false }
|
crates_io_api = { version = "0.8.0", default-features = false }
|
||||||
|
detect-targets = { version = "0.1.0", path = "../detect-targets" }
|
||||||
flate2 = { version = "1.0.24", default-features = false }
|
flate2 = { version = "1.0.24", default-features = false }
|
||||||
flock = { version = "0.1.0", path = "../flock" }
|
flock = { version = "0.1.0", path = "../flock" }
|
||||||
futures-util = { version = "0.3.23", default-features = false }
|
futures-util = { version = "0.3.23", default-features = false }
|
||||||
|
@ -57,9 +58,6 @@ zip = { version = "0.6.2", default-features = false, features = ["deflate", "bzi
|
||||||
# otherwise there will be a link conflict.
|
# otherwise there will be a link conflict.
|
||||||
zstd = { version = "0.10.0", default-features = false }
|
zstd = { version = "0.10.0", default-features = false }
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "macos", target_os = "windows"))'.dependencies]
|
|
||||||
guess_host_triple = "0.1.3"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.9.0"
|
env_logger = "0.9.0"
|
||||||
|
|
||||||
|
|
|
@ -6,4 +6,5 @@ pub mod fs;
|
||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
pub mod manifests;
|
pub mod manifests;
|
||||||
pub mod ops;
|
pub mod ops;
|
||||||
pub mod targets;
|
|
||||||
|
pub use detect_targets::{get_desired_targets, DesiredTargets};
|
||||||
|
|
|
@ -170,9 +170,10 @@ impl<'a> IntoIterator for &'a Records {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{manifests::crate_info::CrateSource, targets::TARGET};
|
use crate::manifests::crate_info::CrateSource;
|
||||||
|
|
||||||
use compact_str::CompactString;
|
use compact_str::CompactString;
|
||||||
|
use detect_targets::TARGET;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
|
|
||||||
|
|
|
@ -130,8 +130,9 @@ pub enum CratesTomlParseError {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{manifests::crate_info::CrateSource, targets::TARGET};
|
use crate::manifests::crate_info::CrateSource;
|
||||||
|
|
||||||
|
use detect_targets::TARGET;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::path::PathBuf;
|
||||||
|
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
|
|
||||||
use crate::{manifests::cargo_toml_binstall::PkgOverride, targets::DesiredTargets};
|
use crate::{manifests::cargo_toml_binstall::PkgOverride, DesiredTargets};
|
||||||
|
|
||||||
pub mod install;
|
pub mod install;
|
||||||
pub mod resolve;
|
pub mod resolve;
|
||||||
|
|
|
@ -1,253 +0,0 @@
|
||||||
use std::{
|
|
||||||
io::{BufRead, Cursor},
|
|
||||||
process::Output,
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use tokio::{process::Command, sync::OnceCell};
|
|
||||||
|
|
||||||
/// Compiled target triple, used as default for binary fetching
|
|
||||||
pub const TARGET: &str = env!("TARGET");
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum DesiredTargetsInner {
|
|
||||||
AutoDetect(Arc<OnceCell<Vec<String>>>),
|
|
||||||
Initialized(Vec<String>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DesiredTargets(DesiredTargetsInner);
|
|
||||||
|
|
||||||
impl DesiredTargets {
|
|
||||||
fn initialized(targets: Vec<String>) -> Self {
|
|
||||||
Self(DesiredTargetsInner::Initialized(targets))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn auto_detect() -> Self {
|
|
||||||
let arc = Arc::new(OnceCell::new());
|
|
||||||
|
|
||||||
let once_cell = arc.clone();
|
|
||||||
tokio::spawn(async move {
|
|
||||||
once_cell.get_or_init(detect_targets).await;
|
|
||||||
});
|
|
||||||
|
|
||||||
Self(DesiredTargetsInner::AutoDetect(arc))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get(&self) -> &[String] {
|
|
||||||
use DesiredTargetsInner::*;
|
|
||||||
|
|
||||||
match &self.0 {
|
|
||||||
Initialized(targets) => targets,
|
|
||||||
|
|
||||||
// This will mostly just wait for the spawned task,
|
|
||||||
// on rare occausion though, it will poll the future
|
|
||||||
// returned by `detect_targets`.
|
|
||||||
AutoDetect(once_cell) => once_cell.get_or_init(detect_targets).await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If opts_targets is `Some`, then it will be used.
|
|
||||||
/// Otherwise, call `detect_targets` using `tokio::spawn` to detect targets.
|
|
||||||
///
|
|
||||||
/// Since `detect_targets` internally spawns a process and wait for it,
|
|
||||||
/// it's pretty costy.
|
|
||||||
///
|
|
||||||
/// Calling it through `tokio::spawn` would enable other tasks, such as
|
|
||||||
/// fetching the crate tarballs, to be executed concurrently.
|
|
||||||
pub fn get_desired_targets(opts_targets: &Option<String>) -> DesiredTargets {
|
|
||||||
if let Some(targets) = opts_targets.as_ref() {
|
|
||||||
DesiredTargets::initialized(targets.split(',').map(|t| t.to_string()).collect())
|
|
||||||
} else {
|
|
||||||
DesiredTargets::auto_detect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Detect the targets supported at runtime,
|
|
||||||
/// which might be different from `TARGET` which is detected
|
|
||||||
/// at compile-time.
|
|
||||||
///
|
|
||||||
/// Return targets supported in the order of preference.
|
|
||||||
/// If target_os is linux and it support gnu, then it is preferred
|
|
||||||
/// to musl.
|
|
||||||
///
|
|
||||||
/// If target_os is mac and it is aarch64, then aarch64 is preferred
|
|
||||||
/// to x86_64.
|
|
||||||
///
|
|
||||||
/// Check [this issue](https://github.com/ryankurte/cargo-binstall/issues/155)
|
|
||||||
/// for more information.
|
|
||||||
pub async fn detect_targets() -> Vec<String> {
|
|
||||||
if let Some(target) = get_target_from_rustc().await {
|
|
||||||
let mut v = vec![target];
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
if v[0].contains("gnu") {
|
|
||||||
v.push(v[0].replace("gnu", "musl"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
if &*v[0] == macos::AARCH64 {
|
|
||||||
v.push(macos::X86.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
v.extend(windows::detect_alternative_targets(&v[0]));
|
|
||||||
|
|
||||||
v
|
|
||||||
} else {
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
{
|
|
||||||
linux::detect_targets_linux().await
|
|
||||||
}
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
{
|
|
||||||
macos::detect_targets_macos()
|
|
||||||
}
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
{
|
|
||||||
windows::detect_targets_windows()
|
|
||||||
}
|
|
||||||
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
|
|
||||||
{
|
|
||||||
vec![TARGET.into()]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Figure out what the host target is using `rustc`.
|
|
||||||
/// If `rustc` is absent, then it would return `None`.
|
|
||||||
async fn get_target_from_rustc() -> Option<String> {
|
|
||||||
let Output { status, stdout, .. } = Command::new("rustc").arg("-vV").output().await.ok()?;
|
|
||||||
if !status.success() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Cursor::new(stdout)
|
|
||||||
.lines()
|
|
||||||
.filter_map(|line| line.ok())
|
|
||||||
.find_map(|line| line.strip_prefix("host: ").map(|host| host.to_owned()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
mod linux {
|
|
||||||
use super::{Command, Output, TARGET};
|
|
||||||
|
|
||||||
pub(super) async fn detect_targets_linux() -> Vec<String> {
|
|
||||||
let (abi, libc) = parse_abi_and_libc();
|
|
||||||
|
|
||||||
if let Libc::Glibc = libc {
|
|
||||||
// Glibc can only be dynamically linked.
|
|
||||||
// If we can run this binary, then it means that the target
|
|
||||||
// supports both glibc and musl.
|
|
||||||
return create_targets_str(&["gnu", "musl"], abi);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(Output {
|
|
||||||
status: _,
|
|
||||||
stdout,
|
|
||||||
stderr,
|
|
||||||
}) = Command::new("ldd").arg("--version").output().await
|
|
||||||
{
|
|
||||||
let libc_version =
|
|
||||||
if let Some(libc_version) = parse_libc_version_from_ldd_output(&stdout) {
|
|
||||||
libc_version
|
|
||||||
} else if let Some(libc_version) = parse_libc_version_from_ldd_output(&stderr) {
|
|
||||||
libc_version
|
|
||||||
} else {
|
|
||||||
return vec![create_target_str("musl", abi)];
|
|
||||||
};
|
|
||||||
|
|
||||||
if libc_version == "gnu" {
|
|
||||||
return create_targets_str(&["gnu", "musl"], abi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to using musl
|
|
||||||
vec![create_target_str("musl", abi)]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_libc_version_from_ldd_output(output: &[u8]) -> Option<&'static str> {
|
|
||||||
let s = String::from_utf8_lossy(output);
|
|
||||||
if s.contains("musl libc") {
|
|
||||||
Some("musl")
|
|
||||||
} else if s.contains("GLIBC") {
|
|
||||||
Some("gnu")
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Libc {
|
|
||||||
Glibc,
|
|
||||||
Musl,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_abi_and_libc() -> (&'static str, Libc) {
|
|
||||||
let last = TARGET.rsplit_once('-').unwrap().1;
|
|
||||||
|
|
||||||
if let Some(libc_version) = last.strip_prefix("musl") {
|
|
||||||
(libc_version, Libc::Musl)
|
|
||||||
} else if let Some(libc_version) = last.strip_prefix("gnu") {
|
|
||||||
(libc_version, Libc::Glibc)
|
|
||||||
} else {
|
|
||||||
panic!("Unrecognized libc")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_target_str(libc_version: &str, abi: &str) -> String {
|
|
||||||
let prefix = TARGET
|
|
||||||
.rsplit_once('-')
|
|
||||||
.expect("unwrap: TARGET always has a -")
|
|
||||||
.0;
|
|
||||||
|
|
||||||
format!("{prefix}-{libc_version}{abi}")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_targets_str(libc_versions: &[&str], abi: &str) -> Vec<String> {
|
|
||||||
libc_versions
|
|
||||||
.iter()
|
|
||||||
.map(|libc_version| create_target_str(libc_version, abi))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
mod macos {
|
|
||||||
use super::TARGET;
|
|
||||||
use guess_host_triple::guess_host_triple;
|
|
||||||
|
|
||||||
pub(super) const AARCH64: &str = "aarch64-apple-darwin";
|
|
||||||
pub(super) const X86: &str = "x86_64-apple-darwin";
|
|
||||||
|
|
||||||
pub(super) fn detect_targets_macos() -> Vec<String> {
|
|
||||||
let mut targets = vec![guess_host_triple().unwrap_or(TARGET).to_string()];
|
|
||||||
|
|
||||||
if targets[0] == AARCH64 {
|
|
||||||
targets.push(X86.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
targets
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
mod windows {
|
|
||||||
use super::TARGET;
|
|
||||||
use guess_host_triple::guess_host_triple;
|
|
||||||
|
|
||||||
pub(super) fn detect_alternative_targets(target: &str) -> Option<String> {
|
|
||||||
let (prefix, abi) = target.rsplit_once('-').expect("Invalid target triple");
|
|
||||||
|
|
||||||
// detect abi in ["gnu", "gnullvm", ...]
|
|
||||||
(abi != "msvc").then(|| format!("{prefix}-msvc"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn detect_targets_windows() -> Vec<String> {
|
|
||||||
let mut targets = vec![guess_host_triple().unwrap_or(TARGET).to_string()];
|
|
||||||
|
|
||||||
targets.extend(detect_alternative_targets(&targets[0]));
|
|
||||||
|
|
||||||
targets
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue