Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

Rust.txt 39 KB

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
  1. = Rust Packaging Guidelines
  2. :last-reviewed: 2024-04-03
  3. https://www.rust-lang.org[Rust] is a strongly and statically typed,
  4. compiled programming language
  5. that supports concepts from both imperative and functional programming.
  6. Because there is not yet a stable Rust ABI,
  7. and because conditional compilation is a widely used feature in the Rust ecosystem,
  8. Rust libraries ("crates") can not be distributed in compiled form,
  9. and are instead distributed as source code.
  10. This document covers how to handle Rust code in packages,
  11. specific to the different ways in which projects can be set up:
  12. * link:#_rust_crates[Rust "crates"]:
  13. packages that are individually published on https://crates.io[crates.io],
  14. the official package registry for Rust
  15. (primarily libraries, but also "single-crate" applications)
  16. * Rust link:#_rust_applications_non_crates_io_crates[applications that are single crates but not published on crates.io]
  17. * Rust projects that are organized as link:#_rust_applications_cargo_workspace_projects[cargo "workspaces"]:
  18. usually larger projects with "internal" crates,
  19. which are often not separately published on https://crates.io[crates.io]
  20. * link:#_python_projects[Python projects] with a "native" component implemented in Rust:
  21. usually built with https://github.com/PyO3/setuptools-rust[setuptools_rust] or https://github.com/PyO3/maturin[maturin]
  22. * link:#_mixed_rust_cc_projects[mixed Rust / C/C++ projects] where parts of the project are implemented in Rust:
  23. either built by wrapping cargo,
  24. or by utilizing https://mesonbuild.com/Rust.html[meson]'s limited support
  25. for directly building Rust code
  26. For the first three of these cases,
  27. the https://pagure.io/fedora-rust/rust2rpm[rust2rpm] tool can be used
  28. to generate spec files from cargo / crate metadata.
  29. It is designed to produce spec files
  30. that are in line with the (Rust) Packaging Guidelines.
  31. There are also guidelines for link:#_building_shared_libraries_with_cargo_c[packaging shared libraries]
  32. that are implemented in Rust
  33. (usually built and installed with https://crates.io/crates/cargo-c[cargo-c]).
  34. == Generic rules
  35. This section covers rules that apply to _all_ packages that ship Rust code.
  36. === Compiler flags
  37. Similarly to other language ecosystems in Fedora,
  38. there is a standardized set of compiler flags
  39. that *MUST* be passed to the Rust compiler.
  40. The defaults for Rust are defined in the `%build_rustflags` macro
  41. from the `rust-srpm-macros` package.
  42. It is part of the default buildroot on Fedora 39+,
  43. where the `%set_build_flags` macro automatically sets the `$RUSTFLAGS` environment variable
  44. based on this macro.
  45. For compatibility with older releases,
  46. this environment variable can be set manually at the start of `%build` and `%check`
  47. in package's spec files:
  48. [source,shell]
  49. ----
  50. export RUSTFLAGS="%build_rustflags"
  51. ----
  52. This is not necessary for packages that use the `%cargo_prep`, `%cargo_build`, and `%cargo_test` macros,
  53. which configure `cargo` to use the default `%build_rustflags` directly.
  54. === Mandatory `BuildRequires`
  55. The RPM macros that provide basic functionality
  56. for building Rust code are included in `rust-rpm-macros`,
  57. which is part of the default buildroot in Fedora,
  58. as it is a dependency of `redhat-rpm-config`.
  59. When building for ELN or EPEL8, this is not the case,
  60. and packages need to use `BuildRequires: rust-toolset`.
  61. Packages that build Rust code with cargo - directly or indirectly -
  62. or which call any of the `%cargo_*` macros,
  63. *MUST* add `BuildRequires: cargo-rpm-macros >= 24`,
  64. which provides the implementations of all `%cargo_*` macros.
  65. This package is not part of the default buildroot,
  66. since it pulls in additional dependencies
  67. (i.e. a Python interpreter).
  68. For backwards compatibility,
  69. packages *MAY* instead depend on earlier versions of the `%cargo_*` macros,
  70. which were provided in the `rust-packaging` package,
  71. if they do not depend on any of the features or macros
  72. that are only available with newer versions.
  73. When generating a spec file for a crate with https://pagure.io/fedora-rust/rust2rpm[rust2rpm],
  74. it will automatically detect usage of these features,
  75. and include the necessary `BuildRequires`
  76. for the RPM macro package automatically.
  77. === License tags
  78. Similar to other languages that produce statically linked binaries,
  79. Rust executables (and shared libraries) contain code
  80. that originates in other packages
  81. (i.e. packages for other Rust crates),
  82. which in turn are covered by different license terms.
  83. This needs to be taken into account
  84. by maintaining a separate `License` tag
  85. for the subpackage that contains these binaries.
  86. More information about `License` tags is available from the link:[Fedora Legal docs].
  87. The `cargo-rpm-macros` package provides two RPM macros
  88. that help with filling the `License` tag correctly:
  89. - `%cargo_license_summary`
  90. This macro determines and prints a summary
  91. of all the licenses of the Rust crates
  92. that end up statically linked into final binaries
  93. (properly excluding build-only or test-only dependencies).
  94. This summary can then be copied from the build log
  95. into the spec file as a comment.
  96. The actual contents of the `License` tag can then be obtained
  97. by constructing a conjunction of these individial licenses (with SPDX `AND` operators).
  98. - `%cargo_license`
  99. This macro determines and prints a complete breakdown of all Rust crates
  100. that end up statically linked into final binaries
  101. (according to the same logic as in the `%cargo_license_summary` macro),
  102. their versions, _and_ their individual license expressions.
  103. Generating this list dynamically at build-time
  104. ensures that its contents always match the actual dependencies.
  105. Both macros accept the same arguments
  106. as all other `%cargo_*` macros (`-a`, `-n`, `-f`),
  107. and for their output to match the actual binaries,
  108. the same flags need to be passed to them and `%cargo_build`.
  109. === Vendored dependencies
  110. https://docs.fedoraproject.org/en-US/packaging-guidelines/#bundling[In general],
  111. packages *SHOULD NOT* use bundled crate dependencies,
  112. whenever possible.
  113. Whenever vendored / bundled crate dependencies _are_ used
  114. (no matter which mechanism is used for the purpose),
  115. all bundled crate dependencies *MUST* be declared
  116. with virtual `Provides` in the format `Provides: bundled(crate($crate)) = $version`
  117. in the subpackage that contains the Rust component.
  118. For example, these virtual `Provides` are used to determine
  119. the impact of security vulnerabilities on packages
  120. that use vendored Rust dependencies.
  121. Building exclusively from vendored dependencies
  122. by using a tarball that was generated by running `cargo vendor`
  123. *SHOULD* only be a last resort.
  124. However, there are also two _rare_ situations
  125. in which bundling at least _some_ Rust crates is likely unavoidable.
  126. ==== Replacing git dependencies
  127. One of the types of dependencies cargo supports are git snapshots,
  128. which are usually used to reference either a specific commit,
  129. or a reference to a downstream fork of a crate.
  130. The project *SHOULD* be patched to use a version of this crate
  131. that is available on https://crates.io[crates.io] instead,
  132. if that is possible.
  133. If it turns out that depending on a git snapshot is no longer necessary,
  134. this patch *SHOULD* be submitted to the upstream project.
  135. If the dependency is not published on https://crates.io[crates.io],
  136. or if the versions published there are not a suitable replacement,
  137. a git snapshot of the crate can be bundled.
  138. This can be achieved by creating and supplying a tarball
  139. with the git snapshot as a separate source,
  140. unpacking the tarball in `%prep`,
  141. and patching `Cargo.toml` to replace the git-based dependency
  142. with a path-based dependency.
  143. ==== Replacing patched crate sources
  144. Another way in which cargo supports specifying modified dependencies is
  145. by "patching" a crate source,
  146. specifying an alternative source for specific crates -
  147. which will likely be either git references or path-based dependencies
  148. that are present to override a crate
  149. that is published on https://crates.io[crates.io] with a (modified) local copy,
  150. or a git repository that points to a (modified) fork of the crate.
  151. These replacements *SHOULD* be dropped
  152. in favor of using only published versions of crates.
  153. If that is not possible,
  154. they must be replaced by path-based dependencies,
  155. similar to the process described for link:#_replacing_git_dependencies[git-type dependencies].
  156. ==== Using vendor tarballs
  157. Official support for building with vendored dependencies
  158. was added in version 25 of cargo-rpm-macros and rust2rpm.
  159. * The `%cargo_prep` macro accepts a `-v $VENDOR` argument,
  160. where `$VENDOR` is the path to the directory
  161. that contains the vendored crate dependencies.
  162. When this argument is passed,
  163. the generated cargo configuration is set up
  164. for building against dependencies in this directory
  165. instead of dependencies from the system-wide registry.
  166. * The `%cargo_generate_buildrequires` macro *MUST NOT* be called
  167. when using vendored dependencies.
  168. * The `%cargo_vendor_manifest` macro generates a manifest (`cargo-vendor.txt`)
  169. that lists the names and versions of all crates in the vendor tarball.
  170. This macro *MUST* be called (for example, in the `%build` scriptlet),
  171. and the generated file *MUST* be added as a `%license` file
  172. in the appropriate package's list of `%files`.
  173. An RPM generator parses this file
  174. and generates appropriate virtual `Provides` for all bundled crates,
  175. as is required for any bundled dependencies.
  176. * Packages that build with vendored dependencies
  177. *MUST NOT* provide a Rust library interface (i.e. in `-devel` subpackages),
  178. because the resulting packages would have broken dependencies.
  179. Typically, the `%prep` scriptlet will look like this
  180. when using vendored dependencies
  181. (assuming `Source1` is the vendor tarball,
  182. and it contains a top-level `vendor` directory):
  183. [source,rpm]
  184. ----
  185. %prep
  186. %autosetup -%{crate}-%{version} -p1 -a1
  187. %cargo_prep -v vendor
  188. ----
  189. The necessary spec file adaptations
  190. and the generation of the vendor tarball itself
  191. happen automatically when running rust2rpm in "vendor" mode.
  192. == rust2rpm
  193. The recommended way to write spec files for Rust projects
  194. is to use https://pagure.io/fedora-rust/rust2rpm[rust2rpm],
  195. and apply any necessary modifications on top of the generated spec file.
  196. There are a few common situations
  197. in which automatically generated spec files
  198. need manual changes:
  199. * invalid `Summary` / `%description`:
  200. The heuristics for generating the `Summary` or `%description` for the package
  201. from the crate metadata can fail to produce valid values
  202. (i.e. `Summary` tag that is too long).
  203. In this case, the `Summary` needs to be shortened manually.
  204. This can also be overridden
  205. in the package-specific rust2rpm configuration file.
  206. * unwanted dependencies / subpackages:
  207. Some crates provide non-default / optional features
  208. that are either unnecessary
  209. (i.e. only applicable to non-Linux systems),
  210. or have additional dependencies
  211. that are not packaged for Fedora.
  212. These features and unavailable optional dependencies *MUST*
  213. be removed from crate metadata - otherwise,
  214. the package will either fail to build,
  215. or produce subpackages with broken dependencies.
  216. * nightly-only / unstable features:
  217. Some crates provide features
  218. that are only available on a nightly version of the Rust compiler,
  219. or features that are unstable and require an opt-in
  220. by passing environment variables.
  221. Features like these *SHOULD* be removed from crate metadata,
  222. since they either cannot work
  223. (Fedora ships only the stable Rust toolchain)
  224. or are not feasible to support.
  225. * unwanted / unnecessary files ("bloat"):
  226. Some projects include files
  227. that are not required for the crate to function properly
  228. (files for CI settings, development / helper scripts, etc.).
  229. Files like these *SHOULD* be prevented from being installed
  230. (by adding / modifying the `package.include`
  231. or `package.exclude` settings in the crate metadata).
  232. It is recommended to submit changes like this to the upstream project.
  233. * incompatible compiler flags:
  234. Some crates include custom settings for the `release` profile
  235. that are incompatible with RPM packaging.
  236. These settings *MUST* be removed from the `release` profile
  237. by patching `Cargo.toml`.
  238. Crates that provide Rust bindings for C libraries
  239. usually require some additional changes (if possible):
  240. * linking against system libraries:
  241. This often requires making some dependencies non-optional and / or
  242. modifying `build.rs` scripts to unconditionally link against system libraries
  243. instead of building and statically linking a bundled copy of the library.
  244. * regenerating Rust bindings (and tests for them) at build-time:
  245. This too often requires making the `bindgen` dependency non-optional and / or
  246. modifying `build.rs` to cause regeneration of Rust bindings at build-time.
  247. Note that patching `Cargo.toml` files
  248. (especially changing the set of optional dependencies and features)
  249. *MUST* be done by running `rust2rpm -p`,
  250. since changes like these affect spec file generation
  251. (i.e. the list of generated subpackages),
  252. which is only correctly taken into account
  253. if the patch is created _before_ generation of the spec file.
  254. == Rust crates
  255. A large part of the process of packaging Rust crates
  256. can (and _should_) be automated by using https://pagure.io/fedora-rust/rust2rpm[rust2rpm].
  257. It is designed to generate spec files that are compliant
  258. with both the general and the Rust Packaging Guidelines.
  259. Additionally, due to some properties of packages for Rust crates
  260. (i.e. subpackages that correspond to crate features / optional dependencies),
  261. https://pagure.io/fedora-rust/rust2rpm[rust2rpm] *MUST* be re-run
  262. for every new version of a crate
  263. to ensure that generated feature subpackages
  264. stays in sync with crate metadata.
  265. === Package naming
  266. The canonical source of Rust crates is https://crates.io[crates.io].
  267. ==== Crates with Rust library interface
  268. Crates that are published on https://crates.io[crates.io]
  269. and that are intended to provide a Rust library interface
  270. *MUST* be packaged with `rust-$crate` as the name of the source package
  271. (where `$crate` is the name of the project on https://crates.io[crates.io]).
  272. This ensures that there are no name collisions
  273. between Rust crates published on https://crates.io[crates.io]
  274. and Rust crates packaged for Fedora.
  275. Projects from sources other than https://crates.io[crates.io]
  276. *MUST NOT* use the `rust-` prefix for source package names,
  277. and *MUST* follow the general Naming Guidelines instead.
  278. In this case, the guidelines for either
  279. link:#_rust_applications_non_crates_io_crates[single-crate Rust applications] or
  280. link:#_rust_applications_cargo_workspace_projects[cargo workspaces] apply.
  281. If a crate is also part of a larger project
  282. and it is not feasible to package the Rust crate separately,
  283. the Rust crate *MAY* be packaged from different sources
  284. (i.e. an upstream tarball) _if and only if_ the crate
  285. is also published on https://crates.io[crates.io]
  286. under the same name and with matching versions.
  287. In this case, the subpackage(s) that contain the Rust crate sources
  288. *MUST* be named `rust-$crate-devel`
  289. and `rust-$crate+$feature-devel` for all crate features
  290. and ensure that the virtual `Provides` for the Rust crate are correct.
  291. The `rust-` prefix is not required for the name of the source package.
  292. ==== Crates without Rust library interface
  293. Crates that do not provide a Rust library interface
  294. (for example, crates that only contain executable targets)
  295. *MAY* drop the `rust-` prefix for the name of the source package
  296. or use the "project name" if it is different from the crate name
  297. _if and only if_ the project will not provide (or need to provide)
  298. a Rust library interface in the future,
  299. since this would require renaming the source package to `rust-$crate`.
  300. In this case, the guidelines for
  301. link:#_rust_applications_non_crates_io_crates[single-crate Rust applications] apply,
  302. and the package is not required to use the sources
  303. that are published on https://crates.io[crates.io].
  304. When building a crate with vendored dependencies
  305. the `rust-` prefix of the source package name *MAY* be dropped as well --
  306. since packages cannot provide a Rust library interface in this case --
  307. _if and only if_ the project will not need to provide a Rust library interface.
  308. When generating a package for a Rust crate
  309. that also (or exclusively) contains an application,
  310. the convention followed by https://pagure.io/fedora-rust/rust2rpm[rust2rpm] is
  311. to generate a subpackage with a name that matches the crate's name
  312. (i.e. the `rust-$crate` source package will have a `$crate` subpackage).
  313. If this name does not match expectations,
  314. it is recommended to either change the name of this subpackage,
  315. or to add virtual `Provides` for the expected name.
  316. === Package versioning
  317. Projects that are built with cargo and / or published on https://crates.io[crates.io]
  318. follow Semantic Versioning (with small cargo-specific tweaks).
  319. Since SemVer strings can contain characters that are invalid in RPM version strings,
  320. they *MUST* be translated to be RPM-compatible.
  321. For example, pre-releases are denoted by a `-<pre>` suffix in SemVer,
  322. but the `-` character is invalid in RPM Versions.
  323. This can be solved by replacing `-` with the `~` character,
  324. which denotes pre-releases in RPM version strings.
  325. This translation happens automatically for the `Version` tag
  326. when generating a spec file with https://pagure.io/fedora-rust/rust2rpm[rust2rpm],
  327. and the "upstream" version is stored in a separate macro
  328. that can be used to refer to the "original" version string.
  329. Additionally, some Rust crates carry extra "build" metadata in their versions
  330. (a `+<build>` suffix).
  331. This format is primarily used to carry information
  332. about the version of a bundled C library.
  333. This `+<build>` suffix *MUST* be removed from crate metadata with a patch,
  334. since it can interfere with RPM dependency / version resolution.
  335. This happens automatically when using rust2rpm version 25 or newer.
  336. === Package sources
  337. Projects from https://crates.io[crates.io] *MUST* be packaged from the sources
  338. that are published there (i.e. by using the `%{crates_source}` macro).
  339. If the sources published on https://crates.io[crates.io]
  340. do not contain all files that are necessary for creating the package
  341. (for example, missing `.desktop` file or man pages),
  342. the upstream sources can be used as an _additional_ source,
  343. but they *MUST NOT* be used for building the crate itself.
  344. It is recommended to file an issue with the upstream project
  345. about including these additional files in published crates.
  346. === Crate license
  347. Most tooling support for determining licenses
  348. requires accurate metadata about licenses in crate metadata,
  349. including the `%cargo_license*` macros,
  350. and other third-party tools like `cargo-license` and `cargo-deny`.
  351. For this reason, the license metadata for all Rust crates packaged for Fedora
  352. *MUST* match the license tag of the Fedora package itself.
  353. Any crates that set `package.license-file` in their metadata
  354. (which is reserved for non-standard / non-SPDX licenses)
  355. *MUST* be patched to set `package.license` in their metadata instead
  356. in cases where this is _not_ appropriate
  357. and an accurate SPDX expression can be provided.
  358. Patches like this *SHOULD* be submitted upstream.
  359. === RPM macros
  360. The process of building and installing Rust crates
  361. is almost entirely automated with several RPM macros:
  362. * `%cargo_prep`:
  363. This macro *MUST* be called in the `%prep` scriptlet
  364. after sources have been unpacked.
  365. It sets up the build environment for cargo
  366. and injects a cargo configuration file,
  367. which sets the default compiler flags
  368. and configures the local crate registry
  369. as a replacement for https://crates.io[crates.io].
  370. * `%cargo_generate_buildrequires`:
  371. This macro *MUST* be called in the `%generate_buildrequires` scriptlet,
  372. except when building with vendored dependencies.
  373. This is the mechanism that automatically generates depepdencies on other Rust crates
  374. based on the metadata in `Cargo.toml`.
  375. * `%cargo_build`:
  376. This macro *MUST* be called in the `%build` scriptlet.
  377. It runs `cargo build` with the appropriate command line arguments.
  378. Calling this macro *MAY* be skipped
  379. if the crate is not supported on the current CPU architecture.
  380. * `%cargo_install`:
  381. This macro *MUST* be called in the `%install` scriptlet
  382. for crates that provide a library interface.
  383. It runs `cargo package` and installs the resulting directory tree
  384. into `%{buildroot}/%{crate_instdir}`
  385. (i.e. `%{buildroot}/%{cargo_registry}/%{crate}-%{version}/`).
  386. For crates that provide `bin` targets,
  387. it installs all built executables into `%{buildroot}/%{_bindir}`.
  388. If any built executables need to be installed in a different location,
  389. they can be moved after calling `%cargo_install`,
  390. or `%cargo_install` can be replaced
  391. with manual installation steps.
  392. To prevent installation of executables by this macro,
  393. the `+%cargo_install_bin+` macro can be defined to `0`.
  394. To prevent installation of library sources by this macro,
  395. the `+%cargo_install_lib+` macro can be defined to `0`.
  396. * `%cargo_test`:
  397. This macro *MUST* be called in the `%check` scriptlet.
  398. It runs `cargo test` with the appropriate command line arguments.
  399. Calling this macro *MAY* be skipped
  400. if the crate is not supported on the current CPU architecture
  401. or if tests are disabled in general.
  402. * `%cargo_license` / `%cargo_license_summary`:
  403. These macros *MUST* be called in the `%build` scriptlet after `%cargo_build`
  404. when building crates that include binary targets.
  405. They can be used to print the list of the licenses
  406. of the crates that are statically linked into any built executable
  407. or shared library (see link:#_license_tags[License tags]).
  408. All packages for Rust crates *MUST* set
  409. either `%bcond_without check` or `%bcond_with check`.
  410. The value of this macro affects the behaviour of `%cargo_generate_buildrequires`.
  411. All `%cargo_*` macros (except `%cargo_prep` and `%cargo_vendor_manifest`)
  412. accept a set of optional flags / arguments
  413. that can be used to control the feature flags that are passed to cargo
  414. (usually to enable optional / non-default features):
  415. * `-a`:
  416. Causes the `--all-features` flag to be passed to cargo,
  417. and the `%cargo_generate_buildrequires` macro
  418. to resolve dependencies with all optional features enabled.
  419. * `-n`:
  420. Causes the `--no-default-features` flags to be passed to cargo,
  421. and the `%cargo_generate_buildrequires` macro
  422. to resolve dependencies with all default and optional features disabled.
  423. * `-f foo,bar`:
  424. Causes the `--features foo,bar` argument to be passed to cargo,
  425. and the `%cargo_generate_buildrequires` macro
  426. to resolve dependencies with the additional features `foo` and `bar` enabled.
  427. This argument accepts a comma-separated list of feature names
  428. (or names of optional dependencies).
  429. The `-a` and `-n` flags are mutually exclusive
  430. and cannot be passed together.
  431. The `-a` flag and `-f` arguments are also incompatible,
  432. since passing `-a` already enables all features.
  433. However, using the `-n` flag and specifically enabling _some_ features
  434. with the `-f` argument is valid.
  435. There are some common situations
  436. in which passing these flags or arguments is necessary:
  437. * It can be necessary to enable additional features and / or optional dependencies
  438. to build and run the test suite of a crate.
  439. In this case, the required features *MUST* be enabled
  440. by passing the corresponding flags to all `%cargo_*` macros,
  441. unless the required optional dependencies are not packaged yet.
  442. * Some applications support additional / non-default features
  443. by passing feature flags.
  444. If it is desirable to build applications with these features enabled,
  445. the required features need to be enabled
  446. by passing the corresponding flags to all `%cargo_*` macros
  447. (including `%cargo_license` and `%cargo_license_summary`).
  448. Note that the `-n` flag should only be used in exceptional circumstances,
  449. for example when enabling a different backend than the one enabled by default,
  450. and *MUST NOT* be used to avoid missing dependencies
  451. that are part of the `"default"` feature set of a crate.
  452. When passing any of the `-a` or `-n` flags or an `-f` argument
  453. to a `%cargo_build` and / or `%cargo_install` macro,
  454. the same flags MUST also be passed
  455. to `%cargo_license` and `%cargo_license_summary` (if present).
  456. Otherwise, the list of generated licenses and the generated license summary
  457. will not match what is used when the application or library is compiled.
  458. It is recommended to set these flags in a `rust2rpm.toml` config file
  459. which causes the flags to be injected into generated spec files automatically,
  460. whereever necessary.
  461. === Dynamically generated `BuildRequires` for crate dependencies
  462. With Semantic Versioning (_"SemVer"_) being
  463. the only supported versioning scheme for Rust crates,
  464. dependencies on Rust libraries are almost exclusively specified as
  465. _"this version or any newer version that is API-compatible with it"_,
  466. i.e. a range of supported versions.
  467. These ranges of supported versions
  468. need to be correctly translated into RPM dependencies,
  469. otherwise a wrong version of a dependency might get pulled in for builds,
  470. causing unhelpful error messages about missing dependencies.
  471. Since dependencies of Rust projects often change with every new release,
  472. and keeping a list of `BuildRequires` up-to-date manually is tedious and error-prone,
  473. packages for projects that build Rust code with cargo
  474. *MUST* use dynamically generated `BuildRequires`
  475. by calling the `%cargo_generate_buildrequires` macro
  476. in the `%generate_buildrequires` scriptlet.
  477. For example, a dependency on `serde = "1.0.100"`
  478. specified in a project's `Cargo.toml` metadata
  479. (a dependency on the crate named "serde",
  480. with version "1.0.100" or any version API-compatible with "1.0.100",
  481. with default features enabled)
  482. would cause a dependency like this to be generated for RPM:
  483. ....
  484. BuildRequires: (crate(serde/default) >= 1.0.100 with crate(serde/default) < 2.0.0~)
  485. ....
  486. Refer to the section about link:#_rpm_macros[RPM macros]
  487. for how to pass feature flags to this macro.
  488. Issues with the `%cargo_generate_buildrequires` macro
  489. that prevent it from being used for a package
  490. should be reported against https://pagure.io/fedora-rust/cargo2rpm[cargo2rpm],
  491. the tool that provides the functionality of this macro.
  492. === Subpackages for crate features
  493. Optional features / dependencies of Rust crates are translated into RPM subpackages
  494. to support resolving dependencies for features and optional dependencies of crates.
  495. The list of crate "features"
  496. (including any implicitly defined features for optional dependencies)
  497. *MUST* be kept in sync with the list of subpackages,
  498. i.e. for every feature `$foo` of the crate `$crate`,
  499. there must be a subpackage with name `rust-$crate+$foo-devel`,
  500. and vice-versa.
  501. This is required for RPM generators for `Provides` and `Requires`
  502. for these optional features / dependencies to work correctly.
  503. If optional features that are _not_ part of the default feature set
  504. are unused and would pull in additional (possibly unavailable) dependencies,
  505. the package *MAY* omit subpackages for these specific feature names.
  506. However, care needs to be taken
  507. that the features corresponding to the ommitted subpackages
  508. are not "reachable" via subpackages that have _not_ been omitted,
  509. since this would result in packages with unsatisfiable dependencies.
  510. Disabling optional features sometimes cannot be handled correctly
  511. simply by omitting subpackages for specific features.
  512. In these cases, the crate metadata in `Cargo.toml`
  513. needs to be patched accordinly instead.
  514. Beware that the "default" feature is always implicitly defined by cargo,
  515. even if the crate metadata does not contain a `[features]` table
  516. or an explicitly defined "default" feature,
  517. so the subpackage for the "default" feature
  518. will be present in all packages for Rust crates with a library interface.
  519. === RPM generators for `Provides` and `Requires`
  520. The cargo-rpm-macros package includes RPM generators
  521. for automatically generating `Provides` and `Requires`
  522. for Rust crates that comply with the Packaging Guidelines
  523. (i.e. install their files into the correct location, `%{crate_instdir}`).
  524. It is recommended to verify
  525. that the generated `Provides` and `Requires` are sane - for example,
  526. the following `Provides` and `Requires`
  527. must be present to ensure correct inter-subpackage dependencies:
  528. * the main `rust-$crate-devel` subpackage
  529. *MUST* provide `crate($crate) = %{version}`
  530. * the `rust-$crate+$feature-devel` subpackages
  531. *MUST* provide `crate($crate/$feature) = %{version}`
  532. and require `crate($crate) = %{version}` (i.e. `rust-$crate-devel`)
  533. Additionally, dependencies on external Rust crates must be as expected:
  534. * the main `rust-$crate-devel` subpackage
  535. *MUST* require the virtual `Provides` for all non-optional crate dependencies
  536. * the `rust-$crate+$feature-devel` subpackages
  537. *MUST* require the virtual `Provides` for the optional crate dependencies
  538. and features that are listed as the feature's dependencies in crate metadata
  539. === Packaging multiple versions
  540. In most circumstances,
  541. the latest version of a crate *SHOULD* be packaged,
  542. and - if possible - packagers *SHOULD* port crates
  543. to use the latest available version of their dependencies,
  544. and submit these patches to upstream
  545. to limit divergence between the upstream project and the Fedora package.
  546. However, there are two common scenarios
  547. in which it is often necessary to provide packages
  548. for multiple versions of a library crate simultaneously:
  549. * It is not feasible to port a crate
  550. to the version of a crate dependency in Fedora
  551. due to large API changes between the required and the packaged version.
  552. * The number of packages affected
  553. by a required SemVer-incompatible library update is very large.
  554. In these cases, a "compat package" can be created for the older version
  555. (i.e. usually the current version),
  556. and the suffix-less package can be updated to the newer version.
  557. https://pagure.io/fedora-rust/rust2rpm[rust2rpm]
  558. supports automatically creating "compat packages"
  559. with names that are compliant with the
  560. https://docs.fedoraproject.org/en-US/packaging-guidelines/Naming/#multiple[Naming Guidelines for this case]
  561. _and_ compatible with the restrictions of Semantic Versioning
  562. by using the `rust2rpm --compat` flag.
  563. All "compat packages" for Rust crates
  564. *MUST* follow the guidelines for Rust crates,
  565. and two additional rules apply when creating them:
  566. * For crates that also includes an executable,
  567. only the package for the _latest_ version can include this executable,
  568. and it *MUST NOT* be built and included in any older versions,
  569. to prevent both the name of the executable under `/usr/bin`
  570. and the name of the subpackage would conflict
  571. between the old and the new version of the package.
  572. * The packager *SHOULD* check
  573. whether running tests in the old version of the crate
  574. would cause additional, potentially undesirable dependencies,
  575. for example, older versions of other dependencies
  576. that would require creating additional "compat packages" -
  577. in this case, tests *SHOULD* be disabled
  578. (i.e. by flipping the `check` bcond).
  579. === The `check` bcond
  580. The behaviour of some RPM macros
  581. depends on the presence and value of the `_with_check` macro,
  582. i.e. if `%bcond_without check` or `%bcond_with check`
  583. are used in the spec file - notably,
  584. the `%cargo_generate_buildrequires` macro only includes `dev-dependencies`
  585. (i.e. dependencies that are only used
  586. for compiling and / or running a project's test suite with cargo)
  587. if the `check` bconf is enabled.
  588. Additionally, packages for Rust crates or workspace projects
  589. that are generated by https://pagure.io/fedora-rust/rust2rpm[rust2rpm]
  590. use the value of this macro to determine if the `%check` scriptlet is run.
  591. Packages *MUST* set this bcond
  592. to avoid unexpected behaviour of the `%cargo_*` macros,
  593. by either explicitly _enabling_ or _disabling_ tests.
  594. === Running tests
  595. Rust crates can have three different kinds of tests in their test suites:
  596. * _"unit tests"_:
  597. These tests are included
  598. alongside library / application source code in the `src/` directory,
  599. and can reference private APIs
  600. (similar to "glass-box" tests).
  601. * _"integration tests"_:
  602. These tests are usually separate files under the `tests/` directory,
  603. and they can only rely on public API of the tested crate
  604. (similar to "black-box" tests).
  605. * _"doctests"_:
  606. These tests are automatically extracted
  607. from code blocks in Markdown documentation,
  608. which is often used as a mechanism
  609. to ensure that code snippets in documentation for public methods
  610. are correct and continue to compile.
  611. By default, running `cargo test` (i.e. by calling the `%cargo_test` macro),
  612. all three kinds of tests are run.
  613. They can also be invoked separately
  614. (for example, because parts of the test suite or large data files are
  615. not included in published sources)
  616. by passing through filtering arguments
  617. to the underlying `cargo test` command:
  618. * `%cargo_test -- --lib`: only run _"unit tests"_ for the library interface
  619. * `%cargo_test -- --bin`: only run _"unit tests"_ for binaries
  620. * `%cargo_test -- --doc`: only run _"doctests"_
  621. * `%cargo_test -- --tests`: only run _"integration tests"_
  622. This can be combined with additional flags
  623. to skip tests with specific names
  624. (or that contain a specific string in their name)
  625. by passing the `--skip` argument through to the test harness
  626. (can be specified multiple times):
  627. ....
  628. %cargo_test -- --lib -- --skip foo::bar::tests::test1
  629. ....
  630. By default, cargo uses substring matching
  631. to match `--skip` arguments and actual names of tests,
  632. which can be turned off by using the `--exact` flag.
  633. If any tests are skipped or disabled,
  634. the package *SHOULD* include comments
  635. that explain why this is the case,
  636. and include links to upstream issues, if available.
  637. == Rust applications (non-crates.io crates)
  638. Most rules that apply to Rust crates
  639. that are published in https://crates.io[crates.io]
  640. also apply to Rust projects that _are_ built with cargo
  641. but _not_ published on https://crates.io[crates.io].
  642. https://pagure.io/fedora-rust/rust2rpm[rust2rpm]
  643. has basic support for generating spec files for this type of package
  644. by running `rust2rpm path/to/Cargo.toml` in unpacked upstream sources.
  645. Packages that fall into this category *MUST NOT* ship crate sources in `%{cargo_registry}`,
  646. i.e. they cannot ship `-devel` subpackages
  647. that contain crate sources or have subpackages
  648. that have virtual provides for `crate(...) = %{version}`.
  649. To prevent the `+%cargo_install+` macro
  650. from installing library sources into `%{cargo_registry}`,
  651. the `%cargo_install_lib` macro can be defined to `0`.
  652. When using rust2rpm with a path to a Cargo.toml file
  653. this macro definition is injected automatically.
  654. === Package naming
  655. Rust applications that are "crates"
  656. but which are not published on https://crates.io[crates.io]
  657. *MUST* be named according to the generic
  658. https://docs.fedoraproject.org/en-US/packaging-guidelines/Naming/[Naming Guidelines],
  659. i.e. they *MUST NOT* use a `rust-` prefix for the source package name.
  660. === Package sources
  661. The generic guidelines for
  662. https://docs.fedoraproject.org/en-US/packaging-guidelines/SourceURL/[referencing sources] apply.
  663. Notably, the `%{crates_source}` macro cannot be used for packages like this.
  664. == Rust applications (cargo workspace projects)
  665. Some Rust projects are organized as "cargo workspaces",
  666. which are collections of Rust crates
  667. that are often considered "internal implementation details".
  668. In most cases, these "internal" crates
  669. are not published individually on https://crates.io[crates.io].
  670. Projects that use this setup
  671. can be handled similarly to Rust projects
  672. that are organized as a single crate
  673. but not published on https://crates.io[crates.io].
  674. https://pagure.io/fedora-rust/rust2rpm[rust2rpm]
  675. has basic support for generating spec files for this type of package
  676. by running `rust2rpm path/to/Cargo.toml` in unpacked upstream sources,
  677. (where `./Cargo.toml` must be the path to the "workspace root",
  678. i.e. the `Cargo.toml` file that contains the `[workspace]` table).
  679. Packages that fall into this category
  680. *MUST NOT* ship crate sources in `%{cargo_registry}`,
  681. i.e. they cannot ship `-devel` subpackages that contain crate sources
  682. or have any subpackages that have virtual provides for `crate(...) = %{version}`.
  683. === Package naming
  684. Rust projects that are organized as "cargo workspaces"
  685. *MUST* be named according to the generic
  686. https://docs.fedoraproject.org/en-US/packaging-guidelines/Naming/[Naming Guidelines],
  687. i.e. they *MUST NOT* use a `rust-` prefix for the source package name.
  688. === Package sources
  689. The generic guidelines for
  690. https://docs.fedoraproject.org/en-US/packaging-guidelines/SourceURL/[referencing sources]
  691. apply.
  692. === RPM macros
  693. All `%cargo_*` macros have support for cargo workspaces
  694. as of `cargo-rpm-macros >= 24`.
  695. Any unexpected results that occur when using these macros for projects
  696. that are set up as a cargo workspace
  697. should be reported against https://pagure.io/fedora-rust/cargo2rpm[cargo2rpm].
  698. Note that currently, any `-a` and `-n` flags or `-f` arguments
  699. that are passed to `%cargo_generate_buildrequires`
  700. are applied to _all_ workspace members during dependency resolution.
  701. == Python projects
  702. Python packages that use https://github.com/PyO3/setuptools-rust[setuptools_rust]
  703. or https://github.com/PyO3/maturin[maturin]
  704. to build a "native" Python extension
  705. also need to apply the link:#_generic_rules[generic rules] for Rust packages
  706. in addition to following the
  707. https://docs.fedoraproject.org/en-US/packaging-guidelines/Python/[Python Packaging Guidelines].
  708. Both https://github.com/PyO3/setuptools-rust[setuptools_rust]
  709. and https://github.com/PyO3/maturin[maturin]
  710. build the native Python extension by calling cargo internally,
  711. so the basic setup for projects that build with cargo
  712. is required for packages like this as well.
  713. This includes calling `%cargo_prep` in `%prep`
  714. to set up the build environment for cargo,
  715. and using `%cargo_generate_buildrequires` to dynamically generate
  716. the appropriate `BuildRequires` for Rust crate dependencies.
  717. Additionally, `%cargo_license` and / or `%cargo_license_summary`
  718. *MUST* be used to determine the licenses
  719. that apply to the statically linked Python extension.
  720. The packager also *MUST* ensure
  721. that the default link:#_compiler_flags[compiler flags] are passed to rustc.
  722. == Mixed Rust / C/C++ projects
  723. Handling of projects that include both C/C++ and Rust code
  724. depends on how building the Rust code is integrated
  725. into the project's build system.
  726. Independent of the specific setup,
  727. the correct link:#_compiler_flags[compiler flags] *MUST* be passed to rustc,
  728. and the License tag of the package that contains the Rust component
  729. *MUST* take the licenses of statically linked crates into account.
  730. === Building with cargo internally
  731. Projects with build systems that call cargo internally to build Rust components
  732. *MUST* follow the same guidelines
  733. as other projects that build Rust code with cargo.
  734. Packages *MUST* ensure that the cargo calls
  735. that are internal to the project's build system
  736. do not pass flags or arguments that are incompatible
  737. with either the default link:#_compiler_flags[compiler flags] or cargo options
  738. that are set in the `%cargo_build` macro or configured by `%cargo_prep`.
  739. === Building with meson directly
  740. Upcoming versions of https://mesonbuild.com/Rust.html[meson]
  741. will have support for building crate dependencies
  742. by reading `Cargo.toml` files directly,
  743. with meson supporting a similar mechanism
  744. for overriding https://crates.io[crates.io] sources with a local registry.
  745. == Building shared libraries with cargo-c
  746. While it is not currently possible
  747. to build Rust crates as shared libraries,
  748. Rust projects can define a C-compatible public API
  749. so that they can be built as standard shared libraries with a C ABI.
  750. In most cases, libraries like this are built with
  751. https://crates.io/crates/cargo-c[cargo-c],
  752. which provides convenient wrappers (`cargo-cbuild` and `cargo-cinstall`)
  753. for both building and installing shared libraries
  754. (including support for generating and installing header files
  755. and and pkg-config files).
  756. The `cargo-c` package includes RPM macros for this functionality
  757. (`%cargo_cbuild` and `%cargo_cinstall`),
  758. which accept the same arguments as their cargo counterparts.
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...