├── .github ├── actions │ └── install-rust │ │ ├── README.md │ │ ├── action.yml │ │ └── main.js └── workflows │ └── main.yml ├── .gitignore ├── .rustfmt.toml ├── Cargo.toml ├── LICENSE ├── README.md ├── build.rs ├── examples ├── host.rs └── misc.rs ├── scripts └── rust-targets.sh └── src ├── data_model.rs ├── host.rs ├── lib.rs ├── parse_error.rs ├── targets.rs └── triple.rs /.github/actions/install-rust/README.md: -------------------------------------------------------------------------------- 1 | # install-rust 2 | 3 | A small github action to install `rustup` and a Rust toolchain. This is 4 | generally expressed inline, but it was repeated enough in this repository it 5 | seemed worthwhile to extract. 6 | 7 | Some gotchas: 8 | 9 | * Can't `--self-update` on Windows due to permission errors (a bug in Github 10 | Actions) 11 | * `rustup` isn't installed on macOS (a bug in Github Actions) 12 | 13 | When the above are fixed we should delete this action and just use this inline: 14 | 15 | ```yml 16 | - run: rustup update $toolchain && rustup default $toolchain 17 | shell: bash 18 | ``` 19 | -------------------------------------------------------------------------------- /.github/actions/install-rust/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Install Rust toolchain' 2 | description: 'Install both `rustup` and a Rust toolchain' 3 | 4 | inputs: 5 | toolchain: 6 | description: 'Default toolchan to install' 7 | required: false 8 | default: 'stable' 9 | 10 | runs: 11 | using: node12 12 | main: 'main.js' 13 | -------------------------------------------------------------------------------- /.github/actions/install-rust/main.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | const toolchain = process.env.INPUT_TOOLCHAIN; 3 | const fs = require('fs'); 4 | 5 | function set_env(name, val) { 6 | fs.appendFileSync(process.env['GITHUB_ENV'], `${name}=${val}\n`) 7 | } 8 | 9 | // Needed for now to get 1.24.2 which fixes a bug in 1.24.1 that causes issues 10 | // on Windows. 11 | if (process.platform === 'win32') { 12 | child_process.execFileSync('rustup', ['self', 'update']); 13 | } 14 | 15 | child_process.execFileSync('rustup', ['set', 'profile', 'minimal']); 16 | child_process.execFileSync('rustup', ['update', toolchain, '--no-self-update']); 17 | child_process.execFileSync('rustup', ['default', toolchain]); 18 | 19 | // Deny warnings on CI to keep our code warning-free as it lands in-tree. Don't 20 | // do this on nightly though since there's a fair amount of warning churn there. 21 | // 22 | // Disable this for now to avoid `unexpected_cfgs` in a way that works with 23 | // Rust 1.34. 24 | //if (!toolchain.startsWith('nightly')) { 25 | // set_env("RUSTFLAGS", "-D warnings"); 26 | //} 27 | 28 | // Save disk space by avoiding incremental compilation, and also we don't use 29 | // any caching so incremental wouldn't help anyway. 30 | set_env("CARGO_INCREMENTAL", "0"); 31 | 32 | // Turn down debuginfo from 2 to 1 to help save disk space 33 | set_env("CARGO_PROFILE_DEV_DEBUG", "1"); 34 | set_env("CARGO_PROFILE_TEST_DEBUG", "1"); 35 | 36 | if (process.platform === 'darwin') { 37 | set_env("CARGO_PROFILE_DEV_SPLIT_DEBUGINFO", "unpacked"); 38 | set_env("CARGO_PROFILE_TEST_SPLIT_DEBUGINFO", "unpacked"); 39 | } 40 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | rustfmt: 11 | name: Rustfmt 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v1 15 | with: 16 | submodules: true 17 | - uses: ./.github/actions/install-rust 18 | with: 19 | toolchain: stable 20 | - run: cargo fmt --all -- --check 21 | 22 | build: 23 | name: Build 24 | runs-on: ${{ matrix.os }} 25 | strategy: 26 | matrix: 27 | build: [1.34.2, stable, beta, nightly, windows, macos] 28 | include: 29 | - build: 1.34.2 30 | os: ubuntu-latest 31 | rust: 1.34.2 32 | - build: stable 33 | os: ubuntu-latest 34 | rust: stable 35 | - build: beta 36 | os: ubuntu-latest 37 | rust: beta 38 | - build: nightly 39 | os: ubuntu-latest 40 | rust: nightly 41 | - build: macos 42 | os: macos-latest 43 | rust: stable 44 | - build: windows 45 | os: windows-latest 46 | rust: stable 47 | - build: windows 48 | os: windows-latest 49 | rust: nightly 50 | 51 | steps: 52 | - uses: actions/checkout@v1 53 | with: 54 | submodules: true 55 | - uses: ./.github/actions/install-rust 56 | with: 57 | toolchain: ${{ matrix.rust }} 58 | - run: cargo build --all --all-features --release -vv 59 | 60 | test: 61 | name: Test 62 | runs-on: ${{ matrix.os }} 63 | strategy: 64 | matrix: 65 | build: [stable, beta, nightly, macos, windows] 66 | include: 67 | - build: stable 68 | os: ubuntu-latest 69 | rust: stable 70 | - build: beta 71 | os: ubuntu-latest 72 | rust: beta 73 | - build: nightly 74 | os: ubuntu-latest 75 | rust: nightly 76 | - build: macos 77 | os: macos-latest 78 | rust: stable 79 | - build: windows 80 | os: windows-latest 81 | rust: stable 82 | - build: windows 83 | os: windows-latest 84 | rust: nightly 85 | 86 | steps: 87 | - uses: actions/checkout@v1 88 | with: 89 | submodules: true 90 | - uses: ./.github/actions/install-rust 91 | with: 92 | toolchain: ${{ matrix.rust }} 93 | - run: cargo test --all-features --all 94 | 95 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bk 2 | *.swp 3 | *.swo 4 | *.swx 5 | tags 6 | target 7 | Cargo.lock 8 | .*.rustfmt 9 | rusty-tags.* 10 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bytecodealliance/target-lexicon/816bd806ad1bf190bf301bc285d3e53d946d52e7/.rustfmt.toml -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "target-lexicon" 3 | version = "0.13.2" 4 | authors = ["Dan Gohman "] 5 | description = "LLVM target triple types" 6 | documentation = "https://docs.rs/target-lexicon/" 7 | readme = "README.md" 8 | keywords = ["target", "host", "triple", "compiler", "jit"] 9 | categories = ["no-std"] 10 | license = "Apache-2.0 WITH LLVM-exception" 11 | repository = "https://github.com/bytecodealliance/target-lexicon" 12 | edition = "2018" 13 | 14 | [dependencies] 15 | serde = { version = "1.0", optional = true } 16 | 17 | [dev-dependencies] 18 | serde_json = "1.0" 19 | 20 | [features] 21 | default = [] 22 | serde_support = ["serde", "std"] 23 | std = [] 24 | # Enable (unstable) support for the zkasm architecture. 25 | arch_zkasm = [] 26 | 27 | [badges] 28 | maintenance = { status = "passively-maintained" } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | 204 | 205 | --- LLVM Exceptions to the Apache 2.0 License ---- 206 | 207 | As an exception, if, as a result of your compiling your source code, portions 208 | of this Software are embedded into an Object form of such source code, you 209 | may redistribute such embedded portions in such Object form without complying 210 | with the conditions of Sections 4(a), 4(b) and 4(d) of the License. 211 | 212 | In addition, if you combine or link compiled forms of this Software with 213 | software that is licensed under the GPLv2 ("Combined Software") and if a 214 | court of competent jurisdiction determines that the patent provision (Section 215 | 3), the indemnity provision (Section 9) or other Section of the License 216 | conflicts with the conditions of the GPLv2, you may retroactively and 217 | prospectively choose to deem waived or otherwise exclude such Section(s) of 218 | the License, but only in their entirety and only with respect to the Combined 219 | Software. 220 | 221 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a library for managing targets for compilers and related tools. 2 | 3 | Currently, the main feature is support for decoding [LLVM "triples"], which 4 | are strings that identify a particular target configuration. They're named 5 | "triples" because historically they contained three fields, though over time 6 | they've added additional fields. This library provides a `Triple` struct 7 | containing enums for each of fields of a triple. `Triple` implements 8 | `FromStr` and `fmt::Display` so it can be converted to and from the 9 | conventional string representation of a triple. 10 | 11 | `Triple` also has functions for querying a triple's endianness, 12 | pointer bit width, and binary format. 13 | 14 | And, `Triple` and the enum types have `host()` constructors, for targeting 15 | the host. 16 | 17 | It somewhat supports reading triples currently used by `rustc` and rustup, 18 | though beware that the mapping between `rustc` and LLVM triples is not 19 | one-to-one. 20 | 21 | It does not support reading JSON target files itself. To use it with a JSON 22 | target file, construct a `Triple` using the value of the "llvm-target" field. 23 | 24 | [LLVM "triples"]: https://clang.llvm.org/docs/CrossCompilation.html#target-triple 25 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | //! build.rs file to obtain the host information. 2 | 3 | // Allow dead code in triple.rs and targets.rs for our purposes here. 4 | #![allow(dead_code)] 5 | 6 | use std::env; 7 | use std::fs::File; 8 | use std::io::{self, Write}; 9 | use std::path::PathBuf; 10 | use std::process::Command; 11 | use std::str::FromStr; 12 | 13 | #[cfg(not(feature = "std"))] 14 | extern crate alloc; 15 | #[cfg(feature = "std")] 16 | extern crate std as alloc; 17 | 18 | // Include triple.rs and targets.rs so we can parse the TARGET environment variable. 19 | // targets.rs depends on data_model 20 | mod data_model { 21 | include!("src/data_model.rs"); 22 | } 23 | mod triple { 24 | include!("src/triple.rs"); 25 | } 26 | mod targets { 27 | include!("src/targets.rs"); 28 | } 29 | 30 | // Stub out `ParseError` to minimally support triple.rs and targets.rs. 31 | mod parse_error { 32 | #[derive(Debug)] 33 | pub enum ParseError { 34 | UnrecognizedArchitecture(String), 35 | UnrecognizedVendor(String), 36 | UnrecognizedOperatingSystem(String), 37 | UnrecognizedEnvironment(String), 38 | UnrecognizedBinaryFormat(String), 39 | UnrecognizedField(String), 40 | } 41 | } 42 | 43 | use self::targets::Vendor; 44 | use self::triple::Triple; 45 | 46 | fn main() { 47 | let out_dir = PathBuf::from( 48 | env::var_os("OUT_DIR").expect("The OUT_DIR environment variable must be set"), 49 | ); 50 | let target = env::var("TARGET").expect("The TARGET environment variable must be set"); 51 | let triple = 52 | Triple::from_str(&target).unwrap_or_else(|_| panic!("Invalid target name: '{}'", target)); 53 | let out = File::create(out_dir.join("host.rs")).expect("error creating host.rs"); 54 | write_host_rs(out, triple).expect("error writing host.rs"); 55 | if using_1_40() { 56 | println!("cargo:rustc-cfg=feature=\"rust_1_40\""); 57 | } 58 | } 59 | 60 | fn using_1_40() -> bool { 61 | match (|| { 62 | let rustc = env::var_os("RUSTC").unwrap(); 63 | let output = Command::new(rustc).arg("--version").output().ok()?; 64 | let stdout = if output.status.success() { 65 | output.stdout 66 | } else { 67 | return None; 68 | }; 69 | std::str::from_utf8(&stdout) 70 | .ok()? 71 | .split(' ') 72 | .nth(1)? 73 | .split('.') 74 | .nth(1)? 75 | .parse::() 76 | .ok() 77 | })() { 78 | Some(version) => version >= 40, 79 | None => true, // assume we're using an up-to-date compiler 80 | } 81 | } 82 | 83 | fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> { 84 | // The generated Debug implementation for the inner architecture variants 85 | // doesn't print the enum name qualifier, so import them here. There 86 | // shouldn't be any conflicts because these enums all share a namespace 87 | // in the triple string format. 88 | writeln!( 89 | out, 90 | r#" 91 | #[allow(unused_imports)] 92 | use crate::Aarch64Architecture::*; 93 | #[allow(unused_imports)] 94 | use crate::ArmArchitecture::*; 95 | #[allow(unused_imports)] 96 | use crate::CustomVendor; 97 | #[allow(unused_imports)] 98 | use crate::Mips32Architecture::*; 99 | #[allow(unused_imports)] 100 | use crate::Mips64Architecture::*; 101 | #[allow(unused_imports)] 102 | use crate::Riscv32Architecture::*; 103 | #[allow(unused_imports)] 104 | use crate::Riscv64Architecture::*; 105 | #[allow(unused_imports)] 106 | use crate::X86_32Architecture::*; 107 | 108 | /// The `Triple` of the current host. 109 | pub const HOST: Triple = Triple {{ 110 | architecture: Architecture::{architecture:?}, 111 | vendor: Vendor::{vendor}, 112 | operating_system: OperatingSystem::{operating_system:?}, 113 | environment: Environment::{environment:?}, 114 | binary_format: BinaryFormat::{binary_format:?}, 115 | }}; 116 | 117 | impl Architecture {{ 118 | /// Return the architecture for the current host. 119 | pub const fn host() -> Self {{ 120 | Architecture::{architecture:?} 121 | }} 122 | }} 123 | 124 | impl Vendor {{ 125 | /// Return the vendor for the current host. 126 | pub const fn host() -> Self {{ 127 | Vendor::{vendor} 128 | }} 129 | }} 130 | 131 | impl OperatingSystem {{ 132 | /// Return the operating system for the current host. 133 | pub const fn host() -> Self {{ 134 | OperatingSystem::{operating_system:?} 135 | }} 136 | }} 137 | 138 | impl Environment {{ 139 | /// Return the environment for the current host. 140 | pub const fn host() -> Self {{ 141 | Environment::{environment:?} 142 | }} 143 | }} 144 | 145 | impl BinaryFormat {{ 146 | /// Return the binary format for the current host. 147 | pub const fn host() -> Self {{ 148 | BinaryFormat::{binary_format:?} 149 | }} 150 | }} 151 | 152 | impl Triple {{ 153 | /// Return the triple for the current host. 154 | pub const fn host() -> Self {{ 155 | Self {{ 156 | architecture: Architecture::{architecture:?}, 157 | vendor: Vendor::{vendor}, 158 | operating_system: OperatingSystem::{operating_system:?}, 159 | environment: Environment::{environment:?}, 160 | binary_format: BinaryFormat::{binary_format:?}, 161 | }} 162 | }} 163 | }}"#, 164 | architecture = triple.architecture, 165 | vendor = vendor_display(&triple.vendor), 166 | operating_system = triple.operating_system, 167 | environment = triple.environment, 168 | binary_format = triple.binary_format, 169 | )?; 170 | 171 | Ok(()) 172 | } 173 | 174 | fn vendor_display(vendor: &Vendor) -> String { 175 | match vendor { 176 | Vendor::Custom(custom) => format!("Custom(CustomVendor::Static({:?}))", custom.as_str()), 177 | known => format!("{:?}", known), 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /examples/host.rs: -------------------------------------------------------------------------------- 1 | extern crate target_lexicon; 2 | 3 | use target_lexicon::HOST; 4 | 5 | fn main() { 6 | println!( 7 | "{}", 8 | HOST.pointer_width() 9 | .expect("architecture should be known") 10 | .bytes() 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /examples/misc.rs: -------------------------------------------------------------------------------- 1 | extern crate target_lexicon; 2 | 3 | use core::str::FromStr; 4 | use target_lexicon::{Triple, HOST}; 5 | 6 | fn main() { 7 | println!("The host triple is {}.", HOST); 8 | 9 | let e = Triple::from_str("riscv32-unknown-unknown") 10 | .expect("expected to recognize the RISC-V target") 11 | .endianness() 12 | .expect("expected to know the endianness of RISC-V"); 13 | println!("The endianness of RISC-V is {:?}.", e); 14 | } 15 | -------------------------------------------------------------------------------- /scripts/rust-targets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | rustup target list | sed 's/ (.*//' > list.txt 5 | rustc +nightly --print target-list >> list.txt 6 | cat list.txt | sort | uniq |sed 's/\(.*\)/ "\1",/' > sorted.txt 7 | rm list.txt 8 | -------------------------------------------------------------------------------- /src/data_model.rs: -------------------------------------------------------------------------------- 1 | /// The size of a type. 2 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 3 | #[allow(missing_docs)] 4 | pub enum Size { 5 | U8, 6 | U16, 7 | U32, 8 | U64, 9 | } 10 | 11 | impl Size { 12 | /// Return the number of bits this `Size` represents. 13 | pub fn bits(self) -> u8 { 14 | use Size::*; 15 | 16 | match self { 17 | U8 => 8, 18 | U16 => 16, 19 | U32 => 32, 20 | U64 => 64, 21 | } 22 | } 23 | 24 | /// Return the number of bytes in a size. 25 | /// 26 | /// A byte is assumed to be 8 bits. 27 | pub fn bytes(self) -> u8 { 28 | use Size::*; 29 | 30 | match self { 31 | U8 => 1, 32 | U16 => 2, 33 | U32 => 4, 34 | U64 => 8, 35 | } 36 | } 37 | } 38 | 39 | /// The C data model used on a target. 40 | /// 41 | /// See also https://en.cppreference.com/w/c/language/arithmetic_types 42 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 43 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 44 | pub enum CDataModel { 45 | /// The data model used most commonly on Win16. `long` and `pointer` are 32 bits. 46 | LP32, 47 | /// The data model used most commonly on Win32 and 32-bit Unix systems. 48 | /// 49 | /// `int`, `long`, and `pointer` are all 32 bits. 50 | ILP32, 51 | /// The data model used most commonly on Win64 52 | /// 53 | /// `long long`, and `pointer` are 64 bits. 54 | LLP64, 55 | /// The data model used most commonly on 64-bit Unix systems 56 | /// 57 | /// `long`, and `pointer` are 64 bits. 58 | LP64, 59 | /// A rare data model used on early 64-bit Unix systems 60 | /// 61 | /// `int`, `long`, and `pointer` are all 64 bits. 62 | ILP64, 63 | } 64 | 65 | impl CDataModel { 66 | /// The width of a pointer (in the default address space). 67 | pub fn pointer_width(self) -> Size { 68 | use CDataModel::*; 69 | 70 | match self { 71 | LP32 | ILP32 => Size::U32, 72 | LLP64 | LP64 | ILP64 => Size::U64, 73 | } 74 | } 75 | /// The size of a C `short`. This is required to be at least 16 bits. 76 | pub fn short_size(self) -> Size { 77 | use CDataModel::*; 78 | 79 | match self { 80 | LP32 | ILP32 | LLP64 | LP64 | ILP64 => Size::U16, 81 | } 82 | } 83 | /// The size of a C `int`. This is required to be at least 16 bits. 84 | pub fn int_size(self) -> Size { 85 | use CDataModel::*; 86 | 87 | match self { 88 | LP32 => Size::U16, 89 | ILP32 | LLP64 | LP64 | ILP64 => Size::U32, 90 | } 91 | } 92 | /// The size of a C `long`. This is required to be at least 32 bits. 93 | pub fn long_size(self) -> Size { 94 | use CDataModel::*; 95 | 96 | match self { 97 | LP32 | ILP32 | LLP64 | ILP64 => Size::U32, 98 | LP64 => Size::U64, 99 | } 100 | } 101 | /// The size of a C `long long`. This is required (in C99+) to be at least 64 bits. 102 | pub fn long_long_size(self) -> Size { 103 | use CDataModel::*; 104 | 105 | match self { 106 | LP32 | ILP32 | LLP64 | ILP64 | LP64 => Size::U64, 107 | } 108 | } 109 | /// The size of a C `float`. 110 | pub fn float_size(self) -> Size { 111 | // TODO: this is probably wrong on at least one architecture 112 | Size::U32 113 | } 114 | /// The size of a C `double`. 115 | pub fn double_size(self) -> Size { 116 | // TODO: this is probably wrong on at least one architecture 117 | Size::U64 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/host.rs: -------------------------------------------------------------------------------- 1 | use crate::{Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor}; 2 | 3 | // Include the implementations of the `HOST` object containing information 4 | // about the current host. 5 | include!(concat!(env!("OUT_DIR"), "/host.rs")); 6 | 7 | #[cfg(test)] 8 | mod tests { 9 | #[cfg(target_os = "aix")] 10 | #[test] 11 | fn test_aix() { 12 | use super::*; 13 | assert_eq!(OperatingSystem::host(), OperatingSystem::Aix); 14 | } 15 | 16 | #[cfg(target_os = "linux")] 17 | #[test] 18 | fn test_linux() { 19 | use super::*; 20 | assert_eq!(OperatingSystem::host(), OperatingSystem::Linux); 21 | } 22 | 23 | #[cfg(target_os = "macos")] 24 | #[test] 25 | fn test_macos() { 26 | use super::*; 27 | assert_eq!(OperatingSystem::host(), OperatingSystem::Darwin(None)); 28 | } 29 | 30 | #[cfg(windows)] 31 | #[test] 32 | fn test_windows() { 33 | use super::*; 34 | assert_eq!(OperatingSystem::host(), OperatingSystem::Windows); 35 | } 36 | 37 | #[cfg(target_pointer_width = "16")] 38 | #[test] 39 | fn test_ptr16() { 40 | use super::*; 41 | assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 16); 42 | } 43 | 44 | #[cfg(target_pointer_width = "32")] 45 | #[test] 46 | fn test_ptr32() { 47 | use super::*; 48 | assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 32); 49 | } 50 | 51 | #[cfg(target_pointer_width = "64")] 52 | #[test] 53 | fn test_ptr64() { 54 | use super::*; 55 | assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 64); 56 | } 57 | 58 | #[test] 59 | fn host_object() { 60 | use super::*; 61 | assert_eq!(HOST, Triple::host()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! LLVM target triple types. 2 | 3 | #![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] 4 | #![warn(unused_import_braces)] 5 | #![cfg_attr( 6 | feature = "cargo-clippy", 7 | warn( 8 | clippy::float_arithmetic, 9 | clippy::mut_mut, 10 | clippy::nonminimal_bool, 11 | clippy::option_map_unwrap_or, 12 | clippy::option_map_unwrap_or_else, 13 | clippy::print_stdout, 14 | clippy::unicode_not_nfc, 15 | clippy::use_self, 16 | ) 17 | )] 18 | #![cfg_attr(not(feature = "std"), no_std)] 19 | 20 | #[cfg(not(feature = "std"))] 21 | extern crate alloc; 22 | #[cfg(feature = "std")] 23 | extern crate std as alloc; 24 | 25 | mod data_model; 26 | mod host; 27 | mod parse_error; 28 | mod targets; 29 | #[macro_use] 30 | mod triple; 31 | 32 | pub use self::data_model::{CDataModel, Size}; 33 | pub use self::host::HOST; 34 | pub use self::parse_error::ParseError; 35 | pub use self::targets::{ 36 | Aarch64Architecture, Architecture, ArmArchitecture, BinaryFormat, CleverArchitecture, 37 | CustomVendor, DeploymentTarget, Environment, Mips32Architecture, Mips64Architecture, 38 | OperatingSystem, Riscv32Architecture, Riscv64Architecture, Vendor, X86_32Architecture, 39 | }; 40 | pub use self::triple::{CallingConvention, Endianness, PointerWidth, Triple}; 41 | 42 | /// A simple wrapper around `Triple` that provides an implementation of 43 | /// `Default` which defaults to `Triple::host()`. 44 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] 45 | pub struct DefaultToHost(pub Triple); 46 | 47 | impl Default for DefaultToHost { 48 | fn default() -> Self { 49 | Self(Triple::host()) 50 | } 51 | } 52 | 53 | /// A simple wrapper around `Triple` that provides an implementation of 54 | /// `Default` which defaults to `Triple::unknown()`. 55 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] 56 | pub struct DefaultToUnknown(pub Triple); 57 | 58 | impl Default for DefaultToUnknown { 59 | fn default() -> Self { 60 | Self(Triple::unknown()) 61 | } 62 | } 63 | 64 | // For some reason, the below `serde` impls don't work when they're in the 65 | // `triple` module. 66 | 67 | #[cfg(feature = "serde_support")] 68 | impl serde::Serialize for Triple { 69 | fn serialize(&self, serializer: S) -> Result { 70 | serializer.serialize_str(&self.to_string()) 71 | } 72 | } 73 | 74 | #[cfg(feature = "serde_support")] 75 | impl<'de> serde::de::Deserialize<'de> for Triple { 76 | fn deserialize>(deserializer: D) -> Result { 77 | let s = String::deserialize(deserializer)?; 78 | s.parse().map_err(serde::de::Error::custom) 79 | } 80 | } 81 | 82 | #[cfg(feature = "serde_support")] 83 | #[test] 84 | fn test_serialize() { 85 | let triples: Vec = vec![ 86 | "x86_64-unknown-linux-gnu".parse().unwrap(), 87 | "i686-pc-windows-gnu".parse().unwrap(), 88 | ]; 89 | 90 | let json = serde_json::to_string(&triples).unwrap(); 91 | assert_eq!( 92 | json, 93 | r#"["x86_64-unknown-linux-gnu","i686-pc-windows-gnu"]"# 94 | ); 95 | } 96 | 97 | #[cfg(feature = "serde_support")] 98 | #[test] 99 | fn test_deserialize() { 100 | let triples: Vec = vec![ 101 | "x86_64-unknown-linux-gnu".parse().unwrap(), 102 | "i686-pc-windows-gnu".parse().unwrap(), 103 | ]; 104 | 105 | let vals: Vec = 106 | serde_json::from_str(r#"["x86_64-unknown-linux-gnu","i686-pc-windows-gnu"]"#).unwrap(); 107 | 108 | assert_eq!(vals, triples); 109 | } 110 | -------------------------------------------------------------------------------- /src/parse_error.rs: -------------------------------------------------------------------------------- 1 | use alloc::string::String; 2 | 3 | use core::fmt; 4 | 5 | /// An error returned from parsing a triple. 6 | #[derive(Clone, Debug, PartialEq, Eq)] 7 | #[allow(missing_docs)] 8 | pub enum ParseError { 9 | UnrecognizedArchitecture(String), 10 | UnrecognizedVendor(String), 11 | UnrecognizedOperatingSystem(String), 12 | UnrecognizedEnvironment(String), 13 | UnrecognizedBinaryFormat(String), 14 | UnrecognizedField(String), 15 | } 16 | 17 | impl fmt::Display for ParseError { 18 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 19 | use ParseError::*; 20 | match self { 21 | UnrecognizedArchitecture(msg) => write!(fmt, "Unrecognized architecture: {}", msg), 22 | UnrecognizedVendor(msg) => write!(fmt, "Unrecognized vendor: {}", msg), 23 | UnrecognizedOperatingSystem(msg) => { 24 | write!(fmt, "Unrecognized operating system: {}", msg) 25 | } 26 | UnrecognizedEnvironment(msg) => write!(fmt, "Unrecognized environment: {}", msg), 27 | UnrecognizedBinaryFormat(msg) => write!(fmt, "Unrecognized binary format: {}", msg), 28 | UnrecognizedField(msg) => write!(fmt, "Unrecognized field: {}", msg), 29 | } 30 | } 31 | } 32 | 33 | #[cfg(feature = "std")] 34 | impl std::error::Error for ParseError {} 35 | -------------------------------------------------------------------------------- /src/targets.rs: -------------------------------------------------------------------------------- 1 | // This file defines all the identifier enums and target-aware logic. 2 | 3 | use crate::triple::{Endianness, PointerWidth, Triple}; 4 | use alloc::borrow::Cow; 5 | use alloc::boxed::Box; 6 | use alloc::format; 7 | use alloc::string::String; 8 | use core::fmt; 9 | use core::hash::{Hash, Hasher}; 10 | use core::str::FromStr; 11 | 12 | /// The "architecture" field, which in some cases also specifies a specific 13 | /// subarchitecture. 14 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 15 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 16 | #[allow(missing_docs)] 17 | pub enum Architecture { 18 | Unknown, 19 | Arm(ArmArchitecture), 20 | AmdGcn, 21 | Aarch64(Aarch64Architecture), 22 | Asmjs, 23 | Avr, 24 | Bpfeb, 25 | Bpfel, 26 | Hexagon, 27 | X86_32(X86_32Architecture), 28 | M68k, 29 | LoongArch64, 30 | Mips32(Mips32Architecture), 31 | Mips64(Mips64Architecture), 32 | Msp430, 33 | Nvptx64, 34 | Pulley32, 35 | Pulley64, 36 | Pulley32be, 37 | Pulley64be, 38 | Powerpc, 39 | Powerpc64, 40 | Powerpc64le, 41 | Riscv32(Riscv32Architecture), 42 | Riscv64(Riscv64Architecture), 43 | S390x, 44 | Sparc, 45 | Sparc64, 46 | Sparcv9, 47 | Wasm32, 48 | Wasm64, 49 | X86_64, 50 | /// x86_64 target that only supports Haswell-compatible Intel chips. 51 | X86_64h, 52 | XTensa, 53 | Clever(CleverArchitecture), 54 | /// A software machine that produces zero-knowledge proofs of the execution. 55 | /// 56 | /// See https://wiki.polygon.technology/docs/category/zk-assembly/ 57 | #[cfg(feature = "arch_zkasm")] 58 | ZkAsm, 59 | } 60 | 61 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 62 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 63 | #[allow(missing_docs)] 64 | pub enum ArmArchitecture { 65 | Arm, // Generic arm 66 | Armeb, 67 | Armv4, 68 | Armv4t, 69 | Armv5t, 70 | Armv5te, 71 | Armv5tej, 72 | Armv6, 73 | Armv6j, 74 | Armv6k, 75 | Armv6z, 76 | Armv6kz, 77 | Armv6t2, 78 | Armv6m, 79 | Armv7, 80 | Armv7a, 81 | Armv7k, 82 | Armv7ve, 83 | Armv7m, 84 | Armv7r, 85 | Armv7s, 86 | Armv8, 87 | Armv8a, 88 | Armv8_1a, 89 | Armv8_2a, 90 | Armv8_3a, 91 | Armv8_4a, 92 | Armv8_5a, 93 | Armv8mBase, 94 | Armv8mMain, 95 | Armv8r, 96 | 97 | Armebv7r, 98 | 99 | Thumbeb, 100 | Thumbv4t, 101 | Thumbv5te, 102 | Thumbv6m, 103 | Thumbv7a, 104 | Thumbv7em, 105 | Thumbv7m, 106 | Thumbv7neon, 107 | Thumbv8mBase, 108 | Thumbv8mMain, 109 | } 110 | 111 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 112 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 113 | #[allow(missing_docs)] 114 | pub enum Aarch64Architecture { 115 | Aarch64, 116 | Aarch64be, 117 | } 118 | 119 | // #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 120 | // #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 121 | // #[allow(missing_docs)] 122 | // pub enum ArmFpu { 123 | // Vfp, 124 | // Vfpv2, 125 | // Vfpv3, 126 | // Vfpv3Fp16, 127 | // Vfpv3Xd, 128 | // Vfpv3XdFp16, 129 | // Neon, 130 | // NeonVfpv3, 131 | // NeonVfpv4, 132 | // Vfpv4, 133 | // Vfpv4D16, 134 | // Fpv4SpD16, 135 | // Fpv5SpD16, 136 | // Fpv5D16, 137 | // FpArmv8, 138 | // NeonFpArmv8, 139 | // CryptoNeonFpArmv8, 140 | // } 141 | 142 | impl ArmArchitecture { 143 | /// Test if this architecture uses the Thumb instruction set. 144 | #[rustfmt::skip] 145 | pub fn is_thumb(self) -> bool { 146 | use ArmArchitecture::*; 147 | 148 | match self { 149 | Arm 150 | | Armeb 151 | | Armv4 152 | | Armv4t 153 | | Armv5t 154 | | Armv5te 155 | | Armv5tej 156 | | Armv6 157 | | Armv6j 158 | | Armv6k 159 | | Armv6z 160 | | Armv6kz 161 | | Armv6t2 162 | | Armv6m 163 | | Armv7 164 | | Armv7a 165 | | Armv7k 166 | | Armv7ve 167 | | Armv7m 168 | | Armv7r 169 | | Armv7s 170 | | Armv8 171 | | Armv8a 172 | | Armv8_1a 173 | | Armv8_2a 174 | | Armv8_3a 175 | | Armv8_4a 176 | | Armv8_5a 177 | | Armv8mBase 178 | | Armv8mMain 179 | | Armv8r 180 | | Armebv7r => false, 181 | Thumbeb 182 | | Thumbv4t 183 | | Thumbv5te 184 | | Thumbv6m 185 | | Thumbv7a 186 | | Thumbv7em 187 | | Thumbv7m 188 | | Thumbv7neon 189 | | Thumbv8mBase 190 | | Thumbv8mMain => true, 191 | } 192 | } 193 | 194 | // pub fn has_fpu(self) -> Result<&'static [ArmFpu], ()> { 195 | 196 | // } 197 | 198 | /// Return the pointer bit width of this target's architecture. 199 | #[rustfmt::skip] 200 | pub fn pointer_width(self) -> PointerWidth { 201 | use ArmArchitecture::*; 202 | 203 | match self { 204 | Arm 205 | | Armeb 206 | | Armv4 207 | | Armv4t 208 | | Armv5t 209 | | Armv5te 210 | | Armv5tej 211 | | Armv6 212 | | Armv6j 213 | | Armv6k 214 | | Armv6z 215 | | Armv6kz 216 | | Armv6t2 217 | | Armv6m 218 | | Armv7 219 | | Armv7a 220 | | Armv7k 221 | | Armv7ve 222 | | Armv7m 223 | | Armv7r 224 | | Armv7s 225 | | Armv8 226 | | Armv8a 227 | | Armv8_1a 228 | | Armv8_2a 229 | | Armv8_3a 230 | | Armv8_4a 231 | | Armv8_5a 232 | | Armv8mBase 233 | | Armv8mMain 234 | | Armv8r 235 | | Armebv7r 236 | | Thumbeb 237 | | Thumbv4t 238 | | Thumbv5te 239 | | Thumbv6m 240 | | Thumbv7a 241 | | Thumbv7em 242 | | Thumbv7m 243 | | Thumbv7neon 244 | | Thumbv8mBase 245 | | Thumbv8mMain => PointerWidth::U32, 246 | } 247 | } 248 | 249 | /// Return the endianness of this architecture. 250 | #[rustfmt::skip] 251 | pub fn endianness(self) -> Endianness { 252 | use ArmArchitecture::*; 253 | 254 | match self { 255 | Arm 256 | | Armv4 257 | | Armv4t 258 | | Armv5t 259 | | Armv5te 260 | | Armv5tej 261 | | Armv6 262 | | Armv6j 263 | | Armv6k 264 | | Armv6z 265 | | Armv6kz 266 | | Armv6t2 267 | | Armv6m 268 | | Armv7 269 | | Armv7a 270 | | Armv7k 271 | | Armv7ve 272 | | Armv7m 273 | | Armv7r 274 | | Armv7s 275 | | Armv8 276 | | Armv8a 277 | | Armv8_1a 278 | | Armv8_2a 279 | | Armv8_3a 280 | | Armv8_4a 281 | | Armv8_5a 282 | | Armv8mBase 283 | | Armv8mMain 284 | | Armv8r 285 | | Thumbv4t 286 | | Thumbv5te 287 | | Thumbv6m 288 | | Thumbv7a 289 | | Thumbv7em 290 | | Thumbv7m 291 | | Thumbv7neon 292 | | Thumbv8mBase 293 | | Thumbv8mMain => Endianness::Little, 294 | Armeb | Armebv7r | Thumbeb => Endianness::Big, 295 | } 296 | } 297 | 298 | /// Convert into a string 299 | pub fn into_str(self) -> Cow<'static, str> { 300 | use ArmArchitecture::*; 301 | 302 | match self { 303 | Arm => Cow::Borrowed("arm"), 304 | Armeb => Cow::Borrowed("armeb"), 305 | Armv4 => Cow::Borrowed("armv4"), 306 | Armv4t => Cow::Borrowed("armv4t"), 307 | Armv5t => Cow::Borrowed("armv5t"), 308 | Armv5te => Cow::Borrowed("armv5te"), 309 | Armv5tej => Cow::Borrowed("armv5tej"), 310 | Armv6 => Cow::Borrowed("armv6"), 311 | Armv6j => Cow::Borrowed("armv6j"), 312 | Armv6k => Cow::Borrowed("armv6k"), 313 | Armv6z => Cow::Borrowed("armv6z"), 314 | Armv6kz => Cow::Borrowed("armv6kz"), 315 | Armv6t2 => Cow::Borrowed("armv6t2"), 316 | Armv6m => Cow::Borrowed("armv6m"), 317 | Armv7 => Cow::Borrowed("armv7"), 318 | Armv7a => Cow::Borrowed("armv7a"), 319 | Armv7k => Cow::Borrowed("armv7k"), 320 | Armv7ve => Cow::Borrowed("armv7ve"), 321 | Armv7m => Cow::Borrowed("armv7m"), 322 | Armv7r => Cow::Borrowed("armv7r"), 323 | Armv7s => Cow::Borrowed("armv7s"), 324 | Armv8 => Cow::Borrowed("armv8"), 325 | Armv8a => Cow::Borrowed("armv8a"), 326 | Armv8_1a => Cow::Borrowed("armv8.1a"), 327 | Armv8_2a => Cow::Borrowed("armv8.2a"), 328 | Armv8_3a => Cow::Borrowed("armv8.3a"), 329 | Armv8_4a => Cow::Borrowed("armv8.4a"), 330 | Armv8_5a => Cow::Borrowed("armv8.5a"), 331 | Armv8mBase => Cow::Borrowed("armv8m.base"), 332 | Armv8mMain => Cow::Borrowed("armv8m.main"), 333 | Armv8r => Cow::Borrowed("armv8r"), 334 | Thumbeb => Cow::Borrowed("thumbeb"), 335 | Thumbv4t => Cow::Borrowed("thumbv4t"), 336 | Thumbv5te => Cow::Borrowed("thumbv5te"), 337 | Thumbv6m => Cow::Borrowed("thumbv6m"), 338 | Thumbv7a => Cow::Borrowed("thumbv7a"), 339 | Thumbv7em => Cow::Borrowed("thumbv7em"), 340 | Thumbv7m => Cow::Borrowed("thumbv7m"), 341 | Thumbv7neon => Cow::Borrowed("thumbv7neon"), 342 | Thumbv8mBase => Cow::Borrowed("thumbv8m.base"), 343 | Thumbv8mMain => Cow::Borrowed("thumbv8m.main"), 344 | Armebv7r => Cow::Borrowed("armebv7r"), 345 | } 346 | } 347 | } 348 | 349 | impl Aarch64Architecture { 350 | /// Test if this architecture uses the Thumb instruction set. 351 | pub fn is_thumb(self) -> bool { 352 | match self { 353 | Aarch64Architecture::Aarch64 | Aarch64Architecture::Aarch64be => false, 354 | } 355 | } 356 | 357 | // pub fn has_fpu(self) -> Result<&'static [ArmFpu], ()> { 358 | 359 | // } 360 | 361 | /// Return the pointer bit width of this target's architecture. 362 | /// 363 | /// This function is only aware of the CPU architecture so it is not aware 364 | /// of ilp32 ABIs. 365 | pub fn pointer_width(self) -> PointerWidth { 366 | match self { 367 | Aarch64Architecture::Aarch64 | Aarch64Architecture::Aarch64be => PointerWidth::U64, 368 | } 369 | } 370 | 371 | /// Return the endianness of this architecture. 372 | pub fn endianness(self) -> Endianness { 373 | match self { 374 | Aarch64Architecture::Aarch64 => Endianness::Little, 375 | Aarch64Architecture::Aarch64be => Endianness::Big, 376 | } 377 | } 378 | 379 | /// Convert into a string 380 | pub fn into_str(self) -> Cow<'static, str> { 381 | use Aarch64Architecture::*; 382 | 383 | match self { 384 | Aarch64 => Cow::Borrowed("aarch64"), 385 | Aarch64be => Cow::Borrowed("aarch64_be"), 386 | } 387 | } 388 | } 389 | 390 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 391 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 392 | #[allow(missing_docs)] 393 | pub enum CleverArchitecture { 394 | Clever, 395 | Clever1_0, 396 | } 397 | 398 | impl CleverArchitecture { 399 | /// Convert into a string 400 | pub fn into_str(self) -> Cow<'static, str> { 401 | use CleverArchitecture::*; 402 | 403 | match self { 404 | Clever => Cow::Borrowed("clever"), 405 | Clever1_0 => Cow::Borrowed("clever1.0"), 406 | } 407 | } 408 | } 409 | 410 | /// An enum for all 32-bit RISC-V architectures. 411 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 412 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 413 | #[allow(missing_docs)] 414 | pub enum Riscv32Architecture { 415 | Riscv32, 416 | Riscv32gc, 417 | Riscv32i, 418 | Riscv32im, 419 | Riscv32ima, 420 | Riscv32imac, 421 | Riscv32imafc, 422 | Riscv32imc, 423 | } 424 | 425 | impl Riscv32Architecture { 426 | /// Convert into a string 427 | pub fn into_str(self) -> Cow<'static, str> { 428 | use Riscv32Architecture::*; 429 | 430 | match self { 431 | Riscv32 => Cow::Borrowed("riscv32"), 432 | Riscv32gc => Cow::Borrowed("riscv32gc"), 433 | Riscv32i => Cow::Borrowed("riscv32i"), 434 | Riscv32im => Cow::Borrowed("riscv32im"), 435 | Riscv32ima => Cow::Borrowed("riscv32ima"), 436 | Riscv32imac => Cow::Borrowed("riscv32imac"), 437 | Riscv32imafc => Cow::Borrowed("riscv32imafc"), 438 | Riscv32imc => Cow::Borrowed("riscv32imc"), 439 | } 440 | } 441 | } 442 | 443 | /// An enum for all 64-bit RISC-V architectures. 444 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 445 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 446 | #[allow(missing_docs)] 447 | pub enum Riscv64Architecture { 448 | Riscv64, 449 | Riscv64gc, 450 | Riscv64imac, 451 | } 452 | 453 | impl Riscv64Architecture { 454 | /// Convert into a string 455 | pub fn into_str(self) -> Cow<'static, str> { 456 | use Riscv64Architecture::*; 457 | 458 | match self { 459 | Riscv64 => Cow::Borrowed("riscv64"), 460 | Riscv64gc => Cow::Borrowed("riscv64gc"), 461 | Riscv64imac => Cow::Borrowed("riscv64imac"), 462 | } 463 | } 464 | } 465 | 466 | /// An enum for all 32-bit x86 architectures. 467 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 468 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 469 | #[allow(missing_docs)] 470 | pub enum X86_32Architecture { 471 | I386, 472 | I586, 473 | I686, 474 | } 475 | 476 | impl X86_32Architecture { 477 | /// Convert into a string 478 | pub fn into_str(self) -> Cow<'static, str> { 479 | use X86_32Architecture::*; 480 | 481 | match self { 482 | I386 => Cow::Borrowed("i386"), 483 | I586 => Cow::Borrowed("i586"), 484 | I686 => Cow::Borrowed("i686"), 485 | } 486 | } 487 | } 488 | 489 | /// An enum for all 32-bit MIPS architectures (not just "MIPS32"). 490 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 491 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 492 | #[allow(missing_docs)] 493 | pub enum Mips32Architecture { 494 | Mips, 495 | Mipsel, 496 | Mipsisa32r6, 497 | Mipsisa32r6el, 498 | } 499 | 500 | impl Mips32Architecture { 501 | /// Convert into a string 502 | pub fn into_str(self) -> Cow<'static, str> { 503 | use Mips32Architecture::*; 504 | 505 | match self { 506 | Mips => Cow::Borrowed("mips"), 507 | Mipsel => Cow::Borrowed("mipsel"), 508 | Mipsisa32r6 => Cow::Borrowed("mipsisa32r6"), 509 | Mipsisa32r6el => Cow::Borrowed("mipsisa32r6el"), 510 | } 511 | } 512 | } 513 | 514 | /// An enum for all 64-bit MIPS architectures (not just "MIPS64"). 515 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 516 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 517 | #[allow(missing_docs)] 518 | pub enum Mips64Architecture { 519 | Mips64, 520 | Mips64el, 521 | Mipsisa64r6, 522 | Mipsisa64r6el, 523 | } 524 | 525 | impl Mips64Architecture { 526 | /// Convert into a string 527 | pub fn into_str(self) -> Cow<'static, str> { 528 | use Mips64Architecture::*; 529 | 530 | match self { 531 | Mips64 => Cow::Borrowed("mips64"), 532 | Mips64el => Cow::Borrowed("mips64el"), 533 | Mipsisa64r6 => Cow::Borrowed("mipsisa64r6"), 534 | Mipsisa64r6el => Cow::Borrowed("mipsisa64r6el"), 535 | } 536 | } 537 | } 538 | 539 | /// A string for a `Vendor::Custom` that can either be used in `const` 540 | /// contexts or hold dynamic strings. 541 | #[derive(Clone, Debug, Eq)] 542 | pub enum CustomVendor { 543 | /// An owned `String`. This supports the general case. 544 | Owned(Box), 545 | /// A static `str`, so that `CustomVendor` can be constructed in `const` 546 | /// contexts. 547 | Static(&'static str), 548 | } 549 | 550 | impl CustomVendor { 551 | /// Extracts a string slice. 552 | pub fn as_str(&self) -> &str { 553 | match self { 554 | CustomVendor::Owned(s) => s, 555 | CustomVendor::Static(s) => s, 556 | } 557 | } 558 | } 559 | 560 | impl PartialEq for CustomVendor { 561 | fn eq(&self, other: &Self) -> bool { 562 | self.as_str() == other.as_str() 563 | } 564 | } 565 | 566 | impl Hash for CustomVendor { 567 | fn hash(&self, state: &mut H) { 568 | self.as_str().hash(state) 569 | } 570 | } 571 | 572 | /// The "vendor" field, which in practice is little more than an arbitrary 573 | /// modifier. 574 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 575 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] 576 | #[allow(missing_docs)] 577 | pub enum Vendor { 578 | Unknown, 579 | Amd, 580 | Apple, 581 | Espressif, 582 | Experimental, 583 | Fortanix, 584 | Ibm, 585 | Kmc, 586 | Nintendo, 587 | Nvidia, 588 | Pc, 589 | Rumprun, 590 | Sun, 591 | Uwp, 592 | Wrs, 593 | 594 | /// A custom vendor. "Custom" in this context means that the vendor is 595 | /// not specifically recognized by upstream Autotools, LLVM, Rust, or other 596 | /// relevant authorities on triple naming. It's useful for people building 597 | /// and using locally patched toolchains. 598 | /// 599 | /// Outside of such patched environments, users of `target-lexicon` should 600 | /// treat `Custom` the same as `Unknown` and ignore the string. 601 | Custom(CustomVendor), 602 | } 603 | 604 | impl Vendor { 605 | /// Extracts a string slice. 606 | pub fn as_str(&self) -> &str { 607 | use Vendor::*; 608 | 609 | match self { 610 | Unknown => "unknown", 611 | Amd => "amd", 612 | Apple => "apple", 613 | Espressif => "espressif", 614 | Experimental => "experimental", 615 | Fortanix => "fortanix", 616 | Ibm => "ibm", 617 | Kmc => "kmc", 618 | Nintendo => "nintendo", 619 | Nvidia => "nvidia", 620 | Pc => "pc", 621 | Rumprun => "rumprun", 622 | Sun => "sun", 623 | Uwp => "uwp", 624 | Wrs => "wrs", 625 | Custom(name) => name.as_str(), 626 | } 627 | } 628 | } 629 | 630 | /// The minimum OS version that we're compiling for. 631 | /// 632 | /// This is formatted as `"major.minor.patch"`. 633 | /// 634 | /// The size of the parts here are limited by Mach-O's `LC_BUILD_VERSION`. 635 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 636 | #[allow(missing_docs)] 637 | pub struct DeploymentTarget { 638 | pub major: u16, 639 | pub minor: u8, 640 | pub patch: u8, 641 | } 642 | 643 | /// The "operating system" field, which sometimes implies an environment, and 644 | /// sometimes isn't an actual operating system. 645 | /// 646 | /// LLVM's Apple triples may optionally include the [deployment target]. 647 | /// 648 | /// [deployment target]: DeploymentTarget 649 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 650 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 651 | #[allow(missing_docs)] 652 | pub enum OperatingSystem { 653 | Unknown, 654 | Aix, 655 | AmdHsa, 656 | Bitrig, 657 | Cloudabi, 658 | Cuda, 659 | /// The general [Darwin][darwin-wiki] core OS. 660 | /// 661 | /// Generally, `-mmacosx-version-min=...` or similar flags are required by 662 | /// Clang to determine the actual OS (either macOS, iOS, tvOS, watchOS or 663 | /// visionOS). 664 | /// 665 | /// WARNING: When parsing `rustc` target triples, this matches the macOS 666 | /// target triples as well. 667 | /// 668 | /// [darwin-wiki]: https://en.wikipedia.org/wiki/Darwin_(operating_system) 669 | Darwin(Option), 670 | Dragonfly, 671 | Emscripten, 672 | Espidf, 673 | Freebsd, 674 | Fuchsia, 675 | Haiku, 676 | Hermit, 677 | Horizon, 678 | Hurd, 679 | Illumos, 680 | IOS(Option), 681 | L4re, 682 | Linux, 683 | /// macOS. 684 | /// 685 | /// WARNING: This does _not_ match the macOS triples when parsing `rustc` 686 | /// target triples, for that see the [`darwin`](Self::Darwin) OS name. 687 | MacOSX(Option), 688 | Nebulet, 689 | Netbsd, 690 | None_, 691 | Openbsd, 692 | Psp, 693 | Redox, 694 | Solaris, 695 | SolidAsp3, 696 | TvOS(Option), 697 | Uefi, 698 | VisionOS(Option), 699 | VxWorks, 700 | Wasi, 701 | WasiP1, 702 | WasiP2, 703 | WatchOS(Option), 704 | Windows, 705 | /// An alternate name for [visionOS][Self::VisionOS]. 706 | XROS(Option), 707 | } 708 | 709 | impl OperatingSystem { 710 | /// Convert into a string 711 | pub fn into_str(self) -> Cow<'static, str> { 712 | use OperatingSystem::*; 713 | 714 | let darwin_version = |name, deployment_target| { 715 | if let Some(DeploymentTarget { 716 | major, 717 | minor, 718 | patch, 719 | }) = deployment_target 720 | { 721 | Cow::Owned(format!("{}{}.{}.{}", name, major, minor, patch)) 722 | } else { 723 | Cow::Borrowed(name) 724 | } 725 | }; 726 | 727 | match self { 728 | Unknown => Cow::Borrowed("unknown"), 729 | Aix => Cow::Borrowed("aix"), 730 | AmdHsa => Cow::Borrowed("amdhsa"), 731 | Bitrig => Cow::Borrowed("bitrig"), 732 | Cloudabi => Cow::Borrowed("cloudabi"), 733 | Cuda => Cow::Borrowed("cuda"), 734 | Darwin(deployment_target) => darwin_version("darwin", deployment_target), 735 | Dragonfly => Cow::Borrowed("dragonfly"), 736 | Emscripten => Cow::Borrowed("emscripten"), 737 | Espidf => Cow::Borrowed("espidf"), 738 | Freebsd => Cow::Borrowed("freebsd"), 739 | Fuchsia => Cow::Borrowed("fuchsia"), 740 | Haiku => Cow::Borrowed("haiku"), 741 | Hermit => Cow::Borrowed("hermit"), 742 | Horizon => Cow::Borrowed("horizon"), 743 | Hurd => Cow::Borrowed("hurd"), 744 | Illumos => Cow::Borrowed("illumos"), 745 | IOS(deployment_target) => darwin_version("ios", deployment_target), 746 | L4re => Cow::Borrowed("l4re"), 747 | Linux => Cow::Borrowed("linux"), 748 | MacOSX(deployment_target) => darwin_version("macosx", deployment_target), 749 | Nebulet => Cow::Borrowed("nebulet"), 750 | Netbsd => Cow::Borrowed("netbsd"), 751 | None_ => Cow::Borrowed("none"), 752 | Openbsd => Cow::Borrowed("openbsd"), 753 | Psp => Cow::Borrowed("psp"), 754 | Redox => Cow::Borrowed("redox"), 755 | Solaris => Cow::Borrowed("solaris"), 756 | SolidAsp3 => Cow::Borrowed("solid_asp3"), 757 | TvOS(deployment_target) => darwin_version("tvos", deployment_target), 758 | Uefi => Cow::Borrowed("uefi"), 759 | VxWorks => Cow::Borrowed("vxworks"), 760 | VisionOS(deployment_target) => darwin_version("visionos", deployment_target), 761 | Wasi => Cow::Borrowed("wasi"), 762 | WasiP1 => Cow::Borrowed("wasip1"), 763 | WasiP2 => Cow::Borrowed("wasip2"), 764 | WatchOS(deployment_target) => darwin_version("watchos", deployment_target), 765 | Windows => Cow::Borrowed("windows"), 766 | XROS(deployment_target) => darwin_version("xros", deployment_target), 767 | } 768 | } 769 | 770 | /// Whether the OS is similar to Darwin. 771 | /// 772 | /// This matches on any of: 773 | /// - [Darwin](Self::Darwin) 774 | /// - [iOS](Self::IOS) 775 | /// - [macOS](Self::MacOSX) 776 | /// - [tvOS](Self::TvOS) 777 | /// - [visionOS](Self::VisionOS) 778 | /// - [watchOS](Self::WatchOS) 779 | /// - [xrOS](Self::XROS) 780 | pub fn is_like_darwin(&self) -> bool { 781 | use OperatingSystem::*; 782 | 783 | match self { 784 | Darwin(_) | IOS(_) | MacOSX(_) | TvOS(_) | VisionOS(_) | WatchOS(_) | XROS(_) => true, 785 | _ => false, 786 | } 787 | } 788 | } 789 | 790 | /// The "environment" field, which specifies an ABI environment on top of the 791 | /// operating system. In many configurations, this field is omitted, and the 792 | /// environment is implied by the operating system. 793 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 794 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 795 | #[allow(missing_docs)] 796 | pub enum Environment { 797 | Unknown, 798 | AmdGiz, 799 | Android, 800 | Androideabi, 801 | Eabi, 802 | Eabihf, 803 | Gnu, 804 | Gnuabi64, 805 | Gnueabi, 806 | Gnueabihf, 807 | Gnuspe, 808 | Gnux32, 809 | GnuIlp32, 810 | GnuLlvm, 811 | HermitKernel, 812 | HurdKernel, 813 | LinuxKernel, 814 | Macabi, 815 | Musl, 816 | Musleabi, 817 | Musleabihf, 818 | Muslabi64, 819 | Msvc, 820 | Newlib, 821 | None, 822 | Kernel, 823 | Uclibc, 824 | Uclibceabi, 825 | Uclibceabihf, 826 | Sgx, 827 | Sim, 828 | Softfloat, 829 | Spe, 830 | Threads, 831 | Ohos, 832 | } 833 | 834 | impl Environment { 835 | /// Convert into a string 836 | pub fn into_str(self) -> Cow<'static, str> { 837 | use Environment::*; 838 | 839 | match self { 840 | Unknown => Cow::Borrowed("unknown"), 841 | AmdGiz => Cow::Borrowed("amdgiz"), 842 | Android => Cow::Borrowed("android"), 843 | Androideabi => Cow::Borrowed("androideabi"), 844 | Eabi => Cow::Borrowed("eabi"), 845 | Eabihf => Cow::Borrowed("eabihf"), 846 | Gnu => Cow::Borrowed("gnu"), 847 | Gnuabi64 => Cow::Borrowed("gnuabi64"), 848 | Gnueabi => Cow::Borrowed("gnueabi"), 849 | Gnueabihf => Cow::Borrowed("gnueabihf"), 850 | Gnuspe => Cow::Borrowed("gnuspe"), 851 | Gnux32 => Cow::Borrowed("gnux32"), 852 | GnuIlp32 => Cow::Borrowed("gnu_ilp32"), 853 | GnuLlvm => Cow::Borrowed("gnullvm"), 854 | HermitKernel => Cow::Borrowed("hermitkernel"), 855 | HurdKernel => Cow::Borrowed("hurdkernel"), 856 | LinuxKernel => Cow::Borrowed("linuxkernel"), 857 | Macabi => Cow::Borrowed("macabi"), 858 | Musl => Cow::Borrowed("musl"), 859 | Musleabi => Cow::Borrowed("musleabi"), 860 | Musleabihf => Cow::Borrowed("musleabihf"), 861 | Muslabi64 => Cow::Borrowed("muslabi64"), 862 | Msvc => Cow::Borrowed("msvc"), 863 | Newlib => Cow::Borrowed("newlib"), 864 | None => Cow::Borrowed("none"), 865 | Kernel => Cow::Borrowed("kernel"), 866 | Uclibc => Cow::Borrowed("uclibc"), 867 | Uclibceabi => Cow::Borrowed("uclibceabi"), 868 | Uclibceabihf => Cow::Borrowed("uclibceabihf"), 869 | Sgx => Cow::Borrowed("sgx"), 870 | Sim => Cow::Borrowed("sim"), 871 | Softfloat => Cow::Borrowed("softfloat"), 872 | Spe => Cow::Borrowed("spe"), 873 | Threads => Cow::Borrowed("threads"), 874 | Ohos => Cow::Borrowed("ohos"), 875 | } 876 | } 877 | } 878 | 879 | /// The "binary format" field, which is usually omitted, and the binary format 880 | /// is implied by the other fields. 881 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 882 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 883 | #[allow(missing_docs)] 884 | pub enum BinaryFormat { 885 | Unknown, 886 | Elf, 887 | Coff, 888 | Macho, 889 | Wasm, 890 | Xcoff, 891 | } 892 | 893 | impl BinaryFormat { 894 | /// Convert into a string 895 | pub fn into_str(self) -> Cow<'static, str> { 896 | use BinaryFormat::*; 897 | 898 | match self { 899 | Unknown => Cow::Borrowed("unknown"), 900 | Elf => Cow::Borrowed("elf"), 901 | Coff => Cow::Borrowed("coff"), 902 | Macho => Cow::Borrowed("macho"), 903 | Wasm => Cow::Borrowed("wasm"), 904 | Xcoff => Cow::Borrowed("xcoff"), 905 | } 906 | } 907 | } 908 | 909 | impl Architecture { 910 | /// Return the endianness of this architecture. 911 | #[rustfmt::skip] 912 | pub fn endianness(self) -> Result { 913 | use Architecture::*; 914 | 915 | match self { 916 | Unknown => Err(()), 917 | Arm(arm) => Ok(arm.endianness()), 918 | Aarch64(aarch) => Ok(aarch.endianness()), 919 | AmdGcn 920 | | Asmjs 921 | | Avr 922 | | Bpfel 923 | | Hexagon 924 | | X86_32(_) 925 | | LoongArch64 926 | | Mips64(Mips64Architecture::Mips64el) 927 | | Mips32(Mips32Architecture::Mipsel) 928 | | Mips32(Mips32Architecture::Mipsisa32r6el) 929 | | Mips64(Mips64Architecture::Mipsisa64r6el) 930 | | Msp430 931 | | Nvptx64 932 | | Pulley32 933 | | Pulley64 934 | | Powerpc64le 935 | | Riscv32(_) 936 | | Riscv64(_) 937 | | Wasm32 938 | | Wasm64 939 | | X86_64 940 | | X86_64h 941 | | XTensa 942 | | Clever(_) => Ok(Endianness::Little), 943 | Bpfeb 944 | | M68k 945 | | Mips32(Mips32Architecture::Mips) 946 | | Mips64(Mips64Architecture::Mips64) 947 | | Mips32(Mips32Architecture::Mipsisa32r6) 948 | | Mips64(Mips64Architecture::Mipsisa64r6) 949 | | Powerpc 950 | | Powerpc64 951 | | Pulley32be 952 | | Pulley64be 953 | | S390x 954 | | Sparc 955 | | Sparc64 956 | | Sparcv9 => Ok(Endianness::Big), 957 | #[cfg(feature="arch_zkasm")] 958 | ZkAsm => Ok(Endianness::Big), 959 | } 960 | } 961 | 962 | /// Return the pointer bit width of this target's architecture. 963 | /// 964 | /// This function is only aware of the CPU architecture so it is not aware 965 | /// of ilp32 and x32 ABIs. 966 | #[rustfmt::skip] 967 | pub fn pointer_width(self) -> Result { 968 | use Architecture::*; 969 | 970 | match self { 971 | Unknown => Err(()), 972 | Avr | Msp430 => Ok(PointerWidth::U16), 973 | Arm(arm) => Ok(arm.pointer_width()), 974 | Aarch64(aarch) => Ok(aarch.pointer_width()), 975 | Asmjs 976 | | Hexagon 977 | | X86_32(_) 978 | | Riscv32(_) 979 | | Sparc 980 | | Wasm32 981 | | M68k 982 | | Mips32(_) 983 | | Pulley32 984 | | Pulley32be 985 | | Powerpc 986 | | XTensa => Ok(PointerWidth::U32), 987 | AmdGcn 988 | | Bpfeb 989 | | Bpfel 990 | | Powerpc64le 991 | | Riscv64(_) 992 | | X86_64 993 | | X86_64h 994 | | Mips64(_) 995 | | Nvptx64 996 | | Pulley64 997 | | Pulley64be 998 | | Powerpc64 999 | | S390x 1000 | | Sparc64 1001 | | Sparcv9 1002 | | LoongArch64 1003 | | Wasm64 1004 | | Clever(_) => Ok(PointerWidth::U64), 1005 | #[cfg(feature="arch_zkasm")] 1006 | ZkAsm => Ok(PointerWidth::U64), 1007 | } 1008 | } 1009 | 1010 | /// Checks if this Architecture is some variant of Clever-ISA 1011 | pub fn is_clever(&self) -> bool { 1012 | match self { 1013 | Architecture::Clever(_) => true, 1014 | _ => false, 1015 | } 1016 | } 1017 | 1018 | /// Convert into a string 1019 | pub fn into_str(self) -> Cow<'static, str> { 1020 | use Architecture::*; 1021 | 1022 | match self { 1023 | Arm(arm) => arm.into_str(), 1024 | Aarch64(aarch) => aarch.into_str(), 1025 | Unknown => Cow::Borrowed("unknown"), 1026 | AmdGcn => Cow::Borrowed("amdgcn"), 1027 | Asmjs => Cow::Borrowed("asmjs"), 1028 | Avr => Cow::Borrowed("avr"), 1029 | Bpfeb => Cow::Borrowed("bpfeb"), 1030 | Bpfel => Cow::Borrowed("bpfel"), 1031 | Hexagon => Cow::Borrowed("hexagon"), 1032 | X86_32(x86_32) => x86_32.into_str(), 1033 | LoongArch64 => Cow::Borrowed("loongarch64"), 1034 | M68k => Cow::Borrowed("m68k"), 1035 | Mips32(mips32) => mips32.into_str(), 1036 | Mips64(mips64) => mips64.into_str(), 1037 | Msp430 => Cow::Borrowed("msp430"), 1038 | Nvptx64 => Cow::Borrowed("nvptx64"), 1039 | Pulley32 => Cow::Borrowed("pulley32"), 1040 | Pulley64 => Cow::Borrowed("pulley64"), 1041 | Pulley32be => Cow::Borrowed("pulley32be"), 1042 | Pulley64be => Cow::Borrowed("pulley64be"), 1043 | Powerpc => Cow::Borrowed("powerpc"), 1044 | Powerpc64 => Cow::Borrowed("powerpc64"), 1045 | Powerpc64le => Cow::Borrowed("powerpc64le"), 1046 | Riscv32(riscv32) => riscv32.into_str(), 1047 | Riscv64(riscv64) => riscv64.into_str(), 1048 | S390x => Cow::Borrowed("s390x"), 1049 | Sparc => Cow::Borrowed("sparc"), 1050 | Sparc64 => Cow::Borrowed("sparc64"), 1051 | Sparcv9 => Cow::Borrowed("sparcv9"), 1052 | Wasm32 => Cow::Borrowed("wasm32"), 1053 | Wasm64 => Cow::Borrowed("wasm64"), 1054 | X86_64 => Cow::Borrowed("x86_64"), 1055 | X86_64h => Cow::Borrowed("x86_64h"), 1056 | XTensa => Cow::Borrowed("xtensa"), 1057 | Clever(ver) => ver.into_str(), 1058 | #[cfg(feature = "arch_zkasm")] 1059 | ZkAsm => Cow::Borrowed("zkasm"), 1060 | } 1061 | } 1062 | } 1063 | 1064 | /// Return the binary format implied by this target triple, ignoring its 1065 | /// `binary_format` field. 1066 | pub(crate) fn default_binary_format(triple: &Triple) -> BinaryFormat { 1067 | match triple.operating_system { 1068 | OperatingSystem::None_ => match triple.environment { 1069 | Environment::Eabi | Environment::Eabihf => BinaryFormat::Elf, 1070 | _ => BinaryFormat::Unknown, 1071 | }, 1072 | OperatingSystem::Aix => BinaryFormat::Xcoff, 1073 | os if os.is_like_darwin() => BinaryFormat::Macho, 1074 | OperatingSystem::Windows => BinaryFormat::Coff, 1075 | OperatingSystem::Nebulet 1076 | | OperatingSystem::Emscripten 1077 | | OperatingSystem::VxWorks 1078 | | OperatingSystem::Wasi 1079 | | OperatingSystem::Unknown => match triple.architecture { 1080 | Architecture::Wasm32 | Architecture::Wasm64 => BinaryFormat::Wasm, 1081 | Architecture::Unknown => BinaryFormat::Unknown, 1082 | // Default to ELF, following `getDefaultFormat` in LLVM. 1083 | _ => BinaryFormat::Elf, 1084 | }, 1085 | _ => BinaryFormat::Elf, 1086 | } 1087 | } 1088 | 1089 | impl fmt::Display for ArmArchitecture { 1090 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1091 | f.write_str(&self.into_str()) 1092 | } 1093 | } 1094 | 1095 | impl fmt::Display for Aarch64Architecture { 1096 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1097 | f.write_str(&self.into_str()) 1098 | } 1099 | } 1100 | 1101 | impl fmt::Display for CleverArchitecture { 1102 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1103 | f.write_str(&self.into_str()) 1104 | } 1105 | } 1106 | 1107 | impl fmt::Display for Riscv32Architecture { 1108 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1109 | f.write_str(&self.into_str()) 1110 | } 1111 | } 1112 | 1113 | impl fmt::Display for Riscv64Architecture { 1114 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1115 | f.write_str(&self.into_str()) 1116 | } 1117 | } 1118 | 1119 | impl fmt::Display for X86_32Architecture { 1120 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1121 | f.write_str(&self.into_str()) 1122 | } 1123 | } 1124 | 1125 | impl fmt::Display for Mips32Architecture { 1126 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1127 | f.write_str(&self.into_str()) 1128 | } 1129 | } 1130 | 1131 | impl fmt::Display for Mips64Architecture { 1132 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1133 | f.write_str(&self.into_str()) 1134 | } 1135 | } 1136 | 1137 | impl fmt::Display for Architecture { 1138 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1139 | f.write_str(&self.into_str()) 1140 | } 1141 | } 1142 | 1143 | impl FromStr for ArmArchitecture { 1144 | type Err = (); 1145 | 1146 | fn from_str(s: &str) -> Result { 1147 | use ArmArchitecture::*; 1148 | 1149 | Ok(match s { 1150 | "arm" => Arm, 1151 | "armeb" => Armeb, 1152 | "armv4" => Armv4, 1153 | "armv4t" => Armv4t, 1154 | "armv5t" => Armv5t, 1155 | "armv5te" => Armv5te, 1156 | "armv5tej" => Armv5tej, 1157 | "armv6" => Armv6, 1158 | "armv6j" => Armv6j, 1159 | "armv6k" => Armv6k, 1160 | "armv6z" => Armv6z, 1161 | "armv6kz" => Armv6kz, 1162 | "armv6t2" => Armv6t2, 1163 | "armv6m" => Armv6m, 1164 | "armv7" => Armv7, 1165 | "armv7a" => Armv7a, 1166 | "armv7k" => Armv7k, 1167 | "armv7ve" => Armv7ve, 1168 | "armv7m" => Armv7m, 1169 | "armv7r" => Armv7r, 1170 | "armv7s" => Armv7s, 1171 | "armv8" => Armv8, 1172 | "armv8a" => Armv8a, 1173 | "armv8.1a" => Armv8_1a, 1174 | "armv8.2a" => Armv8_2a, 1175 | "armv8.3a" => Armv8_3a, 1176 | "armv8.4a" => Armv8_4a, 1177 | "armv8.5a" => Armv8_5a, 1178 | "armv8m.base" => Armv8mBase, 1179 | "armv8m.main" => Armv8mMain, 1180 | "armv8r" => Armv8r, 1181 | "thumbeb" => Thumbeb, 1182 | "thumbv4t" => Thumbv4t, 1183 | "thumbv5te" => Thumbv5te, 1184 | "thumbv6m" => Thumbv6m, 1185 | "thumbv7a" => Thumbv7a, 1186 | "thumbv7em" => Thumbv7em, 1187 | "thumbv7m" => Thumbv7m, 1188 | "thumbv7neon" => Thumbv7neon, 1189 | "thumbv8m.base" => Thumbv8mBase, 1190 | "thumbv8m.main" => Thumbv8mMain, 1191 | "armebv7r" => Armebv7r, 1192 | _ => return Err(()), 1193 | }) 1194 | } 1195 | } 1196 | 1197 | impl FromStr for Aarch64Architecture { 1198 | type Err = (); 1199 | 1200 | fn from_str(s: &str) -> Result { 1201 | use Aarch64Architecture::*; 1202 | 1203 | Ok(match s { 1204 | "aarch64" => Aarch64, 1205 | "arm64" => Aarch64, 1206 | "aarch64_be" => Aarch64be, 1207 | _ => return Err(()), 1208 | }) 1209 | } 1210 | } 1211 | 1212 | impl FromStr for CleverArchitecture { 1213 | type Err = (); 1214 | fn from_str(s: &str) -> Result { 1215 | match s { 1216 | "clever" => Ok(CleverArchitecture::Clever), 1217 | "clever1.0" => Ok(CleverArchitecture::Clever1_0), 1218 | _ => Err(()), 1219 | } 1220 | } 1221 | } 1222 | 1223 | impl FromStr for Riscv32Architecture { 1224 | type Err = (); 1225 | 1226 | fn from_str(s: &str) -> Result { 1227 | use Riscv32Architecture::*; 1228 | 1229 | Ok(match s { 1230 | "riscv32" => Riscv32, 1231 | "riscv32gc" => Riscv32gc, 1232 | "riscv32i" => Riscv32i, 1233 | "riscv32im" => Riscv32im, 1234 | "riscv32ima" => Riscv32ima, 1235 | "riscv32imac" => Riscv32imac, 1236 | "riscv32imafc" => Riscv32imafc, 1237 | "riscv32imc" => Riscv32imc, 1238 | _ => return Err(()), 1239 | }) 1240 | } 1241 | } 1242 | 1243 | impl FromStr for Riscv64Architecture { 1244 | type Err = (); 1245 | 1246 | fn from_str(s: &str) -> Result { 1247 | use Riscv64Architecture::*; 1248 | 1249 | Ok(match s { 1250 | "riscv64" => Riscv64, 1251 | "riscv64gc" => Riscv64gc, 1252 | "riscv64imac" => Riscv64imac, 1253 | _ => return Err(()), 1254 | }) 1255 | } 1256 | } 1257 | 1258 | impl FromStr for X86_32Architecture { 1259 | type Err = (); 1260 | 1261 | fn from_str(s: &str) -> Result { 1262 | use X86_32Architecture::*; 1263 | 1264 | Ok(match s { 1265 | "i386" => I386, 1266 | "i586" => I586, 1267 | "i686" => I686, 1268 | _ => return Err(()), 1269 | }) 1270 | } 1271 | } 1272 | 1273 | impl FromStr for Mips32Architecture { 1274 | type Err = (); 1275 | 1276 | fn from_str(s: &str) -> Result { 1277 | use Mips32Architecture::*; 1278 | 1279 | Ok(match s { 1280 | "mips" => Mips, 1281 | "mipsel" => Mipsel, 1282 | "mipsisa32r6" => Mipsisa32r6, 1283 | "mipsisa32r6el" => Mipsisa32r6el, 1284 | _ => return Err(()), 1285 | }) 1286 | } 1287 | } 1288 | 1289 | impl FromStr for Mips64Architecture { 1290 | type Err = (); 1291 | 1292 | fn from_str(s: &str) -> Result { 1293 | use Mips64Architecture::*; 1294 | 1295 | Ok(match s { 1296 | "mips64" => Mips64, 1297 | "mips64el" => Mips64el, 1298 | "mipsisa64r6" => Mipsisa64r6, 1299 | "mipsisa64r6el" => Mipsisa64r6el, 1300 | _ => return Err(()), 1301 | }) 1302 | } 1303 | } 1304 | 1305 | impl FromStr for Architecture { 1306 | type Err = (); 1307 | 1308 | fn from_str(s: &str) -> Result { 1309 | use Architecture::*; 1310 | 1311 | Ok(match s { 1312 | "unknown" => Unknown, 1313 | "amdgcn" => AmdGcn, 1314 | "asmjs" => Asmjs, 1315 | "avr" => Avr, 1316 | "bpfeb" => Bpfeb, 1317 | "bpfel" => Bpfel, 1318 | "hexagon" => Hexagon, 1319 | "loongarch64" => LoongArch64, 1320 | "m68k" => M68k, 1321 | "msp430" => Msp430, 1322 | "nvptx64" => Nvptx64, 1323 | "pulley32" => Pulley32, 1324 | "pulley64" => Pulley64, 1325 | "pulley32be" => Pulley32be, 1326 | "pulley64be" => Pulley64be, 1327 | "powerpc" => Powerpc, 1328 | "powerpc64" => Powerpc64, 1329 | "powerpc64le" => Powerpc64le, 1330 | "s390x" => S390x, 1331 | "sparc" => Sparc, 1332 | "sparc64" => Sparc64, 1333 | "sparcv9" => Sparcv9, 1334 | "wasm32" => Wasm32, 1335 | "wasm64" => Wasm64, 1336 | "x86_64" => X86_64, 1337 | "x86_64h" => X86_64h, 1338 | "xtensa" => XTensa, 1339 | #[cfg(feature = "arch_zkasm")] 1340 | "zkasm" => ZkAsm, 1341 | _ => { 1342 | if let Ok(arm) = ArmArchitecture::from_str(s) { 1343 | Arm(arm) 1344 | } else if let Ok(aarch64) = Aarch64Architecture::from_str(s) { 1345 | Aarch64(aarch64) 1346 | } else if let Ok(riscv32) = Riscv32Architecture::from_str(s) { 1347 | Riscv32(riscv32) 1348 | } else if let Ok(riscv64) = Riscv64Architecture::from_str(s) { 1349 | Riscv64(riscv64) 1350 | } else if let Ok(x86_32) = X86_32Architecture::from_str(s) { 1351 | X86_32(x86_32) 1352 | } else if let Ok(mips32) = Mips32Architecture::from_str(s) { 1353 | Mips32(mips32) 1354 | } else if let Ok(mips64) = Mips64Architecture::from_str(s) { 1355 | Mips64(mips64) 1356 | } else if let Ok(clever) = CleverArchitecture::from_str(s) { 1357 | Clever(clever) 1358 | } else { 1359 | return Err(()); 1360 | } 1361 | } 1362 | }) 1363 | } 1364 | } 1365 | 1366 | impl fmt::Display for Vendor { 1367 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1368 | f.write_str(self.as_str()) 1369 | } 1370 | } 1371 | 1372 | impl FromStr for Vendor { 1373 | type Err = (); 1374 | 1375 | fn from_str(s: &str) -> Result { 1376 | use Vendor::*; 1377 | 1378 | Ok(match s { 1379 | "unknown" => Unknown, 1380 | "amd" => Amd, 1381 | "apple" => Apple, 1382 | "espressif" => Espressif, 1383 | "experimental" => Experimental, 1384 | "fortanix" => Fortanix, 1385 | "ibm" => Ibm, 1386 | "kmc" => Kmc, 1387 | "nintendo" => Nintendo, 1388 | "nvidia" => Nvidia, 1389 | "pc" => Pc, 1390 | "rumprun" => Rumprun, 1391 | "sun" => Sun, 1392 | "uwp" => Uwp, 1393 | "wrs" => Wrs, 1394 | custom => { 1395 | #[cfg(not(feature = "std"))] 1396 | use alloc::borrow::ToOwned; 1397 | 1398 | // A custom vendor. Since triple syntax is so loosely defined, 1399 | // be as conservative as we can to avoid potential ambiguities. 1400 | // We err on the side of being too strict here, as we can 1401 | // always relax it if needed. 1402 | 1403 | // Don't allow empty string names. 1404 | if custom.is_empty() { 1405 | return Err(()); 1406 | } 1407 | 1408 | // Don't allow any other recognized name as a custom vendor, 1409 | // since vendors can be omitted in some contexts. 1410 | if Architecture::from_str(custom).is_ok() 1411 | || OperatingSystem::from_str(custom).is_ok() 1412 | || Environment::from_str(custom).is_ok() 1413 | || BinaryFormat::from_str(custom).is_ok() 1414 | { 1415 | return Err(()); 1416 | } 1417 | 1418 | // Require the first character to be an ascii lowercase. 1419 | if !custom.chars().next().unwrap().is_ascii_lowercase() { 1420 | return Err(()); 1421 | } 1422 | 1423 | // Restrict the set of characters permitted in a custom vendor. 1424 | let has_restricted = custom.chars().any(|c: char| { 1425 | !(c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '.') 1426 | }); 1427 | 1428 | if has_restricted { 1429 | return Err(()); 1430 | } 1431 | 1432 | Custom(CustomVendor::Owned(Box::new(custom.to_owned()))) 1433 | } 1434 | }) 1435 | } 1436 | } 1437 | 1438 | impl fmt::Display for OperatingSystem { 1439 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1440 | use OperatingSystem::*; 1441 | 1442 | let mut with_version = |name, deployment_target| { 1443 | if let Some(DeploymentTarget { 1444 | major, 1445 | minor, 1446 | patch, 1447 | }) = deployment_target 1448 | { 1449 | write!(f, "{}{}.{}.{}", name, major, minor, patch) 1450 | } else { 1451 | write!(f, "{}", name) 1452 | } 1453 | }; 1454 | 1455 | match *self { 1456 | Darwin(deployment_target) => with_version("darwin", deployment_target), 1457 | IOS(deployment_target) => with_version("ios", deployment_target), 1458 | MacOSX(deployment_target) => with_version("macosx", deployment_target), 1459 | TvOS(deployment_target) => with_version("tvos", deployment_target), 1460 | VisionOS(deployment_target) => with_version("visionos", deployment_target), 1461 | WatchOS(deployment_target) => with_version("watchos", deployment_target), 1462 | XROS(deployment_target) => with_version("xros", deployment_target), 1463 | os => f.write_str(&os.into_str()), 1464 | } 1465 | } 1466 | } 1467 | 1468 | impl FromStr for OperatingSystem { 1469 | type Err = (); 1470 | 1471 | fn from_str(s: &str) -> Result { 1472 | use OperatingSystem::*; 1473 | 1474 | let parse_darwin = |name: &str| { 1475 | let s = &s[name.len()..]; 1476 | let mut parts = s.split('.'); 1477 | 1478 | if s.is_empty() { 1479 | // Not specifying a version is allowed! 1480 | return Ok(None); 1481 | } 1482 | 1483 | let major = if let Some(part) = parts.next() { 1484 | part.parse().map_err(|_| ())? 1485 | } else { 1486 | // If the string was just `.`, with no major version, that's 1487 | // clearly an error. 1488 | return Err(()); 1489 | }; 1490 | let minor = if let Some(part) = parts.next() { 1491 | part.parse().map_err(|_| ())? 1492 | } else { 1493 | // Fall back to 0 if no minor version was set 1494 | 0 1495 | }; 1496 | let patch = if let Some(part) = parts.next() { 1497 | part.parse().map_err(|_| ())? 1498 | } else { 1499 | // Fall back to 0 if no patch version was set 1500 | 0 1501 | }; 1502 | 1503 | if parts.next().is_some() { 1504 | // Too many parts 1505 | return Err(()); 1506 | } 1507 | 1508 | Ok(Some(DeploymentTarget { 1509 | major, 1510 | minor, 1511 | patch, 1512 | })) 1513 | }; 1514 | 1515 | // Parse operating system names that contain a version, like `macosx10.7.0`. 1516 | if s.starts_with("darwin") { 1517 | return Ok(Darwin(parse_darwin("darwin")?)); 1518 | } 1519 | if s.starts_with("ios") { 1520 | return Ok(IOS(parse_darwin("ios")?)); 1521 | } 1522 | if s.starts_with("macosx") { 1523 | return Ok(MacOSX(parse_darwin("macosx")?)); 1524 | } 1525 | if s.starts_with("tvos") { 1526 | return Ok(TvOS(parse_darwin("tvos")?)); 1527 | } 1528 | if s.starts_with("visionos") { 1529 | return Ok(VisionOS(parse_darwin("visionos")?)); 1530 | } 1531 | if s.starts_with("watchos") { 1532 | return Ok(WatchOS(parse_darwin("watchos")?)); 1533 | } 1534 | if s.starts_with("xros") { 1535 | return Ok(XROS(parse_darwin("xros")?)); 1536 | } 1537 | 1538 | Ok(match s { 1539 | "unknown" => Unknown, 1540 | "aix" => Aix, 1541 | "amdhsa" => AmdHsa, 1542 | "bitrig" => Bitrig, 1543 | "cloudabi" => Cloudabi, 1544 | "cuda" => Cuda, 1545 | "dragonfly" => Dragonfly, 1546 | "emscripten" => Emscripten, 1547 | "freebsd" => Freebsd, 1548 | "fuchsia" => Fuchsia, 1549 | "haiku" => Haiku, 1550 | "hermit" => Hermit, 1551 | "horizon" => Horizon, 1552 | "hurd" => Hurd, 1553 | "illumos" => Illumos, 1554 | "l4re" => L4re, 1555 | "linux" => Linux, 1556 | "nebulet" => Nebulet, 1557 | "netbsd" => Netbsd, 1558 | "none" => None_, 1559 | "openbsd" => Openbsd, 1560 | "psp" => Psp, 1561 | "redox" => Redox, 1562 | "solaris" => Solaris, 1563 | "solid_asp3" => SolidAsp3, 1564 | "uefi" => Uefi, 1565 | "vxworks" => VxWorks, 1566 | "wasi" => Wasi, 1567 | "wasip1" => WasiP1, 1568 | "wasip2" => WasiP2, 1569 | "windows" => Windows, 1570 | "espidf" => Espidf, 1571 | _ => return Err(()), 1572 | }) 1573 | } 1574 | } 1575 | 1576 | impl fmt::Display for Environment { 1577 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1578 | f.write_str(&self.into_str()) 1579 | } 1580 | } 1581 | 1582 | impl FromStr for Environment { 1583 | type Err = (); 1584 | 1585 | fn from_str(s: &str) -> Result { 1586 | use Environment::*; 1587 | 1588 | Ok(match s { 1589 | "unknown" => Unknown, 1590 | "amdgiz" => AmdGiz, 1591 | "android" => Android, 1592 | "androideabi" => Androideabi, 1593 | "eabi" => Eabi, 1594 | "eabihf" => Eabihf, 1595 | "gnu" => Gnu, 1596 | "gnuabi64" => Gnuabi64, 1597 | "gnueabi" => Gnueabi, 1598 | "gnueabihf" => Gnueabihf, 1599 | "gnuspe" => Gnuspe, 1600 | "gnux32" => Gnux32, 1601 | "gnu_ilp32" => GnuIlp32, 1602 | "gnullvm" => GnuLlvm, 1603 | "hermitkernel" => HermitKernel, 1604 | "hurdkernel" => HurdKernel, 1605 | "linuxkernel" => LinuxKernel, 1606 | "macabi" => Macabi, 1607 | "musl" => Musl, 1608 | "musleabi" => Musleabi, 1609 | "musleabihf" => Musleabihf, 1610 | "muslabi64" => Muslabi64, 1611 | "msvc" => Msvc, 1612 | "newlib" => Newlib, 1613 | "none" => None, 1614 | "kernel" => Kernel, 1615 | "uclibc" => Uclibc, 1616 | "uclibceabi" => Uclibceabi, 1617 | "uclibceabihf" => Uclibceabihf, 1618 | "sgx" => Sgx, 1619 | "sim" => Sim, 1620 | "softfloat" => Softfloat, 1621 | "spe" => Spe, 1622 | "threads" => Threads, 1623 | "ohos" => Ohos, 1624 | _ => return Err(()), 1625 | }) 1626 | } 1627 | } 1628 | 1629 | impl fmt::Display for BinaryFormat { 1630 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1631 | f.write_str(&self.into_str()) 1632 | } 1633 | } 1634 | 1635 | impl FromStr for BinaryFormat { 1636 | type Err = (); 1637 | 1638 | fn from_str(s: &str) -> Result { 1639 | use BinaryFormat::*; 1640 | 1641 | Ok(match s { 1642 | "unknown" => Unknown, 1643 | "elf" => Elf, 1644 | "coff" => Coff, 1645 | "macho" => Macho, 1646 | "wasm" => Wasm, 1647 | "xcoff" => Xcoff, 1648 | _ => return Err(()), 1649 | }) 1650 | } 1651 | } 1652 | 1653 | #[cfg(test)] 1654 | mod tests { 1655 | use super::*; 1656 | use alloc::string::ToString; 1657 | 1658 | #[test] 1659 | fn roundtrip_known_triples() { 1660 | // This list is constructed from: 1661 | // - targets emitted by "rustup target list" 1662 | // - targets emitted by "rustc +nightly --print target-list" 1663 | // - targets contributors have added 1664 | let targets = [ 1665 | "aarch64-apple-darwin", 1666 | "aarch64-apple-ios", 1667 | "aarch64-apple-ios-macabi", 1668 | "aarch64-apple-ios-sim", 1669 | "aarch64-apple-tvos", 1670 | "aarch64-apple-tvos-sim", 1671 | "aarch64-apple-visionos", 1672 | "aarch64-apple-visionos-sim", 1673 | "aarch64-apple-watchos", 1674 | "aarch64-apple-watchos-sim", 1675 | "aarch64_be-unknown-linux-gnu", 1676 | "aarch64_be-unknown-linux-gnu_ilp32", 1677 | "aarch64_be-unknown-netbsd", 1678 | "aarch64-kmc-solid_asp3", 1679 | "aarch64-linux-android", 1680 | //"aarch64-nintendo-switch-freestanding", // TODO 1681 | "aarch64-pc-windows-gnullvm", 1682 | "aarch64-pc-windows-msvc", 1683 | "aarch64-unknown-cloudabi", 1684 | "aarch64-unknown-freebsd", 1685 | "aarch64-unknown-fuchsia", 1686 | "aarch64-unknown-hermit", 1687 | "aarch64-unknown-illumos", 1688 | "aarch64-unknown-linux-gnu", 1689 | "aarch64-unknown-linux-gnu_ilp32", 1690 | "aarch64-unknown-linux-musl", 1691 | "aarch64-unknown-linux-ohos", 1692 | "aarch64-unknown-netbsd", 1693 | "aarch64-unknown-none", 1694 | "aarch64-unknown-none-softfloat", 1695 | //"aarch64-unknown-nto-qnx710", // TODO 1696 | "aarch64-unknown-openbsd", 1697 | "aarch64-unknown-redox", 1698 | //"aarch64-unknown-teeos", // TODO 1699 | "aarch64-unknown-uefi", 1700 | "aarch64-uwp-windows-msvc", 1701 | "aarch64-wrs-vxworks", 1702 | //"arm64_32-apple-watchos", // TODO 1703 | //"arm64e-apple-darwin", // TODO 1704 | "amdgcn-amd-amdhsa", 1705 | "amdgcn-amd-amdhsa-amdgiz", 1706 | //"arm64e-apple-ios", // TODO 1707 | //"arm64ec-pc-windows-msvc", // TODO 1708 | "armeb-unknown-linux-gnueabi", 1709 | "armebv7r-none-eabi", 1710 | "armebv7r-none-eabihf", 1711 | "arm-linux-androideabi", 1712 | "arm-unknown-linux-gnueabi", 1713 | "arm-unknown-linux-gnueabihf", 1714 | "arm-unknown-linux-musleabi", 1715 | "arm-unknown-linux-musleabihf", 1716 | "armv4t-none-eabi", 1717 | "armv4t-unknown-linux-gnueabi", 1718 | "armv5te-none-eabi", 1719 | "armv5te-unknown-linux-gnueabi", 1720 | "armv5te-unknown-linux-musleabi", 1721 | "armv5te-unknown-linux-uclibceabi", 1722 | "armv6k-nintendo-3ds", 1723 | "armv6-unknown-freebsd", 1724 | "armv6-unknown-netbsd-eabihf", 1725 | "armv7a-kmc-solid_asp3-eabi", 1726 | "armv7a-kmc-solid_asp3-eabihf", 1727 | "armv7a-none-eabi", 1728 | "armv7a-none-eabihf", 1729 | "armv7-apple-ios", 1730 | "armv7k-apple-watchos", 1731 | "armv7-linux-androideabi", 1732 | "armv7r-none-eabi", 1733 | "armv7r-none-eabihf", 1734 | "armv7s-apple-ios", 1735 | "armv7-unknown-cloudabi-eabihf", 1736 | //"armv7-sony-vita-newlibeabihf", // TODO 1737 | "armv7-unknown-freebsd", 1738 | "armv7-unknown-linux-gnueabi", 1739 | "armv7-unknown-linux-gnueabihf", 1740 | "armv7-unknown-linux-musleabi", 1741 | "armv7-unknown-linux-musleabihf", 1742 | "armv7-unknown-linux-ohos", 1743 | "armv7-unknown-linux-uclibceabi", 1744 | "armv7-unknown-linux-uclibceabihf", 1745 | "armv7-unknown-netbsd-eabihf", 1746 | "armv7-wrs-vxworks-eabihf", 1747 | "asmjs-unknown-emscripten", 1748 | "armv8r-none-eabihf", 1749 | //"avr-unknown-gnu-atmega328", // TODO 1750 | "avr-unknown-unknown", 1751 | "bpfeb-unknown-none", 1752 | "bpfel-unknown-none", 1753 | //"csky-unknown-linux-gnuabiv2", // TODO 1754 | //"csky-unknown-linux-gnuabiv2hf", // TODO 1755 | "hexagon-unknown-linux-musl", 1756 | "hexagon-unknown-none-elf", 1757 | "i386-apple-ios", 1758 | //"i586-pc-nto-qnx700", // TODO 1759 | "i586-pc-windows-msvc", 1760 | "i586-unknown-linux-gnu", 1761 | "i586-unknown-linux-musl", 1762 | "i586-unknown-netbsd", 1763 | "i686-apple-darwin", 1764 | "i686-linux-android", 1765 | "i686-apple-macosx10.7.0", 1766 | "i686-pc-windows-gnu", 1767 | "i686-pc-windows-gnullvm", 1768 | "i686-pc-windows-msvc", 1769 | "i686-unknown-cloudabi", 1770 | "i686-unknown-dragonfly", 1771 | "i686-unknown-freebsd", 1772 | "i686-unknown-haiku", 1773 | "i686-unknown-hurd-gnu", 1774 | "i686-unknown-linux-gnu", 1775 | "i686-unknown-linux-musl", 1776 | "i686-unknown-netbsd", 1777 | "i686-unknown-openbsd", 1778 | "i686-unknown-redox", 1779 | "i686-unknown-uefi", 1780 | "i686-uwp-windows-gnu", 1781 | "i686-uwp-windows-msvc", 1782 | "i686-win7-windows-msvc", 1783 | "i686-wrs-vxworks", 1784 | "loongarch64-unknown-linux-gnu", 1785 | "loongarch64-unknown-linux-musl", 1786 | "loongarch64-unknown-none", 1787 | "loongarch64-unknown-none-softfloat", 1788 | "m68k-unknown-linux-gnu", 1789 | "mips64el-unknown-linux-gnuabi64", 1790 | "mips64el-unknown-linux-muslabi64", 1791 | "mips64-openwrt-linux-musl", 1792 | "mips64-unknown-linux-gnuabi64", 1793 | "mips64-unknown-linux-muslabi64", 1794 | "mipsel-sony-psp", 1795 | //"mipsel-sony-psx", // TODO 1796 | "mipsel-unknown-linux-gnu", 1797 | "mipsel-unknown-linux-musl", 1798 | "mipsel-unknown-linux-uclibc", 1799 | "mipsel-unknown-netbsd", 1800 | "mipsel-unknown-none", 1801 | "mipsisa32r6el-unknown-linux-gnu", 1802 | "mipsisa32r6-unknown-linux-gnu", 1803 | "mipsisa64r6el-unknown-linux-gnuabi64", 1804 | "mipsisa64r6-unknown-linux-gnuabi64", 1805 | "mips-unknown-linux-gnu", 1806 | "mips-unknown-linux-musl", 1807 | "mips-unknown-linux-uclibc", 1808 | "msp430-none-elf", 1809 | "nvptx64-nvidia-cuda", 1810 | "powerpc64-ibm-aix", 1811 | "powerpc64le-unknown-freebsd", 1812 | "powerpc64le-unknown-linux-gnu", 1813 | "powerpc64le-unknown-linux-musl", 1814 | "powerpc64-unknown-freebsd", 1815 | "powerpc64-unknown-linux-gnu", 1816 | "powerpc64-unknown-linux-musl", 1817 | "powerpc64-unknown-openbsd", 1818 | "powerpc64-wrs-vxworks", 1819 | "powerpc-ibm-aix", 1820 | "powerpc-unknown-freebsd", 1821 | "powerpc-unknown-linux-gnu", 1822 | "powerpc-unknown-linux-gnuspe", 1823 | "powerpc-unknown-linux-musl", 1824 | "powerpc-unknown-netbsd", 1825 | "powerpc-unknown-openbsd", 1826 | "powerpc-wrs-vxworks", 1827 | "powerpc-wrs-vxworks-spe", 1828 | "riscv32gc-unknown-linux-gnu", 1829 | "riscv32gc-unknown-linux-musl", 1830 | "riscv32imac-esp-espidf", 1831 | "riscv32imac-unknown-none-elf", 1832 | //"riscv32imac-unknown-xous-elf", // TODO 1833 | "riscv32imafc-esp-espidf", 1834 | "riscv32imafc-unknown-none-elf", 1835 | "riscv32ima-unknown-none-elf", 1836 | "riscv32imc-esp-espidf", 1837 | "riscv32imc-unknown-none-elf", 1838 | //"riscv32im-risc0-zkvm-elf", // TODO 1839 | "riscv32im-unknown-none-elf", 1840 | "riscv32i-unknown-none-elf", 1841 | "riscv64gc-unknown-freebsd", 1842 | "riscv64gc-unknown-fuchsia", 1843 | "riscv64gc-unknown-hermit", 1844 | "riscv64gc-unknown-linux-gnu", 1845 | "riscv64gc-unknown-linux-musl", 1846 | "riscv64gc-unknown-netbsd", 1847 | "riscv64gc-unknown-none-elf", 1848 | "riscv64gc-unknown-openbsd", 1849 | "riscv64imac-unknown-none-elf", 1850 | "riscv64-linux-android", 1851 | "s390x-unknown-linux-gnu", 1852 | "s390x-unknown-linux-musl", 1853 | "sparc64-unknown-linux-gnu", 1854 | "sparc64-unknown-netbsd", 1855 | "sparc64-unknown-openbsd", 1856 | "sparc-unknown-linux-gnu", 1857 | "sparc-unknown-none-elf", 1858 | "sparcv9-sun-solaris", 1859 | "thumbv4t-none-eabi", 1860 | "thumbv5te-none-eabi", 1861 | "thumbv6m-none-eabi", 1862 | "thumbv7a-pc-windows-msvc", 1863 | "thumbv7a-uwp-windows-msvc", 1864 | "thumbv7em-none-eabi", 1865 | "thumbv7em-none-eabihf", 1866 | "thumbv7m-none-eabi", 1867 | "thumbv7neon-linux-androideabi", 1868 | "thumbv7neon-unknown-linux-gnueabihf", 1869 | "thumbv7neon-unknown-linux-musleabihf", 1870 | "thumbv8m.base-none-eabi", 1871 | "thumbv8m.main-none-eabi", 1872 | "thumbv8m.main-none-eabihf", 1873 | "wasm32-experimental-emscripten", 1874 | "wasm32-unknown-emscripten", 1875 | "wasm32-unknown-unknown", 1876 | "wasm32-wasi", 1877 | "wasm32-wasip1", 1878 | "wasm32-wasip1-threads", 1879 | "wasm32-wasip2", 1880 | "wasm64-unknown-unknown", 1881 | "wasm64-wasi", 1882 | "x86_64-apple-darwin", 1883 | "x86_64-apple-darwin23.6.0", 1884 | "x86_64-apple-ios", 1885 | "x86_64-apple-ios-macabi", 1886 | "x86_64-apple-tvos", 1887 | "x86_64-apple-watchos-sim", 1888 | "x86_64-fortanix-unknown-sgx", 1889 | "x86_64h-apple-darwin", 1890 | "x86_64-linux-android", 1891 | //"x86_64-pc-nto-qnx710", // TODO 1892 | "x86_64-linux-kernel", // Changed to x86_64-unknown-none-linuxkernel in 1.53.0 1893 | "x86_64-apple-macosx", 1894 | "x86_64-apple-macosx10.7.0", 1895 | "x86_64-pc-solaris", 1896 | "x86_64-pc-windows-gnu", 1897 | "x86_64-pc-windows-gnullvm", 1898 | "x86_64-pc-windows-msvc", 1899 | "x86_64-rumprun-netbsd", // Removed in 1.53.0 1900 | "x86_64-sun-solaris", 1901 | "x86_64-unknown-bitrig", 1902 | "x86_64-unknown-cloudabi", 1903 | "x86_64-unikraft-linux-musl", 1904 | "x86_64-unknown-dragonfly", 1905 | "x86_64-unknown-freebsd", 1906 | "x86_64-unknown-fuchsia", 1907 | "x86_64-unknown-haiku", 1908 | "x86_64-unknown-hermit-kernel", // Changed to x86_64-unknown-none-hermitkernel in 1.53.0 1909 | "x86_64-unknown-hermit", 1910 | "x86_64-unknown-illumos", 1911 | "x86_64-unknown-l4re-uclibc", 1912 | "x86_64-unknown-linux-gnu", 1913 | "x86_64-unknown-linux-gnux32", 1914 | "x86_64-unknown-linux-musl", 1915 | "x86_64-unknown-linux-none", 1916 | "x86_64-unknown-linux-ohos", 1917 | "x86_64-unknown-netbsd", 1918 | "x86_64-unknown-none", 1919 | "x86_64-unknown-none-hermitkernel", 1920 | "x86_64-unknown-none-linuxkernel", 1921 | "x86_64-unknown-openbsd", 1922 | "x86_64-unknown-redox", 1923 | "x86_64-unknown-uefi", 1924 | "x86_64-uwp-windows-gnu", 1925 | "x86_64-uwp-windows-msvc", 1926 | "x86_64-win7-windows-msvc", 1927 | "x86_64-wrs-vxworks", 1928 | "xtensa-esp32-espidf", 1929 | "clever-unknown-elf", 1930 | "xtensa-esp32-none-elf", 1931 | "xtensa-esp32s2-espidf", 1932 | "xtensa-esp32s2-none-elf", 1933 | "xtensa-esp32s3-espidf", 1934 | "xtensa-esp32s3-none-elf", 1935 | #[cfg(feature = "arch_zkasm")] 1936 | "zkasm-unknown-unknown", 1937 | ]; 1938 | 1939 | for target in targets.iter() { 1940 | let t = Triple::from_str(target).expect("can't parse target"); 1941 | assert_ne!(t.architecture, Architecture::Unknown); 1942 | assert_eq!(t.to_string(), *target, "{:#?}", t); 1943 | } 1944 | } 1945 | 1946 | #[test] 1947 | fn default_format_to_elf() { 1948 | let t = Triple::from_str("riscv64").expect("can't parse target"); 1949 | assert_eq!( 1950 | t.architecture, 1951 | Architecture::Riscv64(Riscv64Architecture::Riscv64), 1952 | ); 1953 | assert_eq!(t.vendor, Vendor::Unknown); 1954 | assert_eq!(t.operating_system, OperatingSystem::Unknown); 1955 | assert_eq!(t.environment, Environment::Unknown); 1956 | assert_eq!(t.binary_format, BinaryFormat::Elf); 1957 | } 1958 | 1959 | #[test] 1960 | fn thumbv7em_none_eabihf() { 1961 | let t = Triple::from_str("thumbv7em-none-eabihf").expect("can't parse target"); 1962 | assert_eq!( 1963 | t.architecture, 1964 | Architecture::Arm(ArmArchitecture::Thumbv7em) 1965 | ); 1966 | assert_eq!(t.vendor, Vendor::Unknown); 1967 | assert_eq!(t.operating_system, OperatingSystem::None_); 1968 | assert_eq!(t.environment, Environment::Eabihf); 1969 | assert_eq!(t.binary_format, BinaryFormat::Elf); 1970 | } 1971 | 1972 | #[test] 1973 | fn fuchsia_rename() { 1974 | // Fuchsia targets were renamed to add the `unknown`. 1975 | assert_eq!( 1976 | Triple::from_str("aarch64-fuchsia"), 1977 | Triple::from_str("aarch64-unknown-fuchsia") 1978 | ); 1979 | assert_eq!( 1980 | Triple::from_str("x86_64-fuchsia"), 1981 | Triple::from_str("x86_64-unknown-fuchsia") 1982 | ); 1983 | } 1984 | 1985 | #[test] 1986 | fn custom_vendors() { 1987 | // Test various invalid cases. 1988 | assert!(Triple::from_str("x86_64--linux").is_err()); 1989 | assert!(Triple::from_str("x86_64-42-linux").is_err()); 1990 | assert!(Triple::from_str("x86_64-__customvendor__-linux").is_err()); 1991 | assert!(Triple::from_str("x86_64-^-linux").is_err()); 1992 | assert!(Triple::from_str("x86_64- -linux").is_err()); 1993 | assert!(Triple::from_str("x86_64-CustomVendor-linux").is_err()); 1994 | assert!(Triple::from_str("x86_64-linux-linux").is_err()); 1995 | assert!(Triple::from_str("x86_64-x86_64-linux").is_err()); 1996 | assert!(Triple::from_str("x86_64-elf-linux").is_err()); 1997 | assert!(Triple::from_str("x86_64-gnu-linux").is_err()); 1998 | assert!(Triple::from_str("x86_64-linux-customvendor").is_err()); 1999 | assert!(Triple::from_str("customvendor").is_err()); 2000 | assert!(Triple::from_str("customvendor-x86_64").is_err()); 2001 | assert!(Triple::from_str("x86_64-").is_err()); 2002 | assert!(Triple::from_str("x86_64--").is_err()); 2003 | 2004 | // Test various Unicode things. 2005 | assert!( 2006 | Triple::from_str("x86_64-𝓬𝓾𝓼𝓽𝓸𝓶𝓿𝓮𝓷𝓭𝓸𝓻-linux").is_err(), 2007 | "unicode font hazard" 2008 | ); 2009 | assert!( 2010 | Triple::from_str("x86_64-ćúśtőḿvéńdőŕ-linux").is_err(), 2011 | "diacritical mark stripping hazard" 2012 | ); 2013 | assert!( 2014 | Triple::from_str("x86_64-customvendοr-linux").is_err(), 2015 | "homoglyph hazard" 2016 | ); 2017 | assert!(Triple::from_str("x86_64-customvendor-linux").is_ok()); 2018 | assert!( 2019 | Triple::from_str("x86_64-ffi-linux").is_err(), 2020 | "normalization hazard" 2021 | ); 2022 | assert!(Triple::from_str("x86_64-ffi-linux").is_ok()); 2023 | assert!( 2024 | Triple::from_str("x86_64-custom‍vendor-linux").is_err(), 2025 | "zero-width character hazard" 2026 | ); 2027 | assert!( 2028 | Triple::from_str("x86_64-customvendor-linux").is_err(), 2029 | "BOM hazard" 2030 | ); 2031 | 2032 | // Test some valid cases. 2033 | let t = Triple::from_str("x86_64-customvendor-linux") 2034 | .expect("can't parse target with custom vendor"); 2035 | assert_eq!(t.architecture, Architecture::X86_64); 2036 | assert_eq!( 2037 | t.vendor, 2038 | Vendor::Custom(CustomVendor::Static("customvendor")) 2039 | ); 2040 | assert_eq!(t.operating_system, OperatingSystem::Linux); 2041 | assert_eq!(t.environment, Environment::Unknown); 2042 | assert_eq!(t.binary_format, BinaryFormat::Elf); 2043 | assert_eq!(t.to_string(), "x86_64-customvendor-linux"); 2044 | 2045 | let t = 2046 | Triple::from_str("x86_64-customvendor").expect("can't parse target with custom vendor"); 2047 | assert_eq!(t.architecture, Architecture::X86_64); 2048 | assert_eq!( 2049 | t.vendor, 2050 | Vendor::Custom(CustomVendor::Static("customvendor")) 2051 | ); 2052 | assert_eq!(t.operating_system, OperatingSystem::Unknown); 2053 | assert_eq!(t.environment, Environment::Unknown); 2054 | assert_eq!(t.binary_format, BinaryFormat::Elf); 2055 | 2056 | assert_eq!( 2057 | Triple::from_str("unknown-foo"), 2058 | Ok(Triple { 2059 | architecture: Architecture::Unknown, 2060 | vendor: Vendor::Custom(CustomVendor::Static("foo")), 2061 | operating_system: OperatingSystem::Unknown, 2062 | environment: Environment::Unknown, 2063 | binary_format: BinaryFormat::Unknown, 2064 | }) 2065 | ); 2066 | } 2067 | 2068 | #[test] 2069 | fn deployment_version_parsing() { 2070 | assert_eq!( 2071 | Triple::from_str("aarch64-apple-macosx"), 2072 | Ok(Triple { 2073 | architecture: Architecture::Aarch64(Aarch64Architecture::Aarch64), 2074 | vendor: Vendor::Apple, 2075 | operating_system: OperatingSystem::MacOSX(None), 2076 | environment: Environment::Unknown, 2077 | binary_format: BinaryFormat::Macho, 2078 | }) 2079 | ); 2080 | 2081 | assert_eq!( 2082 | Triple::from_str("aarch64-apple-macosx10.14.6"), 2083 | Ok(Triple { 2084 | architecture: Architecture::Aarch64(Aarch64Architecture::Aarch64), 2085 | vendor: Vendor::Apple, 2086 | operating_system: OperatingSystem::MacOSX(Some(DeploymentTarget { 2087 | major: 10, 2088 | minor: 14, 2089 | patch: 6, 2090 | })), 2091 | environment: Environment::Unknown, 2092 | binary_format: BinaryFormat::Macho, 2093 | }) 2094 | ); 2095 | 2096 | let expected = Triple { 2097 | architecture: Architecture::X86_64, 2098 | vendor: Vendor::Apple, 2099 | operating_system: OperatingSystem::Darwin(Some(DeploymentTarget { 2100 | major: 23, 2101 | minor: 0, 2102 | patch: 0, 2103 | })), 2104 | environment: Environment::Unknown, 2105 | binary_format: BinaryFormat::Macho, 2106 | }; 2107 | assert_eq!( 2108 | Triple::from_str("x86_64-apple-darwin23"), 2109 | Ok(expected.clone()) 2110 | ); 2111 | assert_eq!( 2112 | Triple::from_str("x86_64-apple-darwin23.0"), 2113 | Ok(expected.clone()) 2114 | ); 2115 | assert_eq!(Triple::from_str("x86_64-apple-darwin23.0.0"), Ok(expected)); 2116 | 2117 | assert!(Triple::from_str("x86_64-apple-darwin.").is_err()); 2118 | assert!(Triple::from_str("x86_64-apple-darwin23.0.0.0").is_err()); 2119 | } 2120 | } 2121 | -------------------------------------------------------------------------------- /src/triple.rs: -------------------------------------------------------------------------------- 1 | // This file defines the `Triple` type and support code shared by all targets. 2 | 3 | use crate::data_model::CDataModel; 4 | use crate::parse_error::ParseError; 5 | use crate::targets::{ 6 | default_binary_format, Architecture, ArmArchitecture, BinaryFormat, Environment, 7 | OperatingSystem, Riscv32Architecture, Vendor, 8 | }; 9 | #[cfg(not(feature = "std"))] 10 | use alloc::borrow::ToOwned; 11 | use core::fmt; 12 | use core::str::FromStr; 13 | 14 | /// The target memory endianness. 15 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 16 | #[allow(missing_docs)] 17 | pub enum Endianness { 18 | Little, 19 | Big, 20 | } 21 | 22 | /// The width of a pointer (in the default address space). 23 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 24 | #[allow(missing_docs)] 25 | pub enum PointerWidth { 26 | U16, 27 | U32, 28 | U64, 29 | } 30 | 31 | impl PointerWidth { 32 | /// Return the number of bits in a pointer. 33 | pub fn bits(self) -> u8 { 34 | match self { 35 | PointerWidth::U16 => 16, 36 | PointerWidth::U32 => 32, 37 | PointerWidth::U64 => 64, 38 | } 39 | } 40 | 41 | /// Return the number of bytes in a pointer. 42 | /// 43 | /// For these purposes, there are 8 bits in a byte. 44 | pub fn bytes(self) -> u8 { 45 | match self { 46 | PointerWidth::U16 => 2, 47 | PointerWidth::U32 => 4, 48 | PointerWidth::U64 => 8, 49 | } 50 | } 51 | } 52 | 53 | /// The calling convention, which specifies things like which registers are 54 | /// used for passing arguments, which registers are callee-saved, and so on. 55 | #[cfg_attr(feature = "rust_1_40", non_exhaustive)] 56 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 57 | pub enum CallingConvention { 58 | /// "System V", which is used on most Unix-like platfoms. Note that the 59 | /// specific conventions vary between hardware architectures; for example, 60 | /// x86-32's "System V" is entirely different from x86-64's "System V". 61 | SystemV, 62 | 63 | /// The WebAssembly C ABI. 64 | /// https://github.com/WebAssembly/tool-conventions/blob/master/BasicCABI.md 65 | WasmBasicCAbi, 66 | 67 | /// "Windows Fastcall", which is used on Windows. Note that like "System V", 68 | /// this varies between hardware architectures. On x86-32 it describes what 69 | /// Windows documentation calls "fastcall", and on x86-64 it describes what 70 | /// Windows documentation often just calls the Windows x64 calling convention 71 | /// (though the compiler still recognizes "fastcall" as an alias for it). 72 | WindowsFastcall, 73 | 74 | /// Apple Aarch64 platforms use their own variant of the common Aarch64 75 | /// calling convention. 76 | /// 77 | /// 78 | AppleAarch64, 79 | } 80 | 81 | /// An LLVM target "triple". Historically such things had three fields, though 82 | /// they've added additional fields over time. 83 | /// 84 | /// Note that `Triple` doesn't implement `Default` itself. If you want a type 85 | /// which defaults to the host triple, or defaults to unknown-unknown-unknown, 86 | /// use `DefaultToHost` or `DefaultToUnknown`, respectively. 87 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] 88 | pub struct Triple { 89 | /// The "architecture" (and sometimes the subarchitecture). 90 | pub architecture: Architecture, 91 | /// The "vendor" (whatever that means). 92 | pub vendor: Vendor, 93 | /// The "operating system" (sometimes also the environment). 94 | pub operating_system: OperatingSystem, 95 | /// The "environment" on top of the operating system (often omitted for 96 | /// operating systems with a single predominant environment). 97 | pub environment: Environment, 98 | /// The "binary format" (rarely used). 99 | pub binary_format: BinaryFormat, 100 | } 101 | 102 | impl Triple { 103 | /// Return the endianness of this target's architecture. 104 | pub fn endianness(&self) -> Result { 105 | self.architecture.endianness() 106 | } 107 | 108 | /// Return the pointer width of this target's architecture. 109 | /// 110 | /// This function is aware of x32 and ilp32 ABIs on 64-bit architectures. 111 | pub fn pointer_width(&self) -> Result { 112 | // Some ABIs have a different pointer width than the CPU architecture. 113 | match self.environment { 114 | Environment::Gnux32 | Environment::GnuIlp32 => return Ok(PointerWidth::U32), 115 | _ => {} 116 | } 117 | 118 | self.architecture.pointer_width() 119 | } 120 | 121 | /// Return the default calling convention for the given target triple. 122 | pub fn default_calling_convention(&self) -> Result { 123 | Ok(match self.operating_system { 124 | os if os.is_like_darwin() => match self.architecture { 125 | Architecture::Aarch64(_) => CallingConvention::AppleAarch64, 126 | _ => CallingConvention::SystemV, 127 | }, 128 | OperatingSystem::Aix 129 | | OperatingSystem::Bitrig 130 | | OperatingSystem::Cloudabi 131 | | OperatingSystem::Dragonfly 132 | | OperatingSystem::Freebsd 133 | | OperatingSystem::Fuchsia 134 | | OperatingSystem::Haiku 135 | | OperatingSystem::Hermit 136 | | OperatingSystem::Hurd 137 | | OperatingSystem::L4re 138 | | OperatingSystem::Linux 139 | | OperatingSystem::Netbsd 140 | | OperatingSystem::Openbsd 141 | | OperatingSystem::Redox 142 | | OperatingSystem::Solaris => CallingConvention::SystemV, 143 | OperatingSystem::Windows => CallingConvention::WindowsFastcall, 144 | OperatingSystem::Nebulet 145 | | OperatingSystem::Emscripten 146 | | OperatingSystem::Wasi 147 | | OperatingSystem::Unknown => match self.architecture { 148 | Architecture::Wasm32 => CallingConvention::WasmBasicCAbi, 149 | _ => return Err(()), 150 | }, 151 | _ => return Err(()), 152 | }) 153 | } 154 | 155 | /// The C data model for a given target. If the model is not known, returns `Err(())`. 156 | pub fn data_model(&self) -> Result { 157 | match self.pointer_width()? { 158 | PointerWidth::U64 => { 159 | if self.operating_system == OperatingSystem::Windows { 160 | Ok(CDataModel::LLP64) 161 | } else if self.default_calling_convention() == Ok(CallingConvention::SystemV) 162 | || self.architecture == Architecture::Wasm64 163 | || self.default_calling_convention() == Ok(CallingConvention::AppleAarch64) 164 | { 165 | Ok(CDataModel::LP64) 166 | } else { 167 | Err(()) 168 | } 169 | } 170 | PointerWidth::U32 => { 171 | if self.operating_system == OperatingSystem::Windows 172 | || self.default_calling_convention() == Ok(CallingConvention::SystemV) 173 | || self.architecture == Architecture::Wasm32 174 | { 175 | Ok(CDataModel::ILP32) 176 | } else { 177 | Err(()) 178 | } 179 | } 180 | // TODO: on 16-bit machines there is usually a distinction 181 | // between near-pointers and far-pointers. 182 | // Additionally, code pointers sometimes have a different size than data pointers. 183 | // We don't handle this case. 184 | PointerWidth::U16 => Err(()), 185 | } 186 | } 187 | 188 | /// Return a `Triple` with all unknown fields. 189 | pub fn unknown() -> Self { 190 | Self { 191 | architecture: Architecture::Unknown, 192 | vendor: Vendor::Unknown, 193 | operating_system: OperatingSystem::Unknown, 194 | environment: Environment::Unknown, 195 | binary_format: BinaryFormat::Unknown, 196 | } 197 | } 198 | } 199 | 200 | impl fmt::Display for Triple { 201 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 202 | if let Some(res) = self.special_case_display(f) { 203 | return res; 204 | } 205 | 206 | let implied_binary_format = default_binary_format(&self); 207 | 208 | write!(f, "{}", self.architecture)?; 209 | if self.vendor == Vendor::Unknown 210 | && (self.environment != Environment::HermitKernel 211 | && self.environment != Environment::LinuxKernel) 212 | && ((self.operating_system == OperatingSystem::Linux 213 | && (self.environment == Environment::Android 214 | || self.environment == Environment::Androideabi 215 | || self.environment == Environment::Kernel)) 216 | || self.operating_system == OperatingSystem::Wasi 217 | || self.operating_system == OperatingSystem::WasiP1 218 | || self.operating_system == OperatingSystem::WasiP2 219 | || (self.operating_system == OperatingSystem::None_ 220 | && (self.architecture == Architecture::Arm(ArmArchitecture::Armv4t) 221 | || self.architecture == Architecture::Arm(ArmArchitecture::Armv5te) 222 | || self.architecture == Architecture::Arm(ArmArchitecture::Armebv7r) 223 | || self.architecture == Architecture::Arm(ArmArchitecture::Armv7a) 224 | || self.architecture == Architecture::Arm(ArmArchitecture::Armv7r) 225 | || self.architecture == Architecture::Arm(ArmArchitecture::Armv8r) 226 | || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv4t) 227 | || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv5te) 228 | || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv6m) 229 | || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7em) 230 | || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7m) 231 | || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv8mBase) 232 | || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv8mMain) 233 | || self.architecture == Architecture::Msp430))) 234 | { 235 | // As a special case, omit the vendor for Android, Wasi, and sometimes 236 | // None_, depending on the hardware architecture. This logic is entirely 237 | // ad-hoc, and is just sufficient to handle the current set of recognized 238 | // triples. 239 | write!(f, "-{}", self.operating_system)?; 240 | } else if self.architecture.is_clever() && self.operating_system == OperatingSystem::Unknown 241 | { 242 | write!(f, "-{}", self.vendor)?; 243 | } else { 244 | write!(f, "-{}-{}", self.vendor, self.operating_system)?; 245 | } 246 | 247 | match (&self.vendor, self.operating_system, self.environment) { 248 | (Vendor::Nintendo, OperatingSystem::Horizon, Environment::Newlib) 249 | | (Vendor::Espressif, OperatingSystem::Espidf, Environment::Newlib) => { 250 | // The triple representations of these platforms don't have an environment field. 251 | } 252 | (_, _, Environment::Unknown) => { 253 | // Don't print out the environment if it is unknown. 254 | } 255 | _ => { 256 | write!(f, "-{}", self.environment)?; 257 | } 258 | } 259 | 260 | if self.binary_format != implied_binary_format || show_binary_format_with_no_os(self) { 261 | // As a special case, omit a non-default binary format for some 262 | // targets which happen to exclude it. 263 | write!(f, "-{}", self.binary_format)?; 264 | } 265 | Ok(()) 266 | } 267 | } 268 | 269 | fn show_binary_format_with_no_os(triple: &Triple) -> bool { 270 | if triple.binary_format == BinaryFormat::Unknown { 271 | return false; 272 | } 273 | 274 | #[cfg(feature = "arch_zkasm")] 275 | { 276 | if triple.architecture == Architecture::ZkAsm { 277 | return false; 278 | } 279 | } 280 | 281 | triple.environment != Environment::Eabi 282 | && triple.environment != Environment::Eabihf 283 | && triple.environment != Environment::Sgx 284 | && triple.architecture != Architecture::Avr 285 | && triple.architecture != Architecture::Wasm32 286 | && triple.architecture != Architecture::Wasm64 287 | && (triple.operating_system == OperatingSystem::None_ 288 | || triple.operating_system == OperatingSystem::Unknown) 289 | } 290 | 291 | impl FromStr for Triple { 292 | type Err = ParseError; 293 | 294 | /// Parse a triple from an LLVM target triple. 295 | /// 296 | /// This may also be able to parse `rustc` target triples, though support 297 | /// for that is secondary. 298 | fn from_str(s: &str) -> Result { 299 | if let Some(triple) = Triple::special_case_from_str(s) { 300 | return Ok(triple); 301 | } 302 | 303 | let mut parts = s.split('-'); 304 | let mut result = Self::unknown(); 305 | let mut current_part; 306 | 307 | current_part = parts.next(); 308 | if let Some(s) = current_part { 309 | if let Ok(architecture) = Architecture::from_str(s) { 310 | result.architecture = architecture; 311 | current_part = parts.next(); 312 | } else { 313 | // Insist that the triple start with a valid architecture. 314 | return Err(ParseError::UnrecognizedArchitecture(s.to_owned())); 315 | } 316 | } 317 | 318 | let mut has_vendor = false; 319 | let mut has_operating_system = false; 320 | if let Some(s) = current_part { 321 | if let Ok(vendor) = Vendor::from_str(s) { 322 | has_vendor = true; 323 | result.vendor = vendor; 324 | current_part = parts.next(); 325 | } 326 | } 327 | 328 | if !has_operating_system { 329 | if let Some(s) = current_part { 330 | if let Ok(operating_system) = OperatingSystem::from_str(s) { 331 | has_operating_system = true; 332 | result.operating_system = operating_system; 333 | current_part = parts.next(); 334 | } 335 | } 336 | } 337 | 338 | let mut has_environment = false; 339 | 340 | if !has_environment { 341 | if let Some(s) = current_part { 342 | if let Ok(environment) = Environment::from_str(s) { 343 | has_environment = true; 344 | result.environment = environment; 345 | current_part = parts.next(); 346 | } 347 | } 348 | } 349 | 350 | let mut has_binary_format = false; 351 | if let Some(s) = current_part { 352 | if let Ok(binary_format) = BinaryFormat::from_str(s) { 353 | has_binary_format = true; 354 | result.binary_format = binary_format; 355 | current_part = parts.next(); 356 | } 357 | } 358 | 359 | // The binary format is frequently omitted; if that's the case here, 360 | // infer it from the other fields. 361 | if !has_binary_format { 362 | result.binary_format = default_binary_format(&result); 363 | } 364 | 365 | if let Some(s) = current_part { 366 | Err( 367 | if !has_vendor && !has_operating_system && !has_environment && !has_binary_format { 368 | ParseError::UnrecognizedVendor(s.to_owned()) 369 | } else if !has_operating_system && !has_environment && !has_binary_format { 370 | ParseError::UnrecognizedOperatingSystem(s.to_owned()) 371 | } else if !has_environment && !has_binary_format { 372 | ParseError::UnrecognizedEnvironment(s.to_owned()) 373 | } else if !has_binary_format { 374 | ParseError::UnrecognizedBinaryFormat(s.to_owned()) 375 | } else { 376 | ParseError::UnrecognizedField(s.to_owned()) 377 | }, 378 | ) 379 | } else { 380 | Ok(result) 381 | } 382 | } 383 | } 384 | 385 | impl Triple { 386 | /// Handle special cases in the `Display` implementation. 387 | fn special_case_display(&self, f: &mut fmt::Formatter) -> Option { 388 | let res = match self { 389 | Triple { 390 | architecture: Architecture::Arm(ArmArchitecture::Armv6k), 391 | vendor: Vendor::Nintendo, 392 | operating_system: OperatingSystem::Horizon, 393 | .. 394 | } => write!(f, "{}-{}-3ds", self.architecture, self.vendor), 395 | Triple { 396 | architecture: Architecture::Riscv32(Riscv32Architecture::Riscv32imc), 397 | vendor: Vendor::Espressif, 398 | operating_system: OperatingSystem::Espidf, 399 | .. 400 | } => write!(f, "{}-esp-{}", self.architecture, self.operating_system), 401 | _ => return None, 402 | }; 403 | Some(res) 404 | } 405 | 406 | /// Handle special cases in the `FromStr` implementation. 407 | fn special_case_from_str(s: &str) -> Option { 408 | let mut triple = Triple::unknown(); 409 | 410 | match s { 411 | "armv6k-nintendo-3ds" => { 412 | triple.architecture = Architecture::Arm(ArmArchitecture::Armv6k); 413 | triple.vendor = Vendor::Nintendo; 414 | triple.operating_system = OperatingSystem::Horizon; 415 | triple.environment = Environment::Newlib; 416 | triple.binary_format = default_binary_format(&triple); 417 | } 418 | "riscv32imc-esp-espidf" => { 419 | triple.architecture = Architecture::Riscv32(Riscv32Architecture::Riscv32imc); 420 | triple.vendor = Vendor::Espressif; 421 | triple.operating_system = OperatingSystem::Espidf; 422 | triple.environment = Environment::Newlib; 423 | triple.binary_format = default_binary_format(&triple); 424 | } 425 | _ => return None, 426 | } 427 | 428 | Some(triple) 429 | } 430 | } 431 | 432 | /// A convenient syntax for triple literals. 433 | /// 434 | /// This currently expands to code that just calls `Triple::from_str` and does 435 | /// an `expect`, though in the future it would be cool to use procedural macros 436 | /// or so to report errors at compile time instead. 437 | #[macro_export] 438 | macro_rules! triple { 439 | ($str:tt) => { 440 | <$crate::Triple as core::str::FromStr>::from_str($str).expect("invalid triple literal") 441 | }; 442 | } 443 | 444 | #[cfg(test)] 445 | mod tests { 446 | use super::*; 447 | 448 | #[test] 449 | fn parse_errors() { 450 | assert_eq!( 451 | Triple::from_str(""), 452 | Err(ParseError::UnrecognizedArchitecture("".to_owned())) 453 | ); 454 | assert_eq!( 455 | Triple::from_str("foo"), 456 | Err(ParseError::UnrecognizedArchitecture("foo".to_owned())) 457 | ); 458 | assert_eq!( 459 | Triple::from_str("unknown-unknown-foo"), 460 | Err(ParseError::UnrecognizedOperatingSystem("foo".to_owned())) 461 | ); 462 | assert_eq!( 463 | Triple::from_str("unknown-unknown-unknown-foo"), 464 | Err(ParseError::UnrecognizedEnvironment("foo".to_owned())) 465 | ); 466 | assert_eq!( 467 | Triple::from_str("unknown-unknown-unknown-unknown-foo"), 468 | Err(ParseError::UnrecognizedBinaryFormat("foo".to_owned())) 469 | ); 470 | assert_eq!( 471 | Triple::from_str("unknown-unknown-unknown-unknown-unknown-foo"), 472 | Err(ParseError::UnrecognizedField("foo".to_owned())) 473 | ); 474 | } 475 | 476 | #[test] 477 | fn defaults() { 478 | assert_eq!( 479 | Triple::from_str("unknown-unknown-unknown"), 480 | Ok(Triple::unknown()) 481 | ); 482 | assert_eq!( 483 | Triple::from_str("unknown-unknown-unknown-unknown"), 484 | Ok(Triple::unknown()) 485 | ); 486 | assert_eq!( 487 | Triple::from_str("unknown-unknown-unknown-unknown-unknown"), 488 | Ok(Triple::unknown()) 489 | ); 490 | } 491 | 492 | #[test] 493 | fn unknown_properties() { 494 | assert_eq!(Triple::unknown().endianness(), Err(())); 495 | assert_eq!(Triple::unknown().pointer_width(), Err(())); 496 | assert_eq!(Triple::unknown().default_calling_convention(), Err(())); 497 | } 498 | 499 | #[test] 500 | fn apple_calling_convention() { 501 | for triple in &[ 502 | "aarch64-apple-darwin", 503 | "aarch64-apple-ios", 504 | "aarch64-apple-ios-macabi", 505 | "aarch64-apple-tvos", 506 | "aarch64-apple-watchos", 507 | ] { 508 | let triple = Triple::from_str(triple).unwrap(); 509 | assert_eq!( 510 | triple.default_calling_convention().unwrap(), 511 | CallingConvention::AppleAarch64 512 | ); 513 | assert_eq!(triple.data_model().unwrap(), CDataModel::LP64); 514 | } 515 | 516 | for triple in &["aarch64-linux-android", "x86_64-apple-ios"] { 517 | assert_eq!( 518 | Triple::from_str(triple) 519 | .unwrap() 520 | .default_calling_convention() 521 | .unwrap(), 522 | CallingConvention::SystemV 523 | ); 524 | } 525 | } 526 | 527 | #[test] 528 | fn p32_abi() { 529 | // Test that special 32-bit pointer ABIs on 64-bit architectures are 530 | // reported as having 32-bit pointers. 531 | for triple in &[ 532 | "x86_64-unknown-linux-gnux32", 533 | "aarch64_be-unknown-linux-gnu_ilp32", 534 | "aarch64-unknown-linux-gnu_ilp32", 535 | ] { 536 | assert_eq!( 537 | Triple::from_str(triple).unwrap().pointer_width().unwrap(), 538 | PointerWidth::U32 539 | ); 540 | } 541 | 542 | // Test that the corresponding ABIs have 64-bit pointers. 543 | for triple in &[ 544 | "x86_64-unknown-linux-gnu", 545 | "aarch64_be-unknown-linux-gnu", 546 | "aarch64-unknown-linux-gnu", 547 | ] { 548 | assert_eq!( 549 | Triple::from_str(triple).unwrap().pointer_width().unwrap(), 550 | PointerWidth::U64 551 | ); 552 | } 553 | } 554 | } 555 | --------------------------------------------------------------------------------