Skip to content

Commit 77069b4

Browse files
committed
Auto merge of #11958 - jyn514:named-debuginfo, r=Muscraft
Allow named debuginfo options in Cargo.toml
2 parents de80432 + dbab134 commit 77069b4

File tree

8 files changed

+246
-44
lines changed

8 files changed

+246
-44
lines changed

src/cargo/core/compiler/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ use crate::core::{Feature, PackageId, Target, Verbosity};
9292
use crate::util::errors::{CargoResult, VerboseError};
9393
use crate::util::interning::InternedString;
9494
use crate::util::machine_message::{self, Message};
95+
use crate::util::toml::TomlDebugInfo;
9596
use crate::util::{add_path_args, internal, iter_join_onto, profile};
9697
use cargo_util::{paths, ProcessBuilder, ProcessError};
9798
use rustfix::diagnostics::Applicability;
@@ -603,9 +604,20 @@ fn link_targets(cx: &mut Context<'_, '_>, unit: &Unit, fresh: bool) -> CargoResu
603604
}
604605

605606
if json_messages {
607+
let debuginfo = profile.debuginfo.to_option().map(|d| match d {
608+
TomlDebugInfo::None => machine_message::ArtifactDebuginfo::Int(0),
609+
TomlDebugInfo::Limited => machine_message::ArtifactDebuginfo::Int(1),
610+
TomlDebugInfo::Full => machine_message::ArtifactDebuginfo::Int(2),
611+
TomlDebugInfo::LineDirectivesOnly => {
612+
machine_message::ArtifactDebuginfo::Named("line-directives-only")
613+
}
614+
TomlDebugInfo::LineTablesOnly => {
615+
machine_message::ArtifactDebuginfo::Named("line-tables-only")
616+
}
617+
});
606618
let art_profile = machine_message::ArtifactProfile {
607619
opt_level: profile.opt_level.as_str(),
608-
debuginfo: profile.debuginfo.to_option(),
620+
debuginfo,
609621
debug_assertions: profile.debug_assertions,
610622
overflow_checks: profile.overflow_checks,
611623
test: unit_mode.is_any_test(),

src/cargo/core/profiles.rs

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ use crate::core::dependency::Artifact;
2626
use crate::core::resolver::features::FeaturesFor;
2727
use crate::core::{PackageId, PackageIdSpec, Resolve, Shell, Target, Workspace};
2828
use crate::util::interning::InternedString;
29-
use crate::util::toml::{ProfilePackageSpec, StringOrBool, TomlProfile, TomlProfiles, U32OrBool};
29+
use crate::util::toml::{
30+
ProfilePackageSpec, StringOrBool, TomlDebugInfo, TomlProfile, TomlProfiles,
31+
};
3032
use crate::util::{closest_msg, config, CargoResult, Config};
3133
use anyhow::{bail, Context as _};
3234
use std::collections::{BTreeMap, HashMap, HashSet};
@@ -276,15 +278,13 @@ impl Profiles {
276278
// platform which has a stable `-Csplit-debuginfo` option for rustc,
277279
// and it's typically much faster than running `dsymutil` on all builds
278280
// in incremental cases.
279-
if let Some(debug) = profile.debuginfo.to_option() {
280-
if profile.split_debuginfo.is_none() && debug > 0 {
281-
let target = match &kind {
282-
CompileKind::Host => self.rustc_host.as_str(),
283-
CompileKind::Target(target) => target.short_name(),
284-
};
285-
if target.contains("-apple-") {
286-
profile.split_debuginfo = Some(InternedString::new("unpacked"));
287-
}
281+
if profile.debuginfo.is_turned_on() && profile.split_debuginfo.is_none() {
282+
let target = match &kind {
283+
CompileKind::Host => self.rustc_host.as_str(),
284+
CompileKind::Target(target) => target.short_name(),
285+
};
286+
if target.contains("-apple-") {
287+
profile.split_debuginfo = Some(InternedString::new("unpacked"));
288288
}
289289
}
290290

@@ -528,11 +528,8 @@ fn merge_profile(profile: &mut Profile, toml: &TomlProfile) {
528528
if toml.codegen_units.is_some() {
529529
profile.codegen_units = toml.codegen_units;
530530
}
531-
match toml.debug {
532-
Some(U32OrBool::U32(debug)) => profile.debuginfo = DebugInfo::Explicit(debug),
533-
Some(U32OrBool::Bool(true)) => profile.debuginfo = DebugInfo::Explicit(2),
534-
Some(U32OrBool::Bool(false)) => profile.debuginfo = DebugInfo::None,
535-
None => {}
531+
if let Some(debuginfo) = toml.debug {
532+
profile.debuginfo = DebugInfo::Explicit(debuginfo);
536533
}
537534
if let Some(debug_assertions) = toml.debug_assertions {
538535
profile.debug_assertions = debug_assertions;
@@ -683,7 +680,7 @@ impl Profile {
683680
Profile {
684681
name: InternedString::new("dev"),
685682
root: ProfileRoot::Debug,
686-
debuginfo: DebugInfo::Explicit(2),
683+
debuginfo: DebugInfo::Explicit(TomlDebugInfo::Full),
687684
debug_assertions: true,
688685
overflow_checks: true,
689686
incremental: true,
@@ -742,7 +739,7 @@ pub enum DebugInfo {
742739
/// No debuginfo level was set.
743740
None,
744741
/// A debuginfo level that is explicitly set, by a profile or a user.
745-
Explicit(u32),
742+
Explicit(TomlDebugInfo),
746743
/// For internal purposes: a deferred debuginfo level that can be optimized
747744
/// away, but has this value otherwise.
748745
///
@@ -752,22 +749,22 @@ pub enum DebugInfo {
752749
/// faster to build (see [DebugInfo::weaken]).
753750
///
754751
/// In all other situations, this level value will be the one to use.
755-
Deferred(u32),
752+
Deferred(TomlDebugInfo),
756753
}
757754

758755
impl DebugInfo {
759756
/// The main way to interact with this debuginfo level, turning it into an Option.
760-
pub fn to_option(&self) -> Option<u32> {
757+
pub fn to_option(self) -> Option<TomlDebugInfo> {
761758
match self {
762759
DebugInfo::None => None,
763-
DebugInfo::Explicit(v) | DebugInfo::Deferred(v) => Some(*v),
760+
DebugInfo::Explicit(v) | DebugInfo::Deferred(v) => Some(v),
764761
}
765762
}
766763

767-
/// Returns true if the debuginfo level is high enough (at least 1). Helper
764+
/// Returns true if any debuginfo will be generated. Helper
768765
/// for a common operation on the usual `Option` representation.
769766
pub(crate) fn is_turned_on(&self) -> bool {
770-
self.to_option().unwrap_or(0) != 0
767+
!matches!(self.to_option(), None | Some(TomlDebugInfo::None))
771768
}
772769

773770
pub(crate) fn is_deferred(&self) -> bool {

src/cargo/util/machine_message.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,20 @@ impl<'a> Message for Artifact<'a> {
5555
#[derive(Serialize)]
5656
pub struct ArtifactProfile {
5757
pub opt_level: &'static str,
58-
pub debuginfo: Option<u32>,
58+
pub debuginfo: Option<ArtifactDebuginfo>,
5959
pub debug_assertions: bool,
6060
pub overflow_checks: bool,
6161
pub test: bool,
6262
}
6363

64+
/// Internally this is an enum with different variants, but keep using 0/1/2 as integers for compatibility.
65+
#[derive(Serialize)]
66+
#[serde(untagged)]
67+
pub enum ArtifactDebuginfo {
68+
Int(u32),
69+
Named(&'static str),
70+
}
71+
6472
#[derive(Serialize)]
6573
pub struct BuildScript<'a> {
6674
pub package_id: PackageId,

src/cargo/util/toml/mod.rs

Lines changed: 97 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::collections::{BTreeMap, BTreeSet, HashMap};
2-
use std::fmt;
2+
use std::fmt::{self, Display, Write};
33
use std::marker::PhantomData;
44
use std::path::{Path, PathBuf};
55
use std::rc::Rc;
@@ -12,8 +12,8 @@ use itertools::Itertools;
1212
use lazycell::LazyCell;
1313
use log::{debug, trace};
1414
use semver::{self, VersionReq};
15-
use serde::de;
1615
use serde::de::IntoDeserializer as _;
16+
use serde::de::{self, Unexpected};
1717
use serde::ser;
1818
use serde::{Deserialize, Serialize};
1919
use url::Url;
@@ -442,11 +442,100 @@ impl ser::Serialize for TomlOptLevel {
442442
}
443443
}
444444

445-
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
446-
#[serde(untagged, expecting = "expected a boolean or an integer")]
447-
pub enum U32OrBool {
448-
U32(u32),
449-
Bool(bool),
445+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
446+
pub enum TomlDebugInfo {
447+
None,
448+
LineDirectivesOnly,
449+
LineTablesOnly,
450+
Limited,
451+
Full,
452+
}
453+
454+
impl ser::Serialize for TomlDebugInfo {
455+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
456+
where
457+
S: ser::Serializer,
458+
{
459+
match self {
460+
Self::None => 0.serialize(serializer),
461+
Self::LineDirectivesOnly => "line-directives-only".serialize(serializer),
462+
Self::LineTablesOnly => "line-tables-only".serialize(serializer),
463+
Self::Limited => 1.serialize(serializer),
464+
Self::Full => 2.serialize(serializer),
465+
}
466+
}
467+
}
468+
469+
impl<'de> de::Deserialize<'de> for TomlDebugInfo {
470+
fn deserialize<D>(d: D) -> Result<TomlDebugInfo, D::Error>
471+
where
472+
D: de::Deserializer<'de>,
473+
{
474+
struct Visitor;
475+
476+
impl<'de> de::Visitor<'de> for Visitor {
477+
type Value = TomlDebugInfo;
478+
479+
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
480+
formatter.write_str(
481+
"a boolean, 0, 1, 2, \"line-tables-only\", or \"line-directives-only\"",
482+
)
483+
}
484+
485+
fn visit_i64<E>(self, value: i64) -> Result<TomlDebugInfo, E>
486+
where
487+
E: de::Error,
488+
{
489+
let debuginfo = match value {
490+
0 => TomlDebugInfo::None,
491+
1 => TomlDebugInfo::Limited,
492+
2 => TomlDebugInfo::Full,
493+
_ => return Err(de::Error::invalid_value(Unexpected::Signed(value), &self)),
494+
};
495+
Ok(debuginfo)
496+
}
497+
498+
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
499+
where
500+
E: de::Error,
501+
{
502+
Ok(if v {
503+
TomlDebugInfo::Full
504+
} else {
505+
TomlDebugInfo::None
506+
})
507+
}
508+
509+
fn visit_str<E>(self, value: &str) -> Result<TomlDebugInfo, E>
510+
where
511+
E: de::Error,
512+
{
513+
let debuginfo = match value {
514+
"none" => TomlDebugInfo::None,
515+
"limited" => TomlDebugInfo::Limited,
516+
"full" => TomlDebugInfo::Full,
517+
"line-directives-only" => TomlDebugInfo::LineDirectivesOnly,
518+
"line-tables-only" => TomlDebugInfo::LineTablesOnly,
519+
_ => return Err(de::Error::invalid_value(Unexpected::Str(value), &self)),
520+
};
521+
Ok(debuginfo)
522+
}
523+
}
524+
525+
d.deserialize_any(Visitor)
526+
}
527+
}
528+
529+
impl Display for TomlDebugInfo {
530+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
531+
match self {
532+
TomlDebugInfo::None => f.write_char('0'),
533+
TomlDebugInfo::Limited => f.write_char('1'),
534+
TomlDebugInfo::Full => f.write_char('2'),
535+
TomlDebugInfo::LineDirectivesOnly => f.write_str("line-directives-only"),
536+
TomlDebugInfo::LineTablesOnly => f.write_str("line-tables-only"),
537+
}
538+
}
450539
}
451540

452541
#[derive(Deserialize, Serialize, Clone, Debug, Default, Eq, PartialEq)]
@@ -456,7 +545,7 @@ pub struct TomlProfile {
456545
pub lto: Option<StringOrBool>,
457546
pub codegen_backend: Option<InternedString>,
458547
pub codegen_units: Option<u32>,
459-
pub debug: Option<U32OrBool>,
548+
pub debug: Option<TomlDebugInfo>,
460549
pub split_debuginfo: Option<String>,
461550
pub debug_assertions: Option<bool>,
462551
pub rpath: Option<bool>,

src/doc/src/reference/profiles.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,20 @@ amount of debug information included in the compiled binary.
6767

6868
The valid options are:
6969

70-
* `0` or `false`: no debug info at all
71-
* `1`: line tables only
72-
* `2` or `true`: full debug info
70+
* `0`, `false`, or `"none"`: no debug info at all, default for [`release`](#release)
71+
* `"line-directives-only"`: line info directives only. For the nvptx* targets this enables [profiling]. For other use cases, `line-tables-only` is the better, more compatible choice.
72+
* `"line-tables-only"`: line tables only. Generates the minimal amount of debug info for backtraces with filename/line number info, but not anything else, i.e. no variable or function parameter info.
73+
* `1` or `"limited"`: debug info without type or variable-level information. Generates more detailed module-level info than `line-tables-only`.
74+
* `2`, `true`, or `"full"`: full debug info, default for [`dev`](#dev)
75+
76+
For more information on what each option does see `rustc`'s docs on [debuginfo].
7377

7478
You may wish to also configure the [`split-debuginfo`](#split-debuginfo) option
7579
depending on your needs as well.
7680

7781
[`-C debuginfo` flag]: ../../rustc/codegen-options/index.html#debuginfo
82+
[debuginfo]: ../../rustc/codegen-options/index.html#debuginfo
83+
[profiling]: https://reviews.llvm.org/D46061
7884

7985
#### split-debuginfo
8086

tests/testsuite/bad_config.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,14 +1313,46 @@ fn bad_debuginfo() {
13131313
.file("src/lib.rs", "")
13141314
.build();
13151315

1316+
p.cargo("check")
1317+
.with_status(101)
1318+
.with_stderr(
1319+
"\
1320+
error: failed to parse manifest [..]
1321+
1322+
Caused by:
1323+
invalid value: string \"a\", expected a boolean, 0, 1, 2, \"line-tables-only\", or \"line-directives-only\"
1324+
in `profile.dev.debug`
1325+
",
1326+
)
1327+
.run();
1328+
}
1329+
1330+
#[cargo_test]
1331+
fn bad_debuginfo2() {
1332+
let p = project()
1333+
.file(
1334+
"Cargo.toml",
1335+
r#"
1336+
[package]
1337+
name = "foo"
1338+
version = "0.0.0"
1339+
authors = []
1340+
1341+
[profile.dev]
1342+
debug = 3.6
1343+
"#,
1344+
)
1345+
.file("src/lib.rs", "")
1346+
.build();
1347+
13161348
p.cargo("check")
13171349
.with_status(101)
13181350
.with_stderr(
13191351
"\
13201352
error: failed to parse manifest at `[..]`
13211353
13221354
Caused by:
1323-
expected a boolean or an integer
1355+
invalid type: floating point `3.6`, expected a boolean, 0, 1, 2, \"line-tables-only\", or \"line-directives-only\"
13241356
in `profile.dev.debug`
13251357
",
13261358
)

0 commit comments

Comments
 (0)