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
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
|
// file : doc/packaging.cli
// license : MIT; see accompanying LICENSE file
"\name=build2-packaging-guide"
"\subject=toolchain"
"\title=Packaging Guide"
// NOTES
//
// - Maximum <pre> line is 70 characters.
//
// - In guideline titles (do/don't) omit a/the.
//
// @@ Close the issue in WISHLIST.
"
\h0#preface|Preface|
This document provides guidelines for converting third-party C/C++ projects to
the \c{build2} build system and making them available as packages from
\l{https://cppget.org cppget.org}, the \c{build2} community's central package
repository. For additional information, including documentation for individual
\c{build2} toolchain components, man pages, HOWTOs, etc., refer to the project
\l{https://build2.org/doc.xhtml Documentation} page.
\N|This document is a work in progress and is incomplete.|
\h1#intro|Introduction|
@@ Assume read through toolchain introduction and build system introduction.
Also, ideally, have some experience using \c{build2} in your own projects.
The aim of this guide is to ease the convertion of third-party C/C++ projects
to the \c{build2} build system and publishing them to the
\l{https://cppget.org cppget.org} package repository by codifying the best
practices and techniques. By following the presented guidelines you also make
it easier for others to review your work and help with ongoing maintenance.
The primary focus of this guide are existing C/C++ projects that use a
different build system and that are maintained by a third-party, which we will
refer to as \i{upstream}. Unless upstream is willing to incorporate support
for \c{build2} directly into their repository, such projects are normally
packaged for \c{build2} in a separate \c{git} repository under the
\l{https://github.com/build2-packaging github.com/build2-packaging}
organization. Note, however, that many of the presented guidelines are also
applicable when converting your own projects (that is, where you are the
upstream) as well as projects that use languages other than C or C++.
Most C/C++ packages that are published to \l{https://cppget.org cppget.org}
are either libraries or executables (projects that provide both are normally
split into several packages) with libraries being in the strong majority.
Libraries are also generally more difficult to build correctly. As a result,
this guide uses libraries as a baseline. In most cases, a library-specific
step is easily distinguished as such and can be skipped when dealing with
executables. And in cases where a more nuanced change is required, a note will
be provided.
At the high-level, packaging a third-party project involves the following
steps:
\ol|
\li|Create the \c{git} repository and import upstream source code.|
\li|Generate \c{buildfile} templates that match upstream layout.|
\li|Tweak the generated \c{buildfiles} to match upstream build.|
\li|Test using the \l{https://ci.cppget.org \c{build2} CI service}.|
\li|Publish the package to \l{https://cppget.org cppget.org}.|
|
Once this process is completed and the package is published, new releases
normally require a small amount of work provided there are no drastic changes
in the upstream layout or build. The sequence of steps for a new release would
typical look like this:
\ol|
\li|Add new and/or remove old upstream source code, if any.|
\li|Tweak \c{buildfiles} to match changes to upstream build, if any.|
\li|Test using the \l{https://ci.cppget.org \c{build2} CI service}.|
\li|Publish the package to \l{https://cppget.org cppget.org}.|
|
While packaging a simple library or executable is relatively straightforward,
the C and C++ languages and their ecosystem is famous for a large amount
varience in the platforms, compilers, and build systems used. This leads to
what appears to be an endless list of special considerations that are
applicable in certain, more complex cases.
As result, the presented guidelines are divided into four chapters: The
\l{#core Core Guidelines} cover steps that are applicable to all or most
packaging efforts. As mentioned earlier, these steps will assume packaging a
library but they should be easy to adapt to executables. This chapter is
followed by \l{#dont-do What Not to Do} which covers the common packaging
mistakes and omissions. These are unfortunately relatively common because
experience with other build systems often does not translate directly to
\c{build2} and some techniques (such as header-only libraries) are
discouraged. The last two chapters are \l{#howto HOWTO} and \l{#faq FAQ} which
cover the above-mentioned long list of special considerations that are only
applicable in certain cases as well as answer frequent packaging-related
questions, respectively.
@@ Purpose of notes to provide rationale.
Besides the presented guidelines you may also find the existing packages found
in \l{https://github.com/build2-packaging github.com/build2-packaging} a good
source of example material. The repositories pinned to the front page are the
recommended starting point.
\h#intro-term|Terminology|
upstream
upstream repository
project
package (third-party project)
package \c{git} repository
multi-package repository
\h1#core|Core Guidelines|
\h#core-repo|Setup the package repository|
This section covers the creation of the package \c{git} repository and
the importation of the upstream source code.
\h2#core-repo-exists|Check if package repository already exists|
Before deciding to package a third-party project you have presumably checked
on \l{https://cppget.org cppget.org} if someone has already packaged it. There
are several other places that make sense to check as well:
\ul|
\li|\l{https://queue.cppget.org queue.cppget.org} contains packages that
have been submitted but not yet published.|
\li|\l{https://queue.stage.build2.org queue.stage.build2.org} contains
packages that have been submitted but can only be published after the next
release of the \c{build2} toolchain (see \l{#faq-publish-stage Where to
publish if package requires staged toolchain?} for background).|
\li|\l{https://github.com/build2-packaging github.com/build2-packaging}
contains all the third-party package repositories. Someone could already be
working on the package but haven't they finished it.|
\li|\l{https://github.com/build2-packaging/WISHLIST/issues
github.com/build2-packaging/WISHLIST} contains as issues projects that people
wish were packaged. These may contain offers to collaborate or announcements
of ongoing work.||
In all these cases you should be able to locate the package \c{git} repository
and/or connect with others in order to collaborate on the packaging work. If
the existing effort looks abandoned (for example, there hasn't been any
progress for a while and the existing maintainer doesn't respond) and you
would like to take over the package,
\l{https://build2.org/community.xhtml#help get in touch}.
\h2#core-repo-name|Use upstream repository name as package repository name|
It is almost always best to use the upstream repository name as the package
repository name. If there is no upstream repository (for example, because the
project doesn't use a version control system), the name used in the source
archive distribution would be the natural fallback.
\N|See \l{#core-package-name Decide on the package name} for the complete
picture on choosing names.|
\h2#core-repo-create|Create package repository in personal workspace|
For a third-party project, the end result that we are aiming for is a package
repository under the \l{https://github.com/build2-packaging
github.com/build2-packaging} organization.
\N|We require all the third-party projects that are published to
\l{https://cppget.org cppget.org} to be under the
\l{https://github.com/build2-packaging github.com/build2-packaging}
organization in order to ensure some continuity in case the original
maintainer loose interest, etc. You will still be the owner of the repository
and by hosting your packaging efforts under this organization (as opposed to,
say, your personal workspace) you make it easier for others to discover your
work and to contribute to the package maintenance.
Note that this requirement does not apply to your own projects (that is, where
you are the upstream) and where the \c{build2} support is normally part of the
upstream repository.
Finally, a note on the use of \c{git} and GitHub: if for some reason you are
unable to use either, \l{https://build2.org/community.xhtml#help get in touch}
to discuss alternatives.|
However, the recommended approach is to start with a repository in your
personal workspace and then, when it is ready or in a reasonably stable shape,
transfer it to \l{https://github.com/build2-packaging
github.com/build2-packaging}. This gives you the freedom to make destructive
changes to the repository (including deleting it and strating over) during the
initial packaging work. It also removes the pressure to perform: you can give
it a try and if things turn out more difficult than you expected, you can
just drop the repository.
\N|For repositories under \l{https://github.com/build2-packaging
github.com/build2-packaging} the \c{master}/\c{main} branch is protected: it
cannot be deleted and its commit history cannot be overwritten with a forced
push.|
\N|While you can use any name for a repository under the personal workspace,
under \l{https://github.com/build2-packaging github.com/build2-packaging} it
should follow the \l{core-repo-name Use upstream repository name as package
repository name} guideline. In particular, there should be no prefixes like
\c{build2-} or suffixes like \c{-package}. If the repository under your
personal workspace does not follow this guideline, you should rename it before
transferring it to the \l{https://github.com/build2-packaging
github.com/build2-packaging} organization.|
There is one potenential problem with this approach: it is possible that
several people start working on the same third-party project without being
aware of each other's efforts. If the project you are packaging is relatively
small and you don't expect it to take more than a day or two, then this is
probably not worth worrying about. For bigger projects, however, it makes
sense to announce your work by creating (or updating) the corresponding issue
in \l{https://github.com/build2-packaging/WISHLIST
github.com/build2-packaging/WISHLIST}.
To put it all together, the recommended sequence of actions for this step:
\ol|
\li|Create a new empty repository under your personal workspace from GitHub
UI. Don't automatically add any files (\c{README}, \c{LICENSE}, etc).|
\li|Set the repository description in GitHub UI to the \c{build2 package
for <name>} line, where \c{<name>} is the project name.|
\li|Clone the repository to your machine.||
\N|Since this is your personal repository, you can do the initial work
directly in \c{master}/\c{main} or in a separate branch, it's up to you.|
As a running example, let's assume we want to package a library called \c{foo}
whose upstream repository is at \c{https://github.com/<upstream>/foo.git}. We
have created its package repository at
\c{https://github.com/<personal>/foo.git} (with the \c{build2 package for foo}
description) and can now clone it:
\
$ git clone https://github.com/<personal>/foo.git
\
\h2#core-repo-init|Initialize package repository with \c{bdep new --type empty}|
Change to the root directory of the package repository that you have clonned
on the previous step and run (continuing with our \c{foo} example):
\
$ cd foo
$ bdep new --type empty
$ tree .
./
├── .gitattributes
├── .gitignore
├── README.md
└── repositories.manifest
\
This command creates a number of files in the root of the repository:
\dl|
\li|\n\c{README.md}\n
This is the project \c{README}. We will discuss the recommended content for
this file later.|
\li|\n\c{repositories.manifest}\n
This file specifies the repositories from which this project will obtain its
dependencies (see \l{intro#guide-add-remove-deps Adding and Removing
Dependencies}). If the project you are packaging has no dependencies, then you
can safely remove this file (it's easy to add later if this changes). And for
projects that do have dependecies we will discuss the appropriate changes to
this file later.|
\li|\n\c{.gitattributes} and \c{.gitignore}\n
These are the \c{git} infrastrucutre files for the repository. You shouldn't
normally need to change anything in them at this stage (see the comments
inside for details).||
Next add and commit these files:
\
$ git add .
$ git status
$ git commit -m \"Initialize repository\"
\
\N|In these guidelines we will be using the package repository setup that is
capable of having multiple packages. This is recommended even for upstream
projects that only provides a single package because it gives us the
flexibility of adding new packages at a later stage without having to perform
a major restructuring of our repository.
Note also that upstream providing multiple package is not the only reason we
may end up having multiple \c{build2} packages. Another common reason is
factoring tests into a separate package due to a dependency on a testing
framework
(see \l{https://github.com/build2/HOWTO/blob/master/entries/handle-tests-with-extra-dependencies.md
How do I handle tests that have extra dependencies?} for background and
details). While upstream adding new packages may not be very common, upstream
deciding to use a testing framework is a lot more plausible.
The only notable drawback of using a multi-package setup with a single package
is the extra subdirectory for the package and a few extra files (such as
\c{packages.manifest} that lists the packages) in the root of the repository.
If you are certain that the project that you are converting is unlikely to
have multiple packages (for example, because you are the upstream) or need
extra dependencies for its tests (a reasonable assumption for a C project),
then you could instead go with the single-package repository where the
repository root is the package root. See \l{bdep-new(1)} for details on how to
initialize such a repository. In this guide, however, we will continue to
assume a multi-package repository setup.|
\h2#core-repo-submodule|Add upstream repository as \c{git} submodule|
If the third-party project is available from a \c{git} repository, then the
recommended approach is to use the \c{git} submodule mechanism to make the
upstream source code available inside the package repository, customarily in a
subdirectory called \c{upstream/}.
\N|While \c{git} submodules receive much criticism, in our case we use them
exactly as indended: to select and track specific (release) commits of an
external project. As a result, there is nothing tricky about their use for our
purpose and all the relevant commands will be provided and explained, in case
you are not familiar with this \c{git} mechanism.|
Given the upstream repository URL, to add it as a submodule, run the following
command from the package repository root (continuing with our \c{foo} example):
\
$ git submodule add https://github.com/<upstream>/foo.git upstream
\
\N|You should prefer \c{https://} over \c{git://} for the upstream repository
URL since the \c{git://} protocol may not be accessible from all networks.
Naturally, never use a URL that requires authentication, for example, SSH.|
Besides the repository URL, you also need the commit of the upstream release
which you will be packaging. It is common practice to tag releases so the
upstream tags would be the first place to check. Failed that, you can always
use the commit id.
Assuming the upstream release tag you are interested in is called \c{vX.Y.Z},
to update the \c{upstream} submodule to point to this release commit, run the
following command:
\
$ cd upstream
$ git checkout vX.Y.Z
$ cd ..
\
Then add and commit these changes:
\
$ git add .
$ git status
$ git commit -m \"Add upstream submodule\"
\
Now we have all the upstream source code for the release that we are
interested in available in the \c{upstream/} subdirectory of our repository.
The plan is to then use symbolic links (symlinks) to non-invasively overlay
the \c{build2} files (\c{buildfile}, \c{manifest}, etc) with the upstream
source code, if necessary adjusting upstream structure to split it into
multiple packages and/or to better align with the source/output layouts
recommended by \c{build2} (see \l{https://build2.org/article/symlinks.xhtml
Using Symlinks in \c{build2} Projects} for background and rationale). But
before we can start adding symlinks to the upstream source (and other files
like \c{README}, \c{LICENSE}, etc), we want to generate the \c{buildfile}
templates that match the upstream source code layout. This is the subject of
the next section.
\N|While on UNIX-like operating systems symlinks are in widespread use, on
Windows it's a niche feature that unfortunately could be cumbersome to use
(see \l{https://build2.org/article/symlinks.xhtml#windows Symlinks and
Windows} for details). However, the flexibility afforded by symlinks when
packaging third-party projects is unmatched by any other mechanism and we
therefore use them despite potentially sub-optimal experience on Windows.|
\h#core-package|Create package and generate \c{buildfile} templates|
This section covers the addition of the package to the repository we have
prepared in the previous steps and the generation of the \c{buildfile}
templates that match the upstream source code layout.
\h2#core-package-name|Decide on the package name|
While choosing the package repository name was pretty straightforward, things
get less clear cut when it comes to the package name.
\N|If you need a refresher on the distinction between projects and packages,
see \l{#intro-term Terminology}.|
Picking a name for a package that provides an executable is still relatively
straightforward: you should use the upstream name (which is usually the same
as the upstream project name) unless there is a good reason to deviate. One
recommended place to check before deciding on a name is the
\l{https://packages.debian.org Debian package repository}. If their package
name differs from upstream, then there is likely a good reason for that and
it is worth trying to understand what it is.
\N|Tip: when trying to find the corresponding Debain package, search for the
executable file name in the package contents if you cannot fine the package by
its upstream name. Also consider searching in the \c{unstable} distribution in
addition to \c{testing} for newer packages.|
Picking a name for a package that provides a library is where things can get
more complicated. While all the recommendation that have been listed for
executables apply equally to libraries, there are additional considerations.
In \c{build2} we recommend (but not require) that new library projects use a
name that starts with \c{lib} in order to easily distinguish them from
executables and avoid any clashes, potential in the future (see
\l{intro#proj-struct Canonical Project Structure} for details). To illustrate
the problem, consider the \c{zstd} project which provides a library and an
executable. In upstream repository both are part of the same codebase that
doesn't try to separate them into packages so that, for example, library could
be used without downloading and building the executable. In \c{build2},
however, we do need to split them into two separate packages and both packages
cannot be called \c{zstd}. So we call them \c{zstd} and \c{libzstd}.
\N|If you are familiar with the Debian package naming policy, you will
undoubtedly recognize the approach. In Debian all the library packages (with
very few exceptions) start with the \c{lib} prefix. So when searching for an
upstream name in the \l{https://packages.debian.org Debian package repository}
make sure to prefix it with \c{lib} (unless it already starts with this
prefix, of course).|
This brings the question of what to do about third-party libraries: should we
add the \c{lib} prefix to the package name if it's not already there?
Unfortunately, there is no clear cut answer and whichever decision you make,
there will be drawbacks. Specifically, if you add the \c{lib} prefix, the main
drawback is that the package name now deviates from upstream name and if the
project maintainer ever decides to add \c{build2} support the upstream
repository, there could be substantial friction. On the other handle, if you
don't add the \c{lib} prefix, then you will always run the risk of a future
clash with an executable name. And, as was illustrated with the \c{zstd}
example, a late addition of an executable won't necessarily cause any issues
to upstream. As a result, we don't have a hard requirement for the \c{lib}
prefix unless there is already an executable that would cause the clash (this
applies even if it's not being packaged yet or is provided by an unrelated
project). If you don't have a strong preference, we recommend that you add the
\c{lib} prefix (unless it is already there). In particular, this will free you
from having to check for any potential clashes. See
\l{https://github.com/build2/HOWTO/blob/master/entries/name-packages-in-project.md
How should I name packages when packaging third-party projects?} for
additional background and details.
To build some intuition for choosing package names, let's consider several
real examples. We start with executables:
\
upstream | upstream | Debian | build2 package| build2
project name|executable name|package name|repository name|package name
------------+---------------+------------+---------------+------------
byacc byacc byacc byacc byacc
sqlite sqlite3 sqlite3 sqlite sqlite3
vim xxd xxd xxd xxd
OpenBSD m4 - openbsd-m4 openbsd-m4
qtbase 5 moc qtbase5-\ Qt5 Qt5Moc
dev-tools
qtbase 6 moc qt6-base-\ Qt6 Qt6Moc
dev-tools
\
The examples are arranged from the most straightforward naming to the
least. The last two examples show that sometimes, after carefully considering
upstream naming, you nevertheless have no choice but to ignore it and forge
your own path.
Next let's look at library examples. Notice that some use the same \c{build2}
package repository name as the executables above. That means they are part of
the same multi-package repository.
\
upstream | upstream | Debian | build2 package| build2
project name|library name |package name|repository name|package name
------------+---------------+------------+---------------+------------
libevent libevent libevent libevent libevent
brotli brotli libbrotli brotli libbrotli
zlib zlib zlib zlib libz
sqlite libsqlite3 libsqlite3 sqlite libsqlite3
libsig\ libsigc++ libsigc++ libsig\ libsigc++
cplusplus cplusplus
qtbase 5 QtCore qtbase5-dev Qt5 libQt5Core
qtbase 6 QtCore qt6-base-dev Qt6 libQt6Core
\
If an upstream project is just a single library, then the project name is
normally the same as the library name (but there are exceptions, like
\c{libsigcplusplus} in the above table). However, when looking at upstream
repository that contains multiple components (libraries and/or executables,
like \c{qtcore} in the above example), it may not be immediately obvious what
the upstream's library names are. In such cases, the corresponding Debian
packages can really help clarify the situation. Failed that, look into the
existing build system. In particular, if it generates the \c{pkg-config} file,
then the name of this file is usually the upstream library name.
\N|Looking at the names of the library binaries is less helpful because on
UNIX-like systems they must start with the \c{lib} prefix. And on Windows the
names of library binaries often embed extra information (static/import,
debug/release, etc) and may not correspond directly to the library name.|
And, speaking of multiple components, if you realize the upstream project
provides multiple libraries and/or executables, then you need to decide
whether to split them into seperate \c{build2} packages and if so, how. Here,
again, the corresponding Debian packages can be a good strating point. Note,
however, that in this case we often deviate from their split, especially when
it comes to libraries. For example, \c{libevent} shown in the above table
provides several libraries (\c{libevent-core}, \c{libevent-extra}, etc) and in
Debian it is actually split into several binary packages along these lines. In
\c{build2}, however, there is a single package that provides all these
libraries with everything except \c{libevent-core} being optional. An example
which shows the decision made in a different direction would be the Boost
libraries: in Debian all the header-only Boost libraries are bundled into a
single package while in \c{build2} they are all seperate packages.
The overall criteria here can be stated as follows: if a small family of
libraries provide complimentary functionality (like \c{libevent}), then we put
them all into a single package, usually making the additional functionality
optional. However, if the libraries are independent (like Boost) or provide
alternative rather than complimentary functionality (for example, like
different backends in \c{imgui}), then we make them separate packages. Note
that we never bundle an executable and a (public) library in a single package.
Note also that while it's a good idea to decide on the package split and all
the package names upfront to avoid suprises later, you don't have to actually
provide all the packages right away. For example, if upstream provides a
library and an executable (like \c{zstd}), you can start with the library and
the executable package can be added later (potentially by someone else).
Admittedly, the recommendation in this section are all a bit fuzzy and one can
choose different names or different package splits that could all seem
reasonable. If you are unsure how to split the upstream project or what names
to use, \l{https://build2.org/community.xhtml#help get in touch} to discuss
the alternatives. It can be quite painful to change these things after you
have completed the remaining packaging steps.
Continuing with our \c{foo} example, we will follow the recommendation and
call the library package \c{libfoo}.
\h2#core-package-struct|Decide on the package source code layout|
Another aspect we need to decide on is the source code layout inside the
package. Here we want to stay as close to upstream layout as possible unless
there are valid reasons to deviate. This has the best chance of giving us a
build without any compile errors since the header inclusion in the project can
be sensitive to this layout. This also makes it easier for upstream to adopt
the \c{build2} build.
Sometimes, however, there are good reasons for deviating from upstream,
especially in cases where upstream is clearly following bad practices, for
example including generically-named public headers without the library name as
a subdirectory prefix. If you do decide to change the layout, it's usually
less disruptive (to the build) to rearrange things at the outer levels than at
the inner. For example, it should normally be possible to move/rename the
top-level \c{tests/} directory or to place the library source files into a
subdirectory.
Our overall plan for the package is to create the initial layout and
\c{buildfile} templates automatically using \l{bdep-new(1)} in the
\c{--package} mode, then tweak \c{buildfile}s if necessary, and finally
\"fill\" the package with upstream source code using symlinks.
The main rationale for using \l{bdep-new(1)} instead of doing everything by
hand is that there are many nuances in getting the build right and
auto-generated \c{buildfile}s had years of refinement and fine-tuning. The
familiar structure also makes it easier for others to understand your build,
for example while reviewing your package submission.
The \l{bdep-new(1)} command supports a wide variety of
\l{bdep-new.xhtml#src-layout source layouts}. While it may take a bit of time
to understand the customization points necessary to achieve the desired layout
for your first package, this will pay off in spades when you work on
converting subsequent packages.
And so the focus of the following several steps is to iteratively discover the
\l{bdep-new(1)} command line that best approximates the upstream layout. The
recommended procedure is as follows:
\ol|
\li|\nStudy the upstream source layout and existing build system.|
\li|\nCraft and execute the \l{bdep-new(1)} command line necessary to achieve
the upstream layout.|
\li|\nStudy the auto-generated \c{buildfile}s for things that don't fit and
need to change. But don't rush to start manually editing the result. First get
an overview of the required changes and then check if it's possible to achieve
these changes automatically using one of \l{bdep-new(1)} sub-options. If
that's the case, delete the package subdirectory, and restart from step #2.||
This and the following two sections discuss each of these steps in more detail
and also look at some examples.
The first step above is to study the upstream project in order to understand
where the various parts are (headers, sources, etc.) and how they are built.
Things that can help here include:
\ul|
\li|Read through the existing build system definitions.|
\li|Try to build the project using the existing build system.|
\li|Try to install the project using the existing build system.|
\li|Look into the Debian package contents to see if there are any differences
with regards to the installation locations.||
For libraries, the first key pieces of information we need to find is how the
public headers are included and where they are installed. The two common
\i{good} practices is to either include the public headers with a library name
as a subdirectory, for example, \c{#include\ <foo/util.h>}, or to include the
library name into each public header name, for example, \c{#include\
<foo_util.h>} or \c{#include\ <foo.h>} (in the last example the header name is
the library name itself, which is also fairly common). Unfortunately, there is
also a fairly common \i{bad} practice: having generically named headers (such
as \c{util.h}) included without the library name as a subdirectory.
\N|The reason this is a bad practice is that libraries that have such headers
cannot coexist, neither in the same build nor when installed. See
\l{intro#proj-struct Canonical Project Structure} for background and details.
See \l{#howto-bad-inclusion-practice How do I deal with bad header inclusion
practice} if you encounter such a case.|
Where should we look to get this information? While the library source files
sound like a natural place, oftentimes they include own headers with the
\c{\"\"} style inclusion, either because the headers are in the same directory
or because the library build arranges for them to be found this way with
additional header search paths. As a result, a better place to look could be
library's examples and/or tests. Some libraries also describe which headers
they provide and how to include them in their documentation.
The way public headers are included normally determines where they are
installed. If they are included with a subdirectory, then they are normally
installed into the same subdirectory in, say, \c{/usr/include/}. Continuing
with the above example, a header that is included as \c{<foo/util.h>} would
normally be installed as \c{/usr/include/foo/util.h}. On the other hand, if
the library name is part of the header name, then the headers are usually (but
not always) installed directly into, say, \c{/usr/include/}, for example as
\c{/usr/include/foo_util.h}.
\N|While these are the commonly used installation schemes, there are
deviations. In particular, in both cases upstream may choose to add an
additional subdirectory when installing (so the above examples we instead end
up with, say, \c{/usr/include/foo_v1/foo/util.h} and
\c{/usr/include/foo_v1/sub/foo_util.h}). See
\l{#howto-extra-header-install-subdir How do I handle extra header
installation subdirectory} if you encounter such a case.|
The inclusion scheme would normally be recreated in the upstream source code
layout. In particular, if upstream includes public headers with a subdirectory
prefix, then this subdirectory would normally also be present in the upstream
layout so that such a header can be included form the upstream codebase
directly. As an example, let's say we determined that public headers of
\c{libfoo} are included with the \c{foo/} subdirectory, such as
\c{<foo/util.hpp>}. One of the typical upstream layouts for such a library
would look like this:
\
$ tree upstream/
upstream/
├── include/
│ └── foo/
│ └── util.hpp
└── src/
├── priv.hpp
└── util.cpp
\
Notice how the \c{util.hpp} header is in the \c{foo/} subdirectory rather
than in \c{include/} directly.
The second key pieces of information we need to find is whether and, if so,
how the public headers and sources are split. For instance, in the above
example, we can see that public headers go into \c{include/} while sources and
private headers go into \c{src/}. But they could also be combined in the same
directory, for example, as in the following layout:
\
upstream/
└── foo/
├── priv.hpp
├── util.cpp
└── util.hpp
\
\N|In multi-package projects, for example, those that provide both a library
and an executable, you would also want to understand how the sources are split
between the packages.|
If the headers and sources are split into different directories, then the
source directory may or may not have the inclusion subdirectory, similar to
the header directory. In the above split layout the \c{src/} directory doesn't
contain the inclusion subdirectory (\c{foo/}) while the following layout does:
\
upstream/
├── include/
│ └── foo/
│ └── util.hpp
└── src/
└── foo/
├── priv.hpp
└── util.cpp
\
With the understanding of these key properties of upstream layout you should
be in a good position to start crafting the \l{bdep-new(1)} command line that
recreates it.
\N|The \c{bdep-new} documentation uses a slightly more general terminology
compared to what we used in the previous section in order to also be
applicable to projects that use modules instead of headers.
Specifically, the inclusion subdirectory (\c{foo/}) is called \i{source
subdirectory} while the header directory (\c{include/}) and source directory
(\c{src/}) are called \i{header prefix} and \i{source prefix}, respectively.|
\h2#core-package-craft-cmd|Craft \c{bdep new} command line to create package|
The recommened procedure for this step is to read through the \c{bdep-new}'s
\l{bdep-new.xhtml#src-layout SOURCE LAYOUT} section (which contains a large
number of examples) while experimenting with various options in an attempt to
create the desired layout. If the layout you've got isn't quite right yet,
simply remove the package directory along with the \c{packages.manifest} file
and try again.
Let's illustrate this approach on the original example of the split layout:
\
upstream/
├── include/
│ └── foo/
│ └── util.hpp
└── src/
├── priv.hpp
└── util.cpp
\
We know it's split, so let's start with that and see what we get. Remember,
our \c{foo} package repository that we have clonned and initialized earlier
looks like this:
\
$ tree foo/
foo/
├── .gitattributes
├── .gitignore
├── README.md
└── repositories.manifest
\
Now we create the \c{libfoo} package inside:
\
$ cd foo
$ bdep new --package --lang c++ --type lib,split libfoo
$ tree libfoo/
libfoo/
├── include/
│ └── libfoo/
│ └── foo.hxx
└── src/
└── libfoo/
└── foo.cxx
\
The outer structure looks right, but inside \c{include/} and \c{src/} things
are a bit off. Specifically, the source subdirectory should be \c{foo/}, not
\c{libfoo/}, there shouldn't be one inside \c{src/}, and the file extensions
don't match upstream. All this can be easily tweaked, however:
\
$ rm -r libfoo/ packages.manifest
$ bdep new --package \
--lang c++,cpp \
--type lib,split,subdir=foo,no-subdir-source \
libfoo
$ tree libfoo/
libfoo/
├── include/
│ └── foo/
│ └── foo.hpp
└── src/
└── foo.cpp
\
The other \c{bdep-new} sub-options (see the \l{bdep-new(1)} man page for the
complete list) that you will likely want to use when packaging a third-party
project include:
\dl|
\li|\n\cb{no-version}
Omit the auto-generated version header. Usually upstream will provided its own
equivalent to this functionality.
\N|Note that even if upstream doesn't provide any version information, it's
not a good idea to try to rectify this by providing your own version header
since upstream may add it in a future version and you may end up with a
conflict. Instead, work with the project maintainer to rectify this in
upstream.||
\li|\n\cb{no-symexport}\n\cb{auto-symexport}
The \c{no-symexport} sub-option suppresses the generation of the DLL symbol
exporting header. This is an appropriate option if upstream provides its
own symbol exporting arrangements.
The \c{auto-symexport} sub-option enables automatic DLL symbol exporting
support (see \l{b##cc-auto-symexport Automatic DLL Symbol Exporting} for
background). This is an appropriate option if upstream relies on similar
support in the existing build system. It is also recommended that you give
this functionality a try even if upstream does not support building
shared libraries on Windows.|
\li|\n\cb{binless}
Create a header-only library. See \l{#dont-header-only Don't make
library header-only if it can be compiled} and
\l{https://github.com/build2/HOWTO/blob/master/entries/make-header-only-library.md
How do I make a header-only C/C++ library?}|
\li|\n\cb{buildfile-in-prefix}
Place header/source \c{buildfile}s into the header/source prefix directory
instead of source subdirectory. To illustrate the difference, compare these
two auto-generated layouts paying attention to the location of \c{buildfile}s:
\
$ bdep new ... --type lib,split,subdir=foo libfoo
$ tree libfoo/
libfoo/
├── include/
│ └── foo/
│ ├── buildfile
│ └── foo.hpp
└── src/
└── foo/
├── buildfile
└── foo.cpp
\
\
$ bdep new ... --type lib,split,subdir=foo,buildfile-in-prefix libfoo
$ tree libfoo/
libfoo/
├── include/
│ ├── foo/
│ │ └── foo.hpp
│ └── buildfile
└── src/
├── foo/
│ └── foo.cpp
└── buildfile
\
Note that this sub-option only makes sense if we have the header and/or source
prefixes (\c{include/} and \c{src/} in our case) as well as the source
subdirectory (\c{foo/} in our case).
Why would we want to do this? The main reason is to be able to symlink the
entire upstream directories rather than individual files. In the first
listing, the generated \c{buildfile}s are inside the \c{foo/} subdirectories
which mean we cannot just symlink \c{foo/} from upstream.
With a large number of files to symlink, this can be such a strong motivation
that it may make sense to invent a source subdirectory in the source prefix
even if upstream doesn't have one. See \l{#dont-main-target-root-buildfile
Don't build your main targets in root \c{buldfile}} for details on this
technique.
Another reason we may want to move \c{buildfile}s to prefix is to be able to
handle upstream projects that have multiple source subdirectories. While this
situation is not very common in the header prefix, it can be enountered in the
source prefix of more complex projects, where upstream wishes to organize the
source files into components.||
Continuing with our \c{libfoo} example, assuming upstream provides own symbol
exporting, the final \c{bdep-new} command line would be:
\
$ bdep new --package \
--lang c++,cpp \
--type lib,split,subdir=foo,no-subdir-source,no-version,no-symexport \
libfoo
\
\h2#core-package-review|Review and test auto-genetated \c{buildfile} templates|
Let's get a more complete view of what got generated by the final \c{bdep-new}
command line from the previous section:
\
$ tree libfoo/
libfoo/
├── build/
│ └── ...
├── include/
│ └── foo/
│ ├── buildfile
│ └── foo.hpp
├── src/
│ ├── buildfile
│ └── foo.cpp
├── tests/
│ ├── build/
│ │ └── ...
│ ├── basics/
│ │ ├── buildfile
│ │ └── driver.cpp
│ └── buildfile
├── buildfile
├── manifest
└── README.md
\
Once the overall layout looks right, the next step is to take a closer look at
the generated \c{buildfile}s to make sure that overall they match the upstrem
build. Of particular interest are the header and source directory
\c{buildfile}s (\c{libfoo/include/foo/buildifle} and \c{libfoo/src/buildifle}
in the above listing) which define how the library is built and installed.
Here we are focusing on the macro-level differences that are easier to change
by tweaking the \c{bdep-new} command line rather than manually. For example,
if we look at the generated source directory \c{buildfile} and realize it
builds a \i{binful} library (that is, a library that includes source files and
therefore produces library binaries) while the upsteam library is header-only,
it is much easier to fix this by re-running \c{bdep-new} with the \c{binless}
sub-option than by changing the \c{buildfile}s manually.
\N|Don't be tempted to start making manual changes at this stage even if you
cannot see anything else that can be fixed with a \c{bdep-new} re-run. This
is still a dry-run and we will recreate the package one more time in the
following section before starting manual adjustments.|
Besides examining the generated \c{buildfile}s, it's also a good idea to
build, test, and install the generated package to make sure everything ends up
where you expected and matches upstream where necessary. In particular, make
sure public headers are installed into the same location as upstream.
\N|The \c{bdep-new}-generated library is a simple \"Hello, World!\" example
that can nevertheless be built, tested, and installed. The idea here is to
verify it matches upstream using the generated source files before replacing
them with the upstream source file symlinks.|
Note that at this stage its easiest to build, test, and install in source
directly sidestepping the \c{bdep} initialization of the package (which you
would have to de-initalize before you can re-run \c{bdep-new}). Continue
with the above example, the recommended sequence of commands would be:
\
$ cd libfoo
$ b update
$ b test
$ b install config.install.root=/tmp/install
$ b clean
\
Let's also briefly discuss other subdirectories and files found in the
\c{bdep-new}-generated \c{libfoo} package.
The \c{build/} subdirectory is the standard \c{build2} place for project-wide
build system information (see \l{b#intro-proj-struct Project Structure} for
details). We will look closer at its contents in the following sections.
In the root directory of our package we find the root \c{buildfile} and
package \c{manifest}. We will be tweaking both in the following steps. There
is also \c{README.md} which we will replace with the upstream symlink.
The \c{tests/} subdirectory is the standard \c{build2} tests subproject (see
\l{b#intro-operations-test Testing} for details). While you can suppress its
generation with the \c{no-tests} \c{bdep-new} sub-option, we recommend that
you keep it and use it as a starting point for porting upstream tests or, if
upstream doesn't provide any, for a basic \"smoke test\" (@@ ref HOWTO).
\N|You can easily add/remove/rename this \c{tests/} subproject. The only place
where it is mentioned explicitly and where you will need to make changes is
the root \c{buildfile}. In pacticular, if upstream provides examples that you
wish to port, it is recommended that you use a copy of the generated
\c{tests/} subproject as a starting point (not forgeting to add the
corresponding entry in the root \c{buildfile}).|
\h2#core-package-create|Create final package|
If you are satisfied with the \c{bdep-new} command line and there are no more
automatic adjustments you can squeeze out of it, then it's time to re-run
\c{bdep-new} one last time to create the final package.
\N|While redoing this step later will require more effort, especially if
you've made manual modifications to \c{buildfile} and \c{manifest}, nothing is
set in stone and it can be done again by simply removing the package directory
and removing (or editing, if you have multiple packages and only want to redo
some of them) \c{packages.manifest} and starting over.|
This time, however, we will do things a bit differently in order to take
advantage of some additional automation offered by \c{bdep-new}. If the
package directory already exists and contains certain files, \c{bdep-new} can
take this into account when generating the root \c{buildfile} and package
\c{manifest}. In particular, it will try to guess the license from the
\c{LICENSE} file and extract the summary from \c{README.md} and use this
information in \c{manifest}.
\N|If the file names or formats used by upstream don't match those recognized
by \c{bdep-new} or if an attempt to extra the information is unsuccessful,
then for now simply omit the corresponding files from the package directory
and add them later manually.
Specifically, for \c{README}, \c{bdep-new} only recognizes \c{README.md}.
For license files, \c{bdep-new} recognizes \c{LICENSE}, \c{LICENSE.txt}
\c{LICENSE.md}, \c{COPYING}, and \c{UNLICENSE}.
@@ TODO: PACKAGE-README.md and README-PACKAGE.md (and below)
|
Continuing with our \c{libfoo} example and assuming upstream provides the
\c{README.md} and \c{LICENSE} files, we first manually create the package
directory, then add the symlinks, and finally run \c{bdep-new} (notice that we
have omitted the package name from the \c{bdep-new} command line since we are
running from inside the package directory):
\
$ cd foo/ # Change to the package repository root.
$ rm -r libfoo/ packages.manifest
$ cd foo/ # Change to the package root.
$ mkdir libfoo/
$ ln -s ../upstream/README.md ./
$ ln -s ../upstream/LICENSE ./
$ bdep new --package \
--lang c++,cpp \
--type lib,split,subdir=foo,no-subdir-source,no-version,no-symexport
\
If auto-detection succeeds, then you should see the \c{summary} and
\c{license} values automatically populated in \c{manifest} and the symlinked
files listed in the root \c{buildfile}.
\h#core-adjust|Fill package and adjust \c{buildfiles}, \c{manifest}, etc|
@@ What should be the order? E.g., cannot build without dependencies.
- when do we bdep-init it? Maybe do it with generated code?
@@ repository.manifest if have dependencies
@@ Any other upstream files besides source? Doc?
@@ The 'Don't write buildfiles by hand entry' is now mostly duplicate/redundant.
======================================================================
\h1#dont-do|What Not to Do|
\h#dont-from-scratch|Don't write \c{buildfile}s from scratch, use \c{bdep-new}|
Unless you have good reasons not to, create the initial project layout
automatically using \l{bdep-new(1)}, then tweak it if necessary and fill with
upstream source code.
The main rationale here is that there are many nuances in getting the build
right and auto-generated \c{buildfile}s had years of refinement and
fine-tuning. The familiar structure also makes it easier for others to
understand your build, for example while reviewing your package submission.
The \l{bdep-new(1)} command supports a wide variety of
\l{bdep-new.xhtml#src-layout source layouts}. While it may take a bit of time
to understand the customization points necessary to achieve the desired layout
for your first package, this will pay off in spades when you work on
converting subsequent packages. The recommended sequence of steps is
as follows:
\ol|
\li|Study the upstream source layout. We want to stay as close to upstream as
possible since this has the best chance of producing an issues-free result
(see \l{#dont-change-upstream Don't change upstream source code layout} for
details).|
\li|Craft and execute the \l{bdep-new(1)} command line necessary to achieve
the upstream layout.|
\li|Study the auto-generated \c{buildfile}s for things that don't fit and need
to change. But don't rush to start manually editing the result. First get an
overview of the required changes and then check if it's possible to achieve
these changes automatically using one of \l{bdep-new(1)} sub-options.
For example, if you see that the generated project assumes the wrong C++ file
extensions, these can be changed with \c{--lang|-l} sub-options.|
\li|Once you have squeezed as much as possible out of \l{bdep-new(1)}, it's
time for manual customizations. These would normally include:
\ul|
\li|Replace generated source code with upstream, normally as symlinks from the
\c{upstream/} \c{git} submodule.|
\li|Tweak source subdirectory \c{buildfile} that builds the main target
(library, executable).|
\li|Add tests and, if necessary, examples.|
\li|Tweak \c{manifest} (in particular the \c{version}, \c{summary}, and
\c{license} values).|
\li|Fill in \c{README.md}.|||
|
\h#dont-change-upstream|Don't change upstream source code layout|
It's a good idea to stay as close to the upstream's source code layout as
possible. For background and rationale, see \l{#core-package-struct Decide on
the package source code layout}.
\h#dont-forget-update-manifest|Don't forget to update \c{manifest} values|
After \l{#dont-from-scratch generating the project template with \c{bdep-new}},
don't forget to update at least the key values in the generated \c{manifest}:
\l{#dont-forget-update-manifest-version \c{version}},
\l{#dont-forget-update-manifest-license \c{license}}, and
\l{#dont-forget-update-manifest-summary \c{summary}}.
\h2#dont-forget-update-manifest-version|Don't forget to update \c{manifest} value \c{version}|
For \c{version}, use the upstream version directly if it is semver (or
semver-like, that is, has three version components). Otherwise, see
\l{https://github.com/build2/HOWTO/blob/master/entries/handle-projects-which-dont-use-semver.md
How do I handle projects that don't use semantic versioning?} and
\l{https://github.com/build2/HOWTO/blob/master/entries/handle-projects-which-dont-use-version.md
How do I handle projects that don't use versions at all?}
\h2#dont-forget-update-manifest-license|Don't forget to update \c{manifest} value \c{license}|
For \c{license}, use the \l{https://spdx.org/licenses/ SPDX license ID} if at
all possible. If multiple licenses are involved, use the SPDX License
expression. See the
\l{https://build2.org/bpkg/doc/build2-package-manager-manual.xhtml#manifest-package-license
\c{license} manifest value} documentation for details and the list of the
most commonly used SPDX license IDs.
\h2#dont-forget-update-manifest-summary|Don't forget to update \c{manifest} value \c{summary}|
For \c{summary} use a brief description of the functionality provided by the
package. Less than 70 characters is a good target to aim for. Don't capitalize
subsequent words unless proper nouns and omit the trailing dot. For example:
\
summary: Vim xxd hexdump utility
\
Omit weasel words such as \"modern\", \"simple\", \"fast\", \"small\", etc.,
since they don't convey anything specific. Omit \"header-only\" or
\"single-header\" for C/C++ libraries since at least in the context of
\c{build2} it does not imply any advantage.
If upstream does not offer a sensible summary, the following template is
recommended for libraries:
\
summary: <functionality> C library
summary: <functionality> C++ library
\
For example:
\
summary: Event notification C library
summary: Validating XML parsing and serialization C++ library
\
If the project consists of multiple packages it may be tempting to name each
package in terms of the overall project name, for example:
\
summary: libigl's core module
\
This doesn't give the user any clue about what functionality is provided
unless they find out what \c{libigl} is about. Better:
\
summary: Geometry processing C++ library, core module
\
If you follow the above pattern, then to produce a summary for external tests
or examples packages simply add \"tests\" or \"examples\" at the end,
for example:
\
summary: Event notification C library tests
summary: Geometry processing C++ library, core module examples
\
\h#dont-header-only|Don't make library header-only if it can be compiled|
Some libraries offer two alternative modes: header-only and compiled. Unless
there are good reasons not to, a \c{build2} build of such a library should use
the compiled mode.
\N|Some libraries use the \i{precompiled} term to describe the non-header-only
mode. We don't recommend using this term in the \c{build2} build since it has
a strong association with precompiled headers and can therefore be
confusing. Instead, use the \i{compiled} term.|
The main rationale here is that a library would not be offering a compiled
mode if there were no benefits (usually faster compile times of library
consumers) and there is no reason not to take advantage of it in the
\c{build2} build.
There are, however, reasons why a compiled mode cannot be used, the most
common of which are:
\ul|
\li|The compiled mode is not well maintained/tested by upstream and therefore
offers inferior user experience.|
\li|The compiled mode does not work on some platforms, usually Windows due to
the lack of symbol export support (but see \l{b##cc-auto-symexport Automatic
DLL Symbol Exporting}).|
\li|Uses of the compiled version of the library requires changes to the
library consumers, for example, inclusion of different headers.|
|
If a compiled mode cannot be always used, then it may be tempting to support
both modes potentially making the mode user-configurable. Unless there are
strong reasons to, you should resist this temptation and, if the compiled
mode is not universally usable, then use the header-only mode everywhere.
The main rationale here is that variability adds complexity which makes the
result more prone to bugs, more difficult to use, and harder to review and
maintain. If you really want to have the compiled mode, then the right
way to do it is to work with upstream to fix any issues that prevent its
use in \c{build2}.
There are, however, reasons why supporting both mode may be needed, the most
common of which are:
\ul|
\li|The library is widely used in both modes but switching from one mode to
the other requires changes to the library consumers (for example, inclusion of
different headers). In this case only supporting one mode would mean not
supporting a large number of library consumers.|
\li|The library consists of a large number of independent components and its
common for applications to only use a small subset of them. On the other hand,
compiling all of them in the compiled mode takes a substantial amount of time.
(Note that this can also be addressed by making the presence of optional
components user-configurable.)|
|
\h#dont-main-target-root-buildfile|Don't build your main targets in root \c{buldfile}|
It may be tempting to have your main targets (libraries, executables) in the
root \c{buildfile}, especially if it allows you to symlink entire directories
from \c{upstream/} (which is not possible if you have to have a \c{buildfile}
inside). However, this is a bad idea except for the simplest projects.
Firstly, this quickly gets messy since you have to combine managing
\c{README}s, \c{LICENSE}s, and subdirectories with you main target builds.
But, more importantly, this means that when you main target is imported (and
thus the \c{buildfile} that defines this target must be loaded), your entire
project will be loaded, including any \c{tests/} and \c{examples/} subproject,
which is wasteful.
If you want to continue symlinking entire directories from \c{upstream/} but
without moving everything to the root \c{buildfile}, the recommended approach
is to simply add another subdirectory level. Let's look at a few concrete
example to illustrate the technique (see \l{#core-package-struct Decide on the
package source code layout} for background on the terminology used).
Here is the directory structure of a package which uses a combined layout (no
header/source split) and where everything is in the root \c{buildfile}:
\
libigl-core/
├── igl/ -> upstream/igl/
├── tests/
└── buildfile # Defines lib{igl-core}.
\
And here is the alternative structure where we have added the extra
\c{libigl-core} subdirectory with its own \c{buildfile}:
\
libigl-core/
├── libigl-core/
│ ├── igl/ -> ../upstream/igl/
│ └── buildfile # Defines lib{igl-core}.
├── tests/
└── buildfile
\
Below is the \c{bdep-new} invocation that can be used to automatically
create this alternative structure (see \l{#core-package-craft-cmd Craft
\c{bdep\ new} command line to create package} for background and
\l{bdep-new(1)} for details):
\
$ bdep new \
--type lib,prefix=libigl-core,subdir=igl,buildfile-in-prefix \
libigl-core
\
Let's also look at an example of a split layout, which may require a slightly
different \c{bdep-new} sub-options to achieve the same result. Here is the
layout which matched upstream exactly:
\
$ bdep new --type lib,split,subdir=foo,no-subdir-source libfoo
$ tree libfoo
libfoo/
├── include/
│ └── foo/
│ ├── buildfile
│ └── ...
└── src/
├── buildfile
└── ...
\
However, with this layout we will not be able to symlink the entire
\c{include/foo/} and \c{src/} subdirectories because there are \c{buildfile}s
inside (and which may tempt you to just move everything to the root
\c{buidfile}). To fix this we can move the \c{buildfile}s out of source
subdirectory \c{foo/} and into prefixes (\c{include/} and \c{src/}) using the
\c{buildfile-in-prefix} sub-option. And since \c{src/} doesn't have a source
subdirectory, we have to invent one:
\
$ bdep new --type lib,split,subdir=foo,buildfile-in-prefix libfoo
$ tree libfoo
libfoo/
├── include/
│ ├── foo/ -> ../upstream/include/foo/
│ └── buildfile
└── src/
├── foo/ -> ../upstream/src/
└── buildfile
\
\h1#howto|Packaging HOWTO|
@@ howto make smoke test (and fix ref)
\h#howto-bad-inclusion-practice|How do I deal with bad header inclusion practice|
This sections explains how to deal with libraries that include their public,
generically-named headers without the library name as directory prefix. Such
libraries cannot coexist, neither in the same build nor when installed. For
background and details, see \l{intro#proj-struct Canonical Project Structure}.
@@ TODO
\h#howto-extra-header-install-subdir|How do I handle extra header installation subdirectory|
This sections explains how to handle an additional header installation
subdirectory.
@@ TODO
\h1#faq|Packaging FAQ|
\h#faq-publish-stage|Where to publish if package requires staged toolchain?|
If your package requires the \l{https://build2.org/community.xhtml#stage staged
toolchain}, for example, because it needs a feature or bugfix that is not yet
available in the released toolchain, then you won't be able to publish it to
\c{cppget.org}. Specifically, if your package has the accurate \c{build2}
version constraint and you attempt to publish it, you will get an error like
this:
\
error: package archive is not valid
info: unable to satisfy constraint (build2 >= 0.17.0-) for package foo
info: available build2 version is 0.16.0
\
There are three alternative ways to proceed in this situation:
\ol|
\li|Wait until the next release and then publish the package to
\c{cppget.org}.|
\li|If the requirement for the staged toolchain is \"minor\", that is, it
doesn't affect the common functionality of the package or only affects a small
subset of platforms/compilers, then you can lower the toolchain version
requirement and publish the package to \c{cppget.org}. For example, if
you require the staged toolchain because of a bugfix that only affects
one platform, it doesn't make sense to delay publishing the package
since it is perfectly usable on all the platforms in the meantime.|
\li|Publish it to \l{https://queue.stage.build2.org queue.stage.build2.org},
the staging package repository. This repository contain new packages that
require the staged toolchain to work and which will be automatically
moved to \c{cppget.org} once the staged version is released. The other
advantage of publishing to this repository (besides not having to remember
to manually publish the package once the staged version is released) is
that your package becomes available from an archive repository (which is
substantially faster than a \c{git} repository).
To publish to this repository, use the following \c{bdep-publish} command
line:
\
$ bdep publish --repository=https://stage.build2.org ...
\
||
"
|