[{"data":1,"prerenderedAt":2223},["ShallowReactive",2],{"page-\u002Frust\u002F28-cargo-features":3},{"id":4,"title":5,"body":6,"description":39,"extension":2217,"meta":2218,"navigation":91,"path":2219,"seo":2220,"stem":2221,"__hash__":2222},"content\u002Frust\u002F28-cargo-features.md","28 — Cargo Features",{"type":7,"value":8,"toc":2176},"minimark",[9,13,184,284,371,517,615,765,886,957,1044,1143,1226,1339,1422,1545,1705,1768,1901,1993,2090,2172],[10,11,5],"h1",{"id":12},"_28-cargo-features",[14,15,17,31,78,135],"question-wrapper",{"language":16},"toml",[18,19,21,22,26,27,30],"h3",{"id":20},"q1-what-is-the-correct-way-to-declare-a-feature-named-logging-that-has-no-dependencies-of-its-own-in-cargotoml","Q1. What is the correct way to declare a feature named ",[23,24,25],"code",{},"logging"," that has no dependencies of its own in ",[23,28,29],{},"Cargo.toml","?",[32,33,34],"code-wrapper",{"language":16},[35,36,40],"pre",{"className":37,"code":38,"language":16,"meta":39,"style":39},"language-toml shiki shiki-themes github-light github-dark","[dependencies]\ntracing = { version = \"0.1\", optional = true }\n","",[23,41,42,58],{"__ignoreMap":39},[43,44,47,51,55],"span",{"class":45,"line":46},"line",1,[43,48,50],{"class":49},"ssxIu","[",[43,52,54],{"class":53},"sIsaT","dependencies",[43,56,57],{"class":49},"]\n",[43,59,61,64,68,71,75],{"class":45,"line":60},2,[43,62,63],{"class":49},"tracing = { version = ",[43,65,67],{"class":66},"sJ6F3","\"0.1\"",[43,69,70],{"class":49},", optional = ",[43,72,74],{"class":73},"snvgF","true",[43,76,77],{"class":49}," }\n",[79,80,83,101,113,124],"ul",{"className":81},[82],"contains-task-list",[84,85,88,93,94,97,98],"li",{"className":86},[87],"task-list-item",[89,90],"input",{"disabled":91,"type":92},true,"checkbox"," ",[23,95,96],{},"[features]"," section with ",[23,99,100],{},"logging = []",[84,102,104,93,106,109,110],{"className":103},[87],[89,105],{"disabled":91,"type":92},[23,107,108],{},"[dependencies.logging]"," with ",[23,111,112],{},"optional = true",[84,114,116,93,118,121,122],{"className":115},[87],[89,117],{"disabled":91,"type":92},[23,119,120],{},"logging = true"," at the top level of ",[23,123,29],{},[84,125,127,93,129,109,132],{"className":126},[87],[89,128],{"disabled":91,"type":92},[23,130,131],{},"[profile.logging]",[23,133,134],{},"enabled = true",[136,137,138,142,154],"details",{},[139,140,141],"summary",{},"Show Answer",[143,144,145,149,150,97,152],"p",{},[146,147,148],"strong",{},"Answer:"," A — ",[23,151,96],{},[23,153,100],{},[143,155,156,159,160,162,163,166,167,170,171,173,174,176,177,180,181,183],{},[146,157,158],{},"Explanation:"," Features are declared under a ",[23,161,96],{}," table as ",[23,164,165],{},"name = [list-of-other-features-or-optional-deps-to-enable]","; an empty list is valid for a \"marker\" feature used only in ",[23,168,169],{},"#[cfg(feature = \"logging\")]"," checks. ",[23,172,108],{}," is wrong because features aren't dependencies unless tied to an optional crate. ",[23,175,120],{}," at the top level isn't valid TOML for Cargo's schema. ",[23,178,179],{},"[profile.*]"," tables configure compilation profiles (opt-level, debug info), not feature flags — a common mix-up for newcomers scanning ",[23,182,29],{},".",[14,185,186,198,246],{},[18,187,189,190,193,194,197],{"id":188},"q2-a-crate-declares-serde-version-1-optional-true-under-dependencies-what-happens-by-default","Q2. A crate declares ",[23,191,192],{},"serde = { version = \"1\", optional = true }"," under ",[23,195,196],{},"[dependencies]",". What happens by default?",[79,199,201,211,224,236],{"className":200},[82],[84,202,204,206,207,210],{"className":203},[87],[89,205],{"disabled":91,"type":92}," Cargo implicitly creates a feature named ",[23,208,209],{},"serde"," that enables the dependency",[84,212,214,216,217,220,221],{"className":213},[87],[89,215],{"disabled":91,"type":92}," The dependency is compiled in unconditionally, ",[23,218,219],{},"optional"," only affects ",[23,222,223],{},"cargo doc",[84,225,227,229,230,232,233,235],{"className":226},[87],[89,228],{"disabled":91,"type":92}," The build fails until a matching ",[23,231,96],{}," entry named ",[23,234,209],{}," is added manually",[84,237,239,241,242,245],{"className":238},[87],[89,240],{"disabled":91,"type":92}," The dependency is never compiled unless explicitly named in ",[23,243,244],{},"[build-dependencies]"," too",[136,247,248,250,257],{},[139,249,141],{},[143,251,252,254,255,210],{},[146,253,148],{}," A — Cargo implicitly creates a feature named ",[23,256,209],{},[143,258,259,261,262,264,265,267,268,271,272,276,277,280,281,283],{},[146,260,158],{}," Marking a dependency ",[23,263,112],{}," automatically creates an implicit feature of the same name; enabling that feature pulls in the crate. No manual ",[23,266,96],{}," entry is required (though on the 2021 edition you can opt into requiring the explicit ",[23,269,270],{},"dep:serde"," syntax to ",[273,274,275],"em",{},"suppress"," that implicit feature — see the ",[23,278,279],{},"dep:"," question later in this quiz). It doesn't compile unconditionally, and it has nothing to do with ",[23,282,244],{},", which is a separate dependency graph for build scripts.",[14,285,286,294,329],{},[18,287,289,290,293],{"id":288},"q3-which-flag-builds-a-crate-with-its-default-feature-set-disabled","Q3. Which flag builds a crate with its ",[23,291,292],{},"default"," feature set disabled?",[79,295,297,305,313,321],{"className":296},[82],[84,298,300,93,302],{"className":299},[87],[89,301],{"disabled":91,"type":92},[23,303,304],{},"cargo build --no-default-features",[84,306,308,93,310],{"className":307},[87],[89,309],{"disabled":91,"type":92},[23,311,312],{},"cargo build --features=none",[84,314,316,93,318],{"className":315},[87],[89,317],{"disabled":91,"type":92},[23,319,320],{},"cargo build --default-features=false",[84,322,324,93,326],{"className":323},[87],[89,325],{"disabled":91,"type":92},[23,327,328],{},"cargo build --minimal",[136,330,331,333,339],{},[139,332,141],{},[143,334,335,149,337],{},[146,336,148],{},[23,338,304],{},[143,340,341,93,343,346,347,350,351,354,355,358,359,362,363,366,367,370],{},[146,342,158],{},[23,344,345],{},"--no-default-features"," opts out of whatever ",[23,348,349],{},"[features] default = [...]"," lists; you then opt back in to specific features with ",[23,352,353],{},"--features",". ",[23,356,357],{},"--default-features=false"," is invalid CLI syntax (that phrasing only exists as a Cargo.toml dependency table key, not a top-level flag), ",[23,360,361],{},"--features=none"," just tries to enable a feature literally named ",[23,364,365],{},"none",", and ",[23,368,369],{},"--minimal"," isn't a real Cargo flag.",[14,372,373,380,428,480],{"language":16},[18,374,376,377,379],{"id":375},"q4-in-cargotoml-what-does-this-dependency-declaration-mean","Q4. In ",[23,378,29],{},", what does this dependency declaration mean?",[32,381,382],{"language":16},[35,383,385],{"className":37,"code":384,"language":16,"meta":39,"style":39},"[dependencies.reqwest]\nversion = \"0.11\"\ndefault-features = false\nfeatures = [\"json\"]\n",[23,386,387,400,408,417],{"__ignoreMap":39},[43,388,389,391,393,395,398],{"class":45,"line":46},[43,390,50],{"class":49},[43,392,54],{"class":53},[43,394,183],{"class":49},[43,396,397],{"class":53},"reqwest",[43,399,57],{"class":49},[43,401,402,405],{"class":45,"line":60},[43,403,404],{"class":49},"version = ",[43,406,407],{"class":66},"\"0.11\"\n",[43,409,411,414],{"class":45,"line":410},3,[43,412,413],{"class":49},"default-features = ",[43,415,416],{"class":73},"false\n",[43,418,420,423,426],{"class":45,"line":419},4,[43,421,422],{"class":49},"features = [",[43,424,425],{"class":66},"\"json\"",[43,427,57],{"class":49},[79,429,431,444,455,466],{"className":430},[82],[84,432,434,436,437,439,440,443],{"className":433},[87],[89,435],{"disabled":91,"type":92}," Depend on ",[23,438,397],{}," with its own defaults disabled, enabling only the ",[23,441,442],{},"json"," feature",[84,445,447,436,449,451,452,454],{"className":446},[87],[89,448],{"disabled":91,"type":92},[23,450,397],{}," with all features enabled, then filter down to ",[23,453,442],{}," at link time",[84,456,458,93,460,463,464],{"className":457},[87],[89,459],{"disabled":91,"type":92},[23,461,462],{},"default-features = false"," disables features for the whole workspace, not just ",[23,465,397],{},[84,467,469,471,472,475,476,479],{"className":468},[87],[89,470],{"disabled":91,"type":92}," This is a syntax error; ",[23,473,474],{},"features"," and ",[23,477,478],{},"default-features"," cannot appear together",[136,481,482,484,493],{},[139,483,141],{},[143,485,486,488,489,439,491,443],{},[146,487,148],{}," A — Depend on ",[23,490,397],{},[23,492,442],{},[143,494,495,93,497,499,500,503,504,506,507,93,510,512,513,516],{},[146,496,158],{},[23,498,462],{}," on a ",[273,501,502],{},"specific dependency entry"," opts that dependency out of its own ",[23,505,292],{}," feature set (defined in ",[273,508,509],{},"its",[23,511,29],{},"), scoped only to that dependency — it has no effect on the current crate's own features or the workspace. ",[23,514,515],{},"features = [\"json\"]"," then explicitly turns on just that one. The two keys commonly appear together and are not mutually exclusive; there's nothing resembling \"filtering at link time.\"",[14,518,519,546,582],{},[18,520,522,523,526,527,109,530,533,534,537,538,109,540,542,543,545],{"id":521},"q5-crate-a-depends-on-net-lib-with-features-tls-crate-b-a-sibling-dependency-in-the-same-build-depends-on-net-lib-with-default-features-false-and-no-extra-features-both-end-up-in-the-same-final-binary-what-features-does-net-lib-actually-get-compiled-with","Q5. Crate ",[23,524,525],{},"A"," depends on ",[23,528,529],{},"net-lib",[23,531,532],{},"features = [\"tls\"]",". Crate ",[23,535,536],{},"B"," (a sibling dependency in the same build) depends on ",[23,539,529],{},[23,541,462],{}," and no extra features. Both end up in the same final binary. What features does ",[23,544,529],{}," actually get compiled with?",[79,547,549,559,568,576],{"className":548},[82],[84,550,552,554,555,558],{"className":551},[87],[89,553],{"disabled":91,"type":92}," Only ",[23,556,557],{},"tls"," — Cargo unifies to the union of all requested features across the graph",[84,560,562,564,565,567],{"className":561},[87],[89,563],{"disabled":91,"type":92}," Neither — ",[23,566,462],{}," from B overrides A's request",[84,569,571,93,573,575],{"className":570},[87],[89,572],{"disabled":91,"type":92},[23,574,529],{}," is compiled twice, once per requested feature set",[84,577,579,581],{"className":578},[87],[89,580],{"disabled":91,"type":92}," The build fails with a \"conflicting feature requirements\" error",[136,583,584,586,593],{},[139,585,141],{},[143,587,588,590,591,558],{},[146,589,148],{}," A — Only ",[23,592,557],{},[143,594,595,93,597,600,601,604,605,607,608,610,611,614],{},[146,596,158],{},[146,598,599],{},"Safety\u002FIdiom:"," Cargo compiles each version of a dependency exactly once per build graph, so it must reconcile every requester's feature request into a single set — it takes the ",[273,602,603],{},"union",". B's ",[23,606,462],{}," only says \"don't turn on ",[23,609,529],{},"'s own defaults ",[273,612,613],{},"for my request","\"; it can't retract a feature that A separately asked for. This is the classic \"feature unification\" footgun: you cannot rely on disabling defaults to shrink a dependency if any other crate in the graph re-enables them. There's no per-requester recompilation and no conflict error — features are required to be purely additive for exactly this reason.",[14,616,617,628,681,724],{"language":16},[18,618,620,621,624,625,627],{"id":619},"q6-a-library-crate-wants-an-optional-dependency-regex-available-for-internal-use-but-does-not-want-a-public-feature-named-regex-to-appear-in-its-feature-list-to-avoid-it-being-confused-with-a-user-facing-toggle-which-mechanism-achieves-this","Q6. A library crate wants an optional dependency ",[23,622,623],{},"regex"," available for internal use, but does NOT want a public feature named ",[23,626,623],{}," to appear in its feature list (to avoid it being confused with a user-facing toggle). Which mechanism achieves this?",[32,629,630],{"language":16},[35,631,633],{"className":37,"code":632,"language":16,"meta":39,"style":39},"[dependencies]\nregex = { version = \"1\", optional = true }\n\n[features]\nsearch = [\"dep:regex\"]\n",[23,634,635,643,657,662,670],{"__ignoreMap":39},[43,636,637,639,641],{"class":45,"line":46},[43,638,50],{"class":49},[43,640,54],{"class":53},[43,642,57],{"class":49},[43,644,645,648,651,653,655],{"class":45,"line":60},[43,646,647],{"class":49},"regex = { version = ",[43,649,650],{"class":66},"\"1\"",[43,652,70],{"class":49},[43,654,74],{"class":73},[43,656,77],{"class":49},[43,658,659],{"class":45,"line":410},[43,660,661],{"emptyLinePlaceholder":91},"\n",[43,663,664,666,668],{"class":45,"line":419},[43,665,50],{"class":49},[43,667,474],{"class":53},[43,669,57],{"class":49},[43,671,673,676,679],{"class":45,"line":672},5,[43,674,675],{"class":49},"search = [",[43,677,678],{"class":66},"\"dep:regex\"",[43,680,57],{"class":49},[79,682,684,699,709,718],{"className":683},[82],[84,685,687,689,690,693,694,696,697,443],{"className":686},[87],[89,688],{"disabled":91,"type":92}," The ",[23,691,692],{},"dep:regex"," syntax in ",[23,695,96],{},", which suppresses the automatic implicit ",[23,698,623],{},[84,700,702,704,705,708],{"className":701},[87],[89,703],{"disabled":91,"type":92}," Renaming the crate import with ",[23,706,707],{},"package = \"regex\""," under a different key",[84,710,712,714,715],{"className":711},[87],[89,713],{"disabled":91,"type":92}," Marking the dependency ",[23,716,717],{},"optional = true, hidden = true",[84,719,721,723],{"className":720},[87],[89,722],{"disabled":91,"type":92}," There is no way to do this; every optional dependency always gets a public feature",[136,725,726,728,739],{},[139,727,141],{},[143,729,730,732,733,693,735,696,737,443],{},[146,731,148],{}," A — The ",[23,734,692],{},[23,736,96],{},[23,738,623],{},[143,740,741,743,744,746,747,749,750,753,754,757,758,761,762,764],{},[146,742,158],{}," Since the 2021 edition's feature resolver, referencing an optional dependency as ",[23,745,692],{}," inside any ",[23,748,96],{}," entry suppresses the automatic implicit feature of the same name, letting you expose only ",[23,751,752],{},"search"," publicly while still gating the dependency internally. ",[23,755,756],{},"hidden = true"," isn't a real Cargo.toml key. Renaming via ",[23,759,760],{},"package ="," changes which crate is pulled in under a local name, it doesn't touch feature visibility. Before this mechanism existed, optional deps unavoidably created a same-named public feature — that's exactly the gap ",[23,763,279],{}," was added to close.",[14,766,767,775,837],{},[18,768,770,771,774],{"id":769},"q7-what-is-the-idiomatic-way-to-express-this-crate-is-no_std-unless-a-feature-is-enabled","Q7. What is the idiomatic way to express \"this crate is ",[23,772,773],{},"no_std"," unless a feature is enabled\"?",[79,776,778,801,813,828],{"className":777},[82],[84,779,781,783,784,787,788,790,791,794,795,797,798],{"className":780},[87],[89,782],{"disabled":91,"type":92}," Add a feature (e.g. ",[23,785,786],{},"std",") that, when enabled, brings in ",[23,789,786],{},"; keep the crate ",[23,792,793],{},"#![no_std]"," by default and gate ",[23,796,786],{},"-only code behind ",[23,799,800],{},"#[cfg(feature = \"std\")]",[84,802,804,806,807,809,810,812],{"className":803},[87],[89,805],{"disabled":91,"type":92}," Add a feature named ",[23,808,773],{}," that disables ",[23,811,786],{}," when enabled",[84,814,816,818,819,821,822,825,826],{"className":815},[87],[89,817],{"disabled":91,"type":92}," Use ",[23,820,462],{}," in the crate's own ",[23,823,824],{},"[package]"," section to disable ",[23,827,786],{},[84,829,831,833,834,836],{"className":830},[87],[89,832],{"disabled":91,"type":92}," It cannot be done — ",[23,835,773],{}," must be a fixed, unconditional attribute",[136,838,839,841,854],{},[139,840,141],{},[143,842,843,845,846,848,849,851,852],{},[146,844,148],{}," A — Add a positive ",[23,847,786],{}," feature; stay ",[23,850,793],{}," by default and gate on ",[23,853,800],{},[143,855,856,93,858,861,862,864,865,93,868,870,871,873,874,876,877,879,880,882,883,885],{},[146,857,158],{},[146,859,860],{},"Idiom:"," Cargo features must be additive\u002Funification-safe — enabling a feature can only ever add capability, never remove it, because unification takes the union across the whole graph. A ",[23,863,773],{}," feature that ",[273,866,867],{},"removes",[23,869,786],{}," support when turned on would break the instant two crates in the graph disagree (one wants ",[23,872,786],{},", one wants \"not std\" — unification would nonsensically enable both). The idiomatic pattern flips the polarity: the crate is minimal (",[23,875,773],{},") by default, and an additive ",[23,878,786],{}," feature unlocks more. ",[23,881,462],{}," in ",[23,884,824],{}," isn't a valid key — that phrasing only applies to dependency entries.",[14,887,888,902,932],{},[18,889,891,892,894,895,475,898,901],{"id":890},"q8-a-features-table-defines-backend-a-and-backend-b-and-the-crates-code-assumes-exactly-one-is-active-panicking-or-producing-nonsensical-output-if-both-are-compiled-in-at-once-a-downstream-users-dependency-graph-ends-up-unifying-both-features-on-what-is-the-actual-build-time-outcome","Q8. A ",[23,893,96],{}," table defines ",[23,896,897],{},"backend-a = []",[23,899,900],{},"backend-b = []",", and the crate's code assumes exactly one is active, panicking or producing nonsensical output if both are compiled in at once. A downstream user's dependency graph ends up unifying both features on. What is the actual build-time outcome?",[79,903,905,911,920,926],{"className":904},[82],[84,906,908,910],{"className":907},[87],[89,909],{"disabled":91,"type":92}," Cargo compiles successfully with both features enabled — Cargo has no built-in concept of mutually exclusive features",[84,912,914,916,917,919],{"className":913},[87],[89,915],{"disabled":91,"type":92}," Cargo automatically detects the conflict from the ",[23,918,96],{}," table shape and refuses to build",[84,921,923,925],{"className":922},[87],[89,924],{"disabled":91,"type":92}," Cargo picks whichever feature was requested first in the dependency graph and silently ignores the other",[84,927,929,931],{"className":928},[87],[89,930],{"disabled":91,"type":92}," Cargo emits a warning but disables both features to avoid ambiguity",[136,933,934,936,941],{},[139,935,141],{},[143,937,938,940],{},[146,939,148],{}," A — Cargo compiles successfully; it has no built-in concept of mutually exclusive features",[143,942,943,93,945,948,949,952,953,956],{},[146,944,158],{},[146,946,947],{},"Safety:"," Cargo's feature system was designed to be purely additive so unification always has a well-defined answer (the union); it has no syntax for declaring two features as mutually exclusive, and it will happily enable both if any two crates in the graph disagree. If the crate author needs a hard failure, the idiom is to add ",[23,950,951],{},"compile_error!(\"backend-a and backend-b are mutually exclusive\")"," inside a ",[23,954,955],{},"#[cfg(all(feature = \"backend-a\", feature = \"backend-b\"))]"," block so misuse fails loudly at compile time instead of silently misbehaving at runtime. Cargo does not pick a winner or auto-disable — that would violate the additive guarantee other tooling relies on.",[14,958,959,979,1014],{},[18,960,962,963,109,966,968,969,972,973,975,976,978],{"id":961},"q9-a-binary-crate-depends-on-image-with-default-features-false-in-hopes-of-dropping-the-heavy-png-default-codec-another-dependency-deeper-in-the-graph-pulls-in-image-with-its-regular-defaults-after-unification-is-png-support-present-in-the-final-binary","Q9. A binary crate depends on ",[23,964,965],{},"image",[23,967,462],{}," in hopes of dropping the (heavy) ",[23,970,971],{},"png"," default codec. Another dependency deeper in the graph pulls in ",[23,974,965],{}," with its regular defaults. After unification, is ",[23,977,971],{}," support present in the final binary?",[79,980,982,991,1000,1008],{"className":981},[82],[84,983,985,987,988,990],{"className":984},[87],[89,986],{"disabled":91,"type":92}," Yes — because the other dependency's request for defaults wins the union, ",[23,989,462],{}," cannot retract it",[84,992,994,996,997,999],{"className":993},[87],[89,995],{"disabled":91,"type":92}," No — ",[23,998,462],{}," anywhere in the graph always wins and strips defaults for everyone",[84,1001,1003,1005,1006],{"className":1002},[87],[89,1004],{"disabled":91,"type":92}," It depends on declaration order in ",[23,1007,29],{},[84,1009,1011,1013],{"className":1010},[87],[89,1012],{"disabled":91,"type":92}," No — Cargo deduplicates by intersecting feature requests, not unioning them",[136,1015,1016,1018,1023],{},[139,1017,141],{},[143,1019,1020,1022],{},[146,1021,148],{}," A — Yes; the other dependency's request for defaults wins the union",[143,1024,1025,93,1027,1030,1031,1033,1034,1037,1038,1040,1041,1043],{},[146,1026,158],{},[146,1028,1029],{},"Performance:"," This is a widely-hit real-world footgun: ",[23,1032,462],{}," is a per-requester opt-out, not a graph-wide veto. Because unification takes the union of every requester's features, as soon as ",[273,1035,1036],{},"any"," crate in the graph asks for ",[23,1039,965],{},"'s defaults, they're included in the single shared compilation — your own ",[23,1042,462],{}," only means \"I personally don't require them,\" not \"disable them globally.\" The only reliable fix is to get the other dependency changed (or patched\u002Fforked) to also opt out, or to avoid depending on the offending crate. There is no declaration-order tiebreak and no intersection semantics — it's always a union.",[14,1045,1046,1065,1100],{},[18,1047,1049,1050,1053,1054,1057,1058,475,1061,1064],{"id":1048},"q10-a-crate-has-features-full-net-db-compress-if-a-user-builds-with-cargo-build-features-net-which-of-db-and-compress-get-enabled","Q10. A crate has ",[23,1051,1052],{},"[features] full = [\"net\", \"db\", \"compress\"]",". If a user builds with ",[23,1055,1056],{},"cargo build --features net",", which of ",[23,1059,1060],{},"db",[23,1062,1063],{},"compress"," get enabled?",[79,1066,1068,1077,1086,1094],{"className":1067},[82],[84,1069,1071,564,1073,1076],{"className":1070},[87],[89,1072],{"disabled":91,"type":92},[23,1074,1075],{},"full"," is just an alias that itself must be explicitly requested to pull in its members",[84,1078,1080,1082,1083,1085],{"className":1079},[87],[89,1081],{"disabled":91,"type":92}," Both — enabling any member of ",[23,1084,1075],{}," retroactively enables the whole group",[84,1087,1089,554,1091,1093],{"className":1088},[87],[89,1090],{"disabled":91,"type":92},[23,1092,1060],{},", because it's listed second",[84,1095,1097,1099],{"className":1096},[87],[89,1098],{"disabled":91,"type":92}," It's a compile error to request a partial subset of a feature group",[136,1101,1102,1104,1112],{},[139,1103,141],{},[143,1105,1106,1108,1109,1111],{},[146,1107,148],{}," A — Neither; ",[23,1110,1075],{}," is just an alias and must itself be requested",[143,1113,1114,1116,1117,1120,1121,93,1123,1126,1127,1130,1131,1133,1134,1136,1137,1139,1140,1142],{},[146,1115,158],{}," A feature entry like ",[23,1118,1119],{},"full = [\"net\", \"db\", \"compress\"]"," defines a one-directional relationship: turning ",[23,1122,1075],{},[273,1124,1125],{},"on"," turns those three on. It says nothing about the reverse — enabling ",[23,1128,1129],{},"net"," alone has no effect on ",[23,1132,1075],{},", ",[23,1135,1060],{},", or ",[23,1138,1063],{},". This trips people up because they expect feature \"groups\" to behave symmetrically; in reality ",[23,1141,1075],{}," is nothing more than syntactic sugar for \"enable these three together,\" requested independently like any other feature.",[14,1144,1145,1167,1194],{},[18,1146,1148,1149,1152,1153,1156,1157,1159,1160,1163,1164,30],{"id":1147},"q11-a-crate-lists-criterion-05-only-under-dev-dependencies-not-under-dependencies-can-library-code-non-test-non-bench-reference-criterion-when-the-crate-is-built-normally-with-cargo-build","Q11. A crate lists ",[23,1150,1151],{},"criterion = \"0.5\""," only under ",[23,1154,1155],{},"[dev-dependencies]",", not under ",[23,1158,196],{},". Can library code (non-test, non-bench) reference ",[23,1161,1162],{},"criterion"," when the crate is built normally with ",[23,1165,1166],{},"cargo build",[79,1168,1170,1176,1182,1188],{"className":1169},[82],[84,1171,1173,1175],{"className":1172},[87],[89,1174],{"disabled":91,"type":92}," No — dev-dependencies are only available to tests, examples, and benchmarks, not the library target during a normal build",[84,1177,1179,1181],{"className":1178},[87],[89,1180],{"disabled":91,"type":92}," Yes — dev-dependencies are merged into the normal dependency graph automatically",[84,1183,1185,1187],{"className":1184},[87],[89,1186],{"disabled":91,"type":92}," Only if a matching feature flag with the same name is also enabled",[84,1189,1191,1193],{"className":1190},[87],[89,1192],{"disabled":91,"type":92}," Only in debug builds; release builds strip dev-dependencies but still link them in debug",[136,1195,1196,1198,1203],{},[139,1197,141],{},[143,1199,1200,1202],{},[146,1201,148],{}," A — No; dev-dependencies are only available to tests, examples, and benchmarks",[143,1204,1205,93,1207,1209,1210,1133,1213,1133,1216,1219,1220,1222,1223,1225],{},[146,1206,158],{},[23,1208,1155],{}," populate a separate graph used only when building test\u002Fbench\u002Fexample targets (",[23,1211,1212],{},"cargo test",[23,1214,1215],{},"cargo bench",[23,1217,1218],{},"cargo run --example","); they are not linked into the library or binary artifact produced by a plain ",[23,1221,1166],{},", and downstream consumers of your published crate never see them at all. This is why crates.io rejects a ",[23,1224,29],{}," where library source references a dev-only dependency — it simply won't resolve outside test builds. There's no feature-flag coupling and no debug\u002Frelease distinction here; the separation is by target kind, not build profile.",[14,1227,1228,1239,1286],{},[18,1229,1231,1232,1235,1236,1238],{"id":1230},"q12-inside-a-buildrs-script-what-is-the-correct-way-to-check-whether-the-feature-json-is-enabled-for-the-crate-being-built","Q12. Inside a ",[23,1233,1234],{},"build.rs"," script, what is the correct way to check whether the feature ",[23,1237,442],{}," is enabled for the crate being built?",[79,1240,1242,1252,1263,1277],{"className":1241},[82],[84,1243,1245,1247,1248,1251],{"className":1244},[87],[89,1246],{"disabled":91,"type":92}," Read the ",[23,1249,1250],{},"CARGO_FEATURE_JSON"," environment variable",[84,1253,1255,818,1257,1260,1261],{"className":1254},[87],[89,1256],{"disabled":91,"type":92},[23,1258,1259],{},"#[cfg(feature = \"json\")]"," directly inside ",[23,1262,1234],{},[84,1264,1266,1268,1269,1272,1273,1276],{"className":1265},[87],[89,1267],{"disabled":91,"type":92}," Call ",[23,1270,1271],{},"cargo::features::is_enabled(\"json\")"," from the ",[23,1274,1275],{},"cargo"," crate",[84,1278,1280,1282,1283,1285],{"className":1279},[87],[89,1281],{"disabled":91,"type":92}," Parse ",[23,1284,29],{}," manually since features aren't otherwise visible to build scripts",[136,1287,1288,1290,1297],{},[139,1289,141],{},[143,1291,1292,1294,1295,1251],{},[146,1293,148],{}," A — Read the ",[23,1296,1250],{},[143,1298,1299,93,1301,1304,1305,1307,1308,1311,1312,1314,1315,1317,1318,1321,1322,1325,1326,1328,1329,1332,1333,1335,1336,1338],{},[146,1300,158],{},[146,1302,1303],{},"Debug:"," Cargo exposes each enabled feature to ",[23,1306,1234],{}," as an environment variable named ",[23,1309,1310],{},"CARGO_FEATURE_\u003CFEATURE_NAME_UPPERCASE_WITH_UNDERSCORES>"," (e.g. ",[23,1313,442],{}," → ",[23,1316,1250],{},"), set to ",[23,1319,1320],{},"1"," when enabled and absent otherwise. ",[23,1323,1324],{},"#[cfg(feature = ...)]"," doesn't apply here because ",[23,1327,1234],{}," is compiled and run as a ",[273,1330,1331],{},"separate"," program before the crate itself, under a different cfg context — a mistake newcomers make constantly. There's no such ",[23,1334,1275],{}," crate API for this, and manually parsing ",[23,1337,29],{}," is unnecessary and fragile since Cargo already does the resolution and hands you the answer via env vars.",[14,1340,1341,1348,1385],{},[18,1342,1344,1345,1347],{"id":1343},"q13-running-plain-cargo-doc-no-extra-flags-on-a-crate-with-several-feature-gated-public-items-what-shows-up-in-the-generated-documentation-for-those-items","Q13. Running plain ",[23,1346,223],{}," (no extra flags) on a crate with several feature-gated public items — what shows up in the generated documentation for those items?",[79,1349,1351,1357,1366,1379],{"className":1350},[82],[84,1352,1354,1356],{"className":1353},[87],[89,1355],{"disabled":91,"type":92}," Only items reachable under the crate's default feature set; feature-gated items behind non-default features are omitted",[84,1358,1360,1362,1363,1365],{"className":1359},[87],[89,1361],{"disabled":91,"type":92}," All items regardless of feature gating — ",[23,1364,223],{}," always compiles with every feature enabled",[84,1367,1369,1371,1372,1374,1375,1378],{"className":1368},[87],[89,1370],{"disabled":91,"type":92}," Nothing — ",[23,1373,223],{}," requires ",[23,1376,1377],{},"--all-features"," to produce any output at all",[84,1380,1382,1384],{"className":1381},[87],[89,1383],{"disabled":91,"type":92}," Feature-gated items appear but are rendered with strikethrough text automatically",[136,1386,1387,1389,1394],{},[139,1388,141],{},[143,1390,1391,1393],{},[146,1392,148],{}," A — Only items reachable under the crate's default feature set",[143,1395,1396,93,1398,1400,1401,1403,1404,1406,1407,1410,1411,1414,1415,1418,1419,1421],{},[146,1397,158],{},[23,1399,223],{}," builds documentation the same way ",[23,1402,1166],{}," compiles code: using whatever feature set is active for the invocation, which defaults to the ",[23,1405,292],{}," feature list. Items behind non-default ",[23,1408,1409],{},"#[cfg(feature = \"...\")]"," gates simply don't exist in that compilation and so never reach the doc generator. To document everything, maintainers run ",[23,1412,1413],{},"cargo doc --all-features"," (or docs.rs's ",[23,1416,1417],{},"[package.metadata.docs.rs] all-features = true"," config). Plain ",[23,1420,223],{}," does not fail on zero features, and there's no automatic strikethrough rendering for gated items.",[14,1423,1424,1465,1517],{},[18,1425,1427,1428,475,1431,1434,1435,354,1437,1439,1440,1442,1443,1445,1446,1449,1450,1452,1453,1456,1457,1459,1460,1439,1462,1464],{"id":1426},"q14-a-workspace-has-two-member-crates-app-and-lib-both-depending-on-serde-apps-cargotoml-requests-serde-with-the-derive-feature-libs-does-not-when-building-the-whole-workspace-with-cargo-build-workspace-does-libs-compilation-unit-get-serdes-derive-feature","Q14. A workspace has two member crates, ",[23,1429,1430],{},"app",[23,1432,1433],{},"lib",", both depending on ",[23,1436,209],{},[23,1438,1430],{},"'s ",[23,1441,29],{}," requests ",[23,1444,209],{}," with the ",[23,1447,1448],{},"derive"," feature; ",[23,1451,1433],{},"'s does not. When building the whole workspace with ",[23,1454,1455],{},"cargo build --workspace",", does ",[23,1458,1433],{},"'s compilation unit get ",[23,1461,209],{},[23,1463,1448],{}," feature?",[79,1466,1468,1481,1487,1503],{"className":1467},[82],[84,1469,1471,1473,1474,1477,1478,1480],{"className":1470},[87],[89,1472],{"disabled":91,"type":92}," Yes — feature unification happens across the whole workspace build by default, so ",[23,1475,1476],{},"serde\u002Fderive"," is active everywhere ",[23,1479,209],{}," is used in that build",[84,1482,1484,1486],{"className":1483},[87],[89,1485],{"disabled":91,"type":92}," No — each workspace member is compiled with only the features it explicitly lists",[84,1488,1490,1492,1493,1495,1496,1498,1499,1502],{"className":1489},[87],[89,1491],{"disabled":91,"type":92}," Only if ",[23,1494,1433],{}," is listed before ",[23,1497,1430],{}," in the workspace ",[23,1500,1501],{},"[members]"," array",[84,1504,1506,1508,1509,1512,1513,1516],{"className":1505},[87],[89,1507],{"disabled":91,"type":92}," It depends on whether ",[23,1510,1511],{},"resolver = \"1\""," or ",[23,1514,1515],{},"\"2\""," is set, but resolver 2 disables unification entirely",[136,1518,1519,1521,1526],{},[139,1520,141],{},[143,1522,1523,1525],{},[146,1524,148],{}," A — Yes, feature unification applies across the whole workspace build by default",[143,1527,1528,1530,1531,1533,1534,1537,1538,1541,1542,1544],{},[146,1529,158],{}," When multiple workspace members share a dependency and are built together in one ",[23,1532,1455],{}," invocation, Cargo still compiles that shared dependency once, unified across every member being built in that command — exactly like unification across a single crate's transitive graph. This surprises people who expect workspace members to be isolated. The 2021 \"feature resolver v2\" (",[23,1535,1536],{},"resolver = \"2\"",") ",[273,1539,1540],{},"narrows"," unification (notably separating host\u002Ftarget and dev-dependency feature sets) but does not eliminate cross-member unification for normal dependencies built together; it does not disable unification outright. Member order in ",[23,1543,1501],{}," has no bearing on this.",[14,1546,1547,1558,1615,1662],{"language":16},[18,1548,1550,1551,1554,1555,1557],{"id":1549},"q15-a-published-library-crate-wants-to-offer-an-async-api-built-on-tokio-but-also-be-usable-by-consumers-who-dont-want-tokio-pulled-in-at-all-what-is-the-idiomatic-cargotoml-structure","Q15. A published library crate wants to offer an async API built on ",[23,1552,1553],{},"tokio"," but also be usable by consumers who don't want ",[23,1556,1553],{}," pulled in at all. What is the idiomatic Cargo.toml structure?",[32,1559,1560],{"language":16},[35,1561,1563],{"className":37,"code":1562,"language":16,"meta":39,"style":39},"[dependencies]\ntokio = { version = \"1\", optional = true, features = [\"rt\"] }\n\n[features]\nasync = [\"dep:tokio\"]\n",[23,1564,1565,1573,1593,1597,1605],{"__ignoreMap":39},[43,1566,1567,1569,1571],{"class":45,"line":46},[43,1568,50],{"class":49},[43,1570,54],{"class":53},[43,1572,57],{"class":49},[43,1574,1575,1578,1580,1582,1584,1587,1590],{"class":45,"line":60},[43,1576,1577],{"class":49},"tokio = { version = ",[43,1579,650],{"class":66},[43,1581,70],{"class":49},[43,1583,74],{"class":73},[43,1585,1586],{"class":49},", features = [",[43,1588,1589],{"class":66},"\"rt\"",[43,1591,1592],{"class":49},"] }\n",[43,1594,1595],{"class":45,"line":410},[43,1596,661],{"emptyLinePlaceholder":91},[43,1598,1599,1601,1603],{"class":45,"line":419},[43,1600,50],{"class":49},[43,1602,474],{"class":53},[43,1604,57],{"class":49},[43,1606,1607,1610,1613],{"class":45,"line":672},[43,1608,1609],{"class":49},"async = [",[43,1611,1612],{"class":66},"\"dep:tokio\"",[43,1614,57],{"class":49},[79,1616,1618,1633,1644,1653],{"className":1617},[82],[84,1619,1621,1623,1624,1626,1627,1630,1631],{"className":1620},[87],[89,1622],{"disabled":91,"type":92}," Make ",[23,1625,1553],{}," an optional dependency gated behind an additive ",[23,1628,1629],{},"async"," feature that is NOT in ",[23,1632,292],{},[84,1634,1636,436,1638,1640,1641,1643],{"className":1635},[87],[89,1637],{"disabled":91,"type":92},[23,1639,1553],{}," unconditionally; consumers who don't want it can use ",[23,1642,345],{}," on their own crate",[84,1645,1647,1649,1650,1652],{"className":1646},[87],[89,1648],{"disabled":91,"type":92}," Vendor a minimal subset of ",[23,1651,1553],{},"'s API directly into the crate to avoid the dependency entirely",[84,1654,1656,1658,1659,1661],{"className":1655},[87],[89,1657],{"disabled":91,"type":92}," Use two entirely separate published crates with identical code, one with ",[23,1660,1553],{}," and one without",[136,1663,1664,1666,1676],{},[139,1665,141],{},[143,1667,1668,1670,1671,1673,1674,443],{},[146,1669,148],{}," A — Make ",[23,1672,1553],{}," optional, gated behind a non-default ",[23,1675,1629],{},[143,1677,1678,93,1680,1682,1683,1133,1685,1688,1689,1691,1692,1694,1695,1697,1698,1700,1701,1704],{},[146,1679,158],{},[146,1681,860],{}," This is the standard pattern seen across the ecosystem (e.g. ",[23,1684,397],{},[23,1686,1687],{},"sqlx","): mark the runtime dependency ",[23,1690,112],{}," and expose it through an additive feature that consumers opt into, leaving it off of ",[23,1693,292],{}," so sync-only consumers pay zero cost. Depending on ",[23,1696,1553],{}," unconditionally forces every consumer to compile and link it even if they never touch the async API — ",[23,1699,345],{}," on the ",[273,1702,1703],{},"consumer's own crate"," does nothing to strip a dependency the library itself declared unconditionally. Vendoring or forking into duplicate crates massively increases maintenance burden for no benefit when Cargo already solves this cleanly.",[14,1706,1707,1715,1745],{},[18,1708,1710,1711,1714],{"id":1709},"q16-which-of-these-is-the-best-practice-for-a-feature-that-changes-the-behavior-of-existing-default-functionality-eg-switching-a-hash-function-to-a-faster-non-cryptographic-one-rather-than-adding-new-opt-in-api-surface","Q16. Which of these is the best practice for a feature that changes the ",[273,1712,1713],{},"behavior"," of existing default functionality (e.g. switching a hash function to a faster non-cryptographic one), rather than adding new opt-in API surface?",[79,1716,1718,1724,1730,1739],{"className":1717},[82],[84,1719,1721,1723],{"className":1720},[87],[89,1722],{"disabled":91,"type":92}," Avoid it if at all possible — behavior-changing features violate the \"features are additive\" convention and can silently produce different results depending on unrelated crates in the dependency graph",[84,1725,1727,1729],{"className":1726},[87],[89,1728],{"disabled":91,"type":92}," It's fine as long as the feature is well documented in the crate's README",[84,1731,1733,1735,1736,1738],{"className":1732},[87],[89,1734],{"disabled":91,"type":92}," Always make such features part of ",[23,1737,292],{}," so behavior is consistent",[84,1740,1742,1744],{"className":1741},[87],[89,1743],{"disabled":91,"type":92}," Use a build-time environment variable instead of a Cargo feature, since env vars are more explicit",[136,1746,1747,1749,1754],{},[139,1748,141],{},[143,1750,1751,1753],{},[146,1752,148],{}," A — Avoid it; behavior-changing features break the additive convention",[143,1755,1756,93,1758,1760,1761,1763,1764,1767],{},[146,1757,158],{},[146,1759,947],{}," Because feature unification means \"if anything in the dependency graph enables this feature, it's on for everyone,\" a feature that changes semantics (not just adds capability) can silently alter your crate's behavior based on an unrelated dependency three levels away enabling it for its own reasons — a notoriously hard bug to trace. The Cargo team's own guidance is that features should be strictly additive; behavior toggles are better expressed as separate crates, runtime configuration, or distinct type-level APIs. Documentation doesn't fix the unification hazard, making it ",[23,1762,292],{}," doesn't solve the underlying issue, and environment variables introduce their own non-reproducibility problems for library code (they're invisible to ",[23,1765,1766],{},"Cargo.lock"," and to downstream consumers reasoning about a crate's compiled behavior).",[14,1769,1770,1777,1802,1845],{"language":16},[18,1771,1773,1774,1776],{"id":1772},"q17-a-crate-wants-to-enable-a-specific-feature-of-an-optional-dependency-serdederive-only-when-its-own-dependent-turns-that-dependency-on-elsewhere-in-the-graph-without-itself-forcing-the-optional-dependency-to-be-pulled-in-which-syntax-expresses-this-weak-feature-dependency","Q17. A crate wants to enable a specific feature of an optional dependency (",[23,1775,1476],{},") only when its own dependent turns that dependency on elsewhere in the graph, without itself forcing the optional dependency to be pulled in. Which syntax expresses this \"weak\" feature dependency?",[32,1778,1779],{"language":16},[35,1780,1782],{"className":37,"code":1781,"language":16,"meta":39,"style":39},"[features]\nderive-support = [\"serde?\u002Fderive\"]\n",[23,1783,1784,1792],{"__ignoreMap":39},[43,1785,1786,1788,1790],{"class":45,"line":46},[43,1787,50],{"class":49},[43,1789,474],{"class":53},[43,1791,57],{"class":49},[43,1793,1794,1797,1800],{"class":45,"line":60},[43,1795,1796],{"class":49},"derive-support = [",[43,1798,1799],{"class":66},"\"serde?\u002Fderive\"",[43,1801,57],{"class":49},[79,1803,1805,1818,1829,1839],{"className":1804},[82],[84,1806,1808,689,1810,1813,1814,1817],{"className":1807},[87],[89,1809],{"disabled":91,"type":92},[23,1811,1812],{},"dep_name?\u002Ffeature_name"," syntax (e.g. ",[23,1815,1816],{},"serde?\u002Fderive",")",[84,1819,1821,689,1823,1826,1827],{"className":1820},[87],[89,1822],{"disabled":91,"type":92},[23,1824,1825],{},"dep_name\u002Ffeature_name"," syntax without a ",[23,1828,30],{},[84,1830,1832,93,1834,193,1837],{"className":1831},[87],[89,1833],{"disabled":91,"type":92},[23,1835,1836],{},"optional-features = [\"serde\u002Fderive\"]",[23,1838,824],{},[84,1840,1842,1844],{"className":1841},[87],[89,1843],{"disabled":91,"type":92}," There is no such mechanism; enabling a sub-feature always forces the base dependency on",[136,1846,1847,1849,1856],{},[139,1848,141],{},[143,1850,1851,732,1853,1855],{},[146,1852,148],{},[23,1854,1812],{}," weak-dependency-feature syntax",[143,1857,1858,93,1860,93,1862,1864,1865,1867,1868,1870,1871,1874,1875,1877,1878,1880,1881,1883,1884,1886,1887,1890,1891,1893,1894,1896,1897,1900],{},[146,1859,158],{},[146,1861,860],{},[23,1863,1816],{}," (the ",[23,1866,30],{}," marks it \"weak\") means \"if ",[23,1869,209],{}," ends up enabled by ",[273,1872,1873],{},"someone"," in the graph, also turn on its ",[23,1876,1448],{}," feature — but don't turn ",[23,1879,209],{}," on by yourself.\" This is exactly for the case in the question: contributing a feature to a dependency without forcing that dependency to exist. The non-",[23,1882,30],{}," form ",[23,1885,1476],{}," is the older, \"strong\" syntax that ",[273,1888,1889],{},"does"," implicitly enable ",[23,1892,209],{}," as a side effect, which is the opposite of what's wanted here. ",[23,1895,824],{}," has no ",[23,1898,1899],{},"optional-features"," key.",[14,1902,1903,1911,1951],{},[18,1904,1906,1907,1910],{"id":1905},"q18-why-do-many-cratesio-libraries-deliberately-keep-features-default-empty-rather-than-defaulting-to-their-most-common-configuration","Q18. Why do many crates.io libraries deliberately keep ",[23,1908,1909],{},"[features] default = []"," (empty) rather than defaulting to their most common configuration?",[79,1912,1914,1920,1929,1938],{"className":1913},[82],[84,1915,1917,1919],{"className":1916},[87],[89,1918],{"disabled":91,"type":92}," To let downstream consumers opt into exactly what they need without unwanted transitive dependencies or unification surprises leaking through unless explicitly requested",[84,1921,1923,1925,1926,1928],{"className":1922},[87],[89,1924],{"disabled":91,"type":92}," Because Cargo requires ",[23,1927,292],{}," to be empty for crates published to crates.io",[84,1930,1932,1934,1935],{"className":1931},[87],[89,1933],{"disabled":91,"type":92}," Because non-empty defaults are silently ignored by ",[23,1936,1937],{},"cargo install",[84,1939,1941,1943,1944,1947,1948,1950],{"className":1940},[87],[89,1942],{"disabled":91,"type":92}," It has no practical effect; ",[23,1945,1946],{},"default = []"," and omitting ",[23,1949,96],{}," entirely behave identically in every situation",[136,1952,1953,1955,1960],{},[139,1954,141],{},[143,1956,1957,1959],{},[146,1958,148],{}," A — To let consumers opt in explicitly and avoid unwanted transitive weight or unification surprises",[143,1961,1962,93,1964,1966,1967,1969,1970,1973,1974,1976,1977,1979,1980,1982,1983,1985,1986,1988,1989,1992],{},[146,1963,158],{},[146,1965,860],{}," Keeping ",[23,1968,292],{}," minimal (or empty) is a deliberate ecosystem convention for foundational crates so that consumers pay only for what they ask for, and so that unification doesn't quietly drag in heavy optional dependencies just because ",[273,1971,1972],{},"some"," crate in the graph forgot to pass ",[23,1975,462],{},". This is purely a design choice, not a crates.io requirement — Cargo places no restriction on ",[23,1978,292],{}," content for publishing. ",[23,1981,1937],{}," respects defaults normally. And the last option is wrong in a subtle way: omitting ",[23,1984,96],{}," entirely means the crate has zero features at all (nothing to enable), whereas an explicit ",[23,1987,1946],{}," still allows ",[273,1990,1991],{},"other",", non-default features to exist and be turned on individually — they're not identical when the crate defines additional optional features.",[14,1994,1995,1999,2039],{},[18,1996,1998],{"id":1997},"q19-what-is-the-most-reliable-way-to-verify-that-a-crate-compiles-correctly-under-every-individual-feature-combination-not-just-all-features-on-or-default-only-before-publishing","Q19. What is the most reliable way to verify that a crate compiles correctly under every individual feature combination, not just \"all features on\" or \"default only,\" before publishing?",[79,2000,2002,2012,2025,2033],{"className":2001},[82],[84,2003,2005,2007,2008,2011],{"className":2004},[87],[89,2006],{"disabled":91,"type":92}," Use a tool like ",[23,2009,2010],{},"cargo hack --feature-powerset --no-dev-deps check"," in CI to compile every combination of feature flags",[84,2013,2015,2017,2018,2021,2022,2024],{"className":2014},[87],[89,2016],{"disabled":91,"type":92}," Run ",[23,2019,2020],{},"cargo check"," once with ",[23,2023,1377],{},"; if that passes, every subset is guaranteed to also compile",[84,2026,2028,2017,2030,2032],{"className":2027},[87],[89,2029],{"disabled":91,"type":92},[23,2031,1212],{}," once; test failures would reveal any feature-combination compile errors",[84,2034,2036,2038],{"className":2035},[87],[89,2037],{"disabled":91,"type":92}," It's unnecessary — Cargo's unification guarantees every subset compiles if the full set does",[136,2040,2041,2043,2051],{},[139,2042,141],{},[143,2044,2045,149,2047,2050],{},[146,2046,148],{},[23,2048,2049],{},"cargo hack --feature-powerset"," (or similar) to check every combination",[143,2052,2053,93,2055,93,2058,2060,2061,2064,2065,2068,2069,2072,2073,2076,2077,2079,2080,1439,2083,2086,2087,2089],{},[146,2054,158],{},[146,2056,2057],{},"Idiom\u002FDebug:",[23,2059,1377],{}," on is a ",[273,2062,2063],{},"different"," compilation than any individual subset — a crate can easily compile fine with everything on (where conflicting ",[23,2066,2067],{},"#[cfg]"," branches never both trigger issues) yet fail to compile with only feature ",[23,2070,2071],{},"x"," on and not ",[23,2074,2075],{},"y",", especially with mutually-referential ",[23,2078,1324],{}," code. ",[23,2081,2082],{},"cargo-hack",[23,2084,2085],{},"--feature-powerset"," mode compiles every combination in turn and is the standard CI safeguard used by mature crates for exactly this reason. ",[23,2088,1212],{}," only runs whatever single feature set was active for that invocation, so it can't surface combination-specific breakage on its own, and there is no guarantee that \"all features compiles\" implies \"every subset compiles\" — the additive-features convention is a social contract enforced by testing, not something the compiler verifies for you.",[14,2091,2092,2100,2144],{},[18,2093,2095,2096,2099],{"id":2094},"q20-a-crate-has-a-feature-unstable-that-exposes-experimental-semver-unstable-apis-what-is-the-recommended-convention-for-how-this-feature-interacts-with-semantic-versioning-guarantees","Q20. A crate has a feature ",[23,2097,2098],{},"unstable"," that exposes experimental, semver-unstable APIs. What is the recommended convention for how this feature interacts with semantic versioning guarantees?",[79,2101,2103,2112,2121,2131],{"className":2102},[82],[84,2104,2106,2108,2109,2111],{"className":2105},[87],[89,2107],{"disabled":91,"type":92}," Document explicitly that APIs behind ",[23,2110,2098],{}," are exempt from semver guarantees and may break even in patch releases",[84,2113,2115,2117,2118,2120],{"className":2114},[87],[89,2116],{"disabled":91,"type":92}," Treat ",[23,2119,2098],{}," like any other feature — once published, its APIs are covered by normal semver like everything else",[84,2122,2124,2126,2127,2130],{"className":2123},[87],[89,2125],{"disabled":91,"type":92}," Cargo automatically excludes ",[23,2128,2129],{},"#[cfg(feature = \"unstable\")]"," items from semver compatibility checks with no documentation needed",[84,2132,2134,2136,2137,2139,2140,2143],{"className":2133},[87],[89,2135],{"disabled":91,"type":92}," Publish ",[23,2138,2098],{},"-gated code only to a separate ",[23,2141,2142],{},"-unstable"," suffixed crate name, never mixed into the main crate",[136,2145,2146,2148,2156],{},[139,2147,141],{},[143,2149,2150,2152,2153,2155],{},[146,2151,148],{}," A — Explicitly document that ",[23,2154,2098],{},"-gated APIs are exempt from normal semver guarantees",[143,2157,2158,93,2160,2162,2163,2165,2166,1133,2168,2171],{},[146,2159,158],{},[146,2161,860],{}," Since Cargo has no built-in notion of \"this feature's APIs don't count toward semver\" (there is no automatic exemption — that part of option C is fabricated), crates that ship experimental surface behind a feature like ",[23,2164,2098],{}," rely entirely on clear documentation (README, feature doc comment, changelog policy) stating that breaking changes there can land in any release, including patches. This is a widely used convention (e.g. in ",[23,2167,1553],{},[23,2169,2170],{},"rand",") precisely because publishing genuinely separate crates for every experimental API would fragment the ecosystem and versioning unnecessarily. Treating it like normal semver-bound code would freeze experimentation prematurely.",[2173,2174,2175],"style",{},"html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}",{"title":39,"searchDepth":60,"depth":60,"links":2177},[2178,2180,2182,2184,2186,2188,2190,2192,2194,2196,2198,2200,2202,2204,2206,2208,2210,2212,2214,2215],{"id":20,"depth":410,"text":2179},"Q1. What is the correct way to declare a feature named logging that has no dependencies of its own in Cargo.toml?",{"id":188,"depth":410,"text":2181},"Q2. A crate declares serde = { version = \"1\", optional = true } under [dependencies]. What happens by default?",{"id":288,"depth":410,"text":2183},"Q3. Which flag builds a crate with its default feature set disabled?",{"id":375,"depth":410,"text":2185},"Q4. In Cargo.toml, what does this dependency declaration mean?",{"id":521,"depth":410,"text":2187},"Q5. Crate A depends on net-lib with features = [\"tls\"]. Crate B (a sibling dependency in the same build) depends on net-lib with default-features = false and no extra features. Both end up in the same final binary. What features does net-lib actually get compiled with?",{"id":619,"depth":410,"text":2189},"Q6. A library crate wants an optional dependency regex available for internal use, but does NOT want a public feature named regex to appear in its feature list (to avoid it being confused with a user-facing toggle). Which mechanism achieves this?",{"id":769,"depth":410,"text":2191},"Q7. What is the idiomatic way to express \"this crate is no_std unless a feature is enabled\"?",{"id":890,"depth":410,"text":2193},"Q8. A [features] table defines backend-a = [] and backend-b = [], and the crate's code assumes exactly one is active, panicking or producing nonsensical output if both are compiled in at once. A downstream user's dependency graph ends up unifying both features on. What is the actual build-time outcome?",{"id":961,"depth":410,"text":2195},"Q9. A binary crate depends on image with default-features = false in hopes of dropping the (heavy) png default codec. Another dependency deeper in the graph pulls in image with its regular defaults. After unification, is png support present in the final binary?",{"id":1048,"depth":410,"text":2197},"Q10. A crate has [features] full = [\"net\", \"db\", \"compress\"]. If a user builds with cargo build --features net, which of db and compress get enabled?",{"id":1147,"depth":410,"text":2199},"Q11. A crate lists criterion = \"0.5\" only under [dev-dependencies], not under [dependencies]. Can library code (non-test, non-bench) reference criterion when the crate is built normally with cargo build?",{"id":1230,"depth":410,"text":2201},"Q12. Inside a build.rs script, what is the correct way to check whether the feature json is enabled for the crate being built?",{"id":1343,"depth":410,"text":2203},"Q13. Running plain cargo doc (no extra flags) on a crate with several feature-gated public items — what shows up in the generated documentation for those items?",{"id":1426,"depth":410,"text":2205},"Q14. A workspace has two member crates, app and lib, both depending on serde. app's Cargo.toml requests serde with the derive feature; lib's does not. When building the whole workspace with cargo build --workspace, does lib's compilation unit get serde's derive feature?",{"id":1549,"depth":410,"text":2207},"Q15. A published library crate wants to offer an async API built on tokio but also be usable by consumers who don't want tokio pulled in at all. What is the idiomatic Cargo.toml structure?",{"id":1709,"depth":410,"text":2209},"Q16. Which of these is the best practice for a feature that changes the behavior of existing default functionality (e.g. switching a hash function to a faster non-cryptographic one), rather than adding new opt-in API surface?",{"id":1772,"depth":410,"text":2211},"Q17. A crate wants to enable a specific feature of an optional dependency (serde\u002Fderive) only when its own dependent turns that dependency on elsewhere in the graph, without itself forcing the optional dependency to be pulled in. Which syntax expresses this \"weak\" feature dependency?",{"id":1905,"depth":410,"text":2213},"Q18. Why do many crates.io libraries deliberately keep [features] default = [] (empty) rather than defaulting to their most common configuration?",{"id":1997,"depth":410,"text":1998},{"id":2094,"depth":410,"text":2216},"Q20. A crate has a feature unstable that exposes experimental, semver-unstable APIs. What is the recommended convention for how this feature interacts with semantic versioning guarantees?","md",{},"\u002Frust\u002F28-cargo-features",{"title":5,"description":39},"rust\u002F28-cargo-features","t80IBEFn6jwXXJdhB4bBO6HCqKKiyG1EvUfQFffs2y8",1787335398453]