cargo_subcommand_metadata/
lib.rs

1/// Cargo's name for the purpose of ELF notes.
2///
3/// The `name` field of an ELF note is designated to hold the entry's "owner" or
4/// "originator". No formal mechanism exists for avoiding name conflicts. By
5/// convention, vendors use their own name such as "XYZ Computer Company".
6pub const ELF_NOTE_NAME: &str = "rust-lang/cargo";
7
8/// Values used by Cargo as the `type` of its ELF notes.
9///
10/// Each originator controls its own note types. Multiple interpretations of a
11/// single type value can exist. A program must recognize both the `name` and
12/// the `type` to understand a descriptor.
13#[repr(i32)]
14#[non_exhaustive]
15pub enum ElfNoteType {
16    //              DESCRIP
17    Description = 0xDE5C819,
18}
19
20/// Embed a description into a compiled Cargo subcommand, to be shown by `cargo
21/// --list`.
22///
23/// The following restrictions apply to a subcommand description:
24///
25/// - String length can be at most 280 bytes in UTF-8, although much shorter is
26///   better.
27/// - Must not contain the characters `\n`, `\r`, or `\x1B` (ESC).
28///
29/// Please consider running `cargo --list` and following the style of the
30/// existing descriptions of the built-in Cargo subcommands.
31///
32/// # Example
33///
34/// ```
35/// // subcommand's main.rs
36///
37/// cargo_subcommand_metadata::description! {
38///     "Draw a spiffy visualization of things"
39/// }
40///
41/// fn main() {
42///     /* … */
43/// }
44/// ```
45#[macro_export]
46macro_rules! description {
47    ($description:expr) => {
48        const _: () = {
49            const CARGO_SUBCOMMAND_DESCRIPTION: &str = $description;
50
51            assert!(
52                CARGO_SUBCOMMAND_DESCRIPTION.len() <= 280,
53                "subcommand description too long, must be at most 280",
54            );
55
56            #[cfg(target_os = "linux")]
57            const _: () = {
58                #[repr(C)]
59                struct ElfNote {
60                    namesz: u32,
61                    descsz: u32,
62                    ty: $crate::ElfNoteType,
63
64                    name: [u8; $crate::ELF_NOTE_NAME.len()],
65                    // At least 1 to nul-terminate the string as is convention
66                    // (though not required), plus zero padding to a multiple of 4
67                    // bytes.
68                    name_padding: [$crate::private::Padding;
69                        1 + match ($crate::ELF_NOTE_NAME.len() + 1) % 4 {
70                            0 => 0,
71                            r => 4 - r,
72                        }],
73
74                    desc: [u8; CARGO_SUBCOMMAND_DESCRIPTION.len()],
75                    // Zero padding to a multiple of 4 bytes.
76                    desc_padding: [$crate::private::Padding;
77                        match CARGO_SUBCOMMAND_DESCRIPTION.len() % 4 {
78                            0 => 0,
79                            r => 4 - r,
80                        }],
81                }
82
83                #[used]
84                #[link_section = ".note.cargo.subcommand"]
85                static ELF_NOTE: ElfNote = {
86                    ElfNote {
87                        namesz: $crate::ELF_NOTE_NAME.len() as u32 + 1,
88                        descsz: CARGO_SUBCOMMAND_DESCRIPTION.len() as u32,
89                        ty: $crate::ElfNoteType::Description,
90                        name: unsafe { *$crate::ELF_NOTE_NAME.as_ptr().cast() },
91                        name_padding: $crate::private::padding(),
92                        desc: unsafe { *CARGO_SUBCOMMAND_DESCRIPTION.as_ptr().cast() },
93                        desc_padding: $crate::private::padding(),
94                    }
95                };
96            };
97        };
98    };
99}
100
101// Implementation details. Not public API.
102#[doc(hidden)]
103pub mod private {
104    #[derive(Copy, Clone)]
105    #[repr(u8)]
106    pub enum Padding {
107        Zero = 0,
108    }
109
110    pub const fn padding<const N: usize>() -> [Padding; N] {
111        [Padding::Zero; N]
112    }
113}