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
|
// file : doc/intro1.cli
// license : MIT; see accompanying LICENSE file
"\name=build2-toolchain-intro"
"\subject=toolchain"
"\title=Toolchain Introduction"
// TODO
//
// @@ refs to further docs
//
// STYLE
//
// @@ section boundary page breaks (<hr class="page-break"/>)
// @@ when printed, code background is gone, but spaces still there
//
// PDF
//
// @@ tree output is garbled
// @@ Install list margins missing
// @@ Could we use a nicer font, seeing that we embed them?
//
// NOTES
//
// - Maximum <pre> line is 70 characters.
//
"
\h#tldr|TL;DR|
\
$ bpkg create -d hello cc
created new configuration in hello/
$ cd hello/
$ bpkg add https://build2.org/pkg/1/hello/stable
added repository build2.org/hello/stable
$ bpkg fetch
fetching build2.org/hello/stable
2 package(s) in 1 repository(s)
$ bpkg build hello
build libhello/1.0.0 (required by hello)
build hello/1.0.0
continue? [Y/n] y
libhello-1.0.0.tar.gz 100% of 2428 B 983 kBps 00m01s
fetched libhello/1.0.0
unpacked libhello/1.0.0
hello-1.0.0.tar.gz 100% of 1057 B 6882 kBps 00m01s
fetched hello/1.0.0
unpacked hello/1.0.0
configured libhello/1.0.0
configured hello/1.0.0
c++ hello-1.0.0/cxx{hello}
c++ libhello-1.0.0/hello/cxx{hello}
ld libhello-1.0.0/hello/libs{hello}
ld hello-1.0.0/exe{hello}
updated hello/1.0.0
\
"
"
\h#warning|Warning|
The \c{build2} toolchain \c{0.X.Y} series are alpha releases. Interfaces
\i{will} most likely change in backwards-incompatible ways. But if you want
to start playing with it, welcome and join the \l{https://lists.build2.org
mailing list}!
Our approach to developing \c{build2} is to first get the hard parts right
before focusing on completeness. So while we might still have no support for
custom build rules, we do handle auto-generated source code (and, in
particular, headers) properly. In other words, we go depth rather than
breadth-first. As a result, there are some limitations and missing pieces,
especially in the build system. The most notable ones are:
\ul|
\li|Limited documentation.|
\li|No support for custom build system rules/modules.|
|
"
"
\h#intro|Introduction|
The \c{build2} toolchain is a set of tools designed for building and packaging
C and C++ code (though, if it can handle C++, it can handle anything,
right?). The toolchain currently includes the \i{build system} (\c{build2}),
the \i{package manager} (\c{bpkg}), and the \i{repository web interface}
(\c{brep}). More tools, such as the \i{build robot} (\c{bbot}), are in the
works. Then there is \l{https://cppget.org/ cppget.org} (running \c{brep})
which we hope will become \i{the C++ package repository}.
The goal of this document is to give you a basic idea of what the \c{build2}
toolchain can do so that you can decide if you are interested and want to learn
more. Further documentation is referenced at the end of this introduction.
The \c{build2} toolchain is self-hosted and self-packaged (and, yes, it is on
\l{https://cppget.org/ cppget.org}). It could have served as its own example,
however, before the toolchain can build itself, we have to bootstrap it (that
chicken and egg problem again). And this step wouldn't serve our goal of
quickly learning what \c{build2} is about. So, instead, we will start with a
customary \i{\"Hello, World!\"} example which you won't yet be able to try
yourself (but don't worry, complete terminal output will be shown). If at the
end you find \c{build2} appealing, you can jump straight to
\l{build2-toolchain-install.xhtml The \c{build2} Toolchain Installation and
Upgrade} (and, yes, there you get to run that coveted \c{bpkg build bpkg}).
Once the \c{build2} installation is complete, you can come back to the
\i{\"Hello, World!\"} example and try all of the steps for yourself.
This introduction explores the \i{consumer} side of \i{\"Hello, World!\"}.
That is, we assume that someone was kind enough to create and package the
\c{libhello} library as well as the \c{hello} program and we will learn how to
obtain and build them as well as keep up with their updates. At the end we
will also see how to write our own, \c{hello2}, program that depends on
\c{libhello}. And so, without further ado, let's begin.
Actually, one more thing: if you have a recent enough compiler and would like
to try the new C++ Modules support, then you can instead use the modularized
variants of these packages: simply replace \c{hello} with \c{mhello} and
\c{libhello} with \c{libmhello} in the commands below.
The first step in using \c{bpkg} is to create a \i{configuration}. A
configuration is a directory where packages that require similar compile
settings will be built. You can create as many configurations as you want: for
different C++ compilers, targets (\c{build2} is big on cross-compiling),
debug/release, 32/64-bit, or even for different days of the week, if you are
so inclined. Say we are in the mood for a GCC 5 release build today:
\
$ mkdir hello-gcc5-release
$ cd hello-gcc5-release
$ bpkg create cxx config.cxx=g++-5 config.cxx.coptions=-O3
created new configuration in /tmp/hello-gcc5-release/
\
Or perhaps you are on Windows and prefer Visual Studio (running from the
Visual Studio Tools Command Prompt):
\
> mkdir hello-vc14-release
> cd hello-vc14-release
> bpkg create cxx config.cxx=cl config.cxx.coptions=/O2
created new configuration in C:\projects\hello-vc14-release\
\
One of the primary goals of the \c{build2} toolchain is to provide a uniform
build interface across all the platforms and compilers. While the following
examples use the \c{hello-gcc5-release} configuration and assume a UNIX-like
operation system, everything will work if you use \c{hello-vc14-release} (or
\c{hello-mingw-release}) on Windows. Just use appropriate paths, compilers,
and options.
Let's discuss that last command line: \l{bpkg-cfg-create(1) \c{bpkg create}}
is the command for creating a new configuration. As a side note, if you ever
want to get help for any \c{bpkg} command, run \c{bpkg help \i{<command>}}. To
see the list of commands, run just \l{bpkg-help(1) \c{bpkg help}} (or see
\l{bpkg(1)}). While we are at it, if you ever want to see what \c{bpkg} is
running underneath, there is the \c{-v} (essential commands) and \c{-V} (all
commands) options. And if you really want to get under the hood, use
\l{bpkg-common-options(1) \c{--verbose <level>}}.
After the command we have \c{cxx} which is the name of the \c{build2} build
system module. As you might have guessed, \c{cxx} provides support for the C++
compilation. By specifying this module when creating the configuration we
configure it (yes, with those \c{config.cxx.*} variables that follow) for the
entire configuration. That is, every package that we will build in this
configuration and that uses the \c{cxx} module will by default inherit these
settings.
The rest of the command line are the configuration variables for the \c{cxx}
module with \c{coptions} standing for \i{compile options} (there are also
\c{poptions} for \i{preprocess options}, \c{loptions} for \i{link options}, and
\c{libs} for extra libraries to link).
There is also the \c{c} module for the C compilation. So if we were planning
to build both C and C++ projects, then we could have run:
\
$ bpkg create c cxx ...
\
The problem, of course, is that you may not know what mix of languages those
projects (or their dependencies) might use. For example, the use of C might be
an implementation detail of a C++ library. To solve this, \c{build2} provides
another module called \c{cc} which stands for \i{C-common}. So, in this
context, instead of using the \c{c} and \c{cxx} modules directly, it's a good
idea to get into the habit of using \c{cc}:
\
$ bpkg create cc config.cxx=g++-5 config.cc.coptions=-O3
\
Notice two things about this command line: we don't need to specify the C
compiler with \c{config.c} \- \c{build2} is smart enough to figure it out
from \c{config.cxx} (or vice versa). We also used \c{config.cc.coptions}
instead of \c{config.cxx.coptions} so that the options apply to all the
C-common languages (we can still use \c{config.{c,cxx\}.*} for the
language-specific options).
Ok, configuration in hand, where can we get some packages? \c{bpkg} packages
come from \i{repositories}. A repository can be a local filesystem directory
or a remote URL. Our example packages come from their own remote \i{\"Hello,
World!\"} repository: \c{\l{https://build2.org/pkg/1/hello/stable/}} (go ahead,
browse it, I will wait).
Instead of scouring repository manifests by hand (I know you couldn't resist),
we can ask \c{bpkg} to interrogate a repository location for us:
\
$ bpkg rep-info https://build2.org/pkg/1/hello/stable
warning: authenticity of the certificate for repository build2.org/hello/stable cannot be established
certificate is for build2.org, \"Code Synthesis\" <admin@build2.org>
certificate SHA256 fingerprint:
FF:DF:7D:38:67:4E:C3:82:[...]:30:56:B9:77:B9:F2:01:94
trust this certificate? [y/n]
\
The \c{bpkg} repositories are normally signed to prevent tampering with
packages. If the repository certificate is seen (in this configuration) for
the first time, \c{bpkg} will ask you to authenticate it. A good way to
authenticate a certificate is to compare the displayed fingerprint to the one
you have received earlier, for example, in an email announcement. The
repository's about page also lists the fingerprint (see the
\l{https://build2.org/pkg/hello/?about about page} for our repository). For
more details on repository signing see the \l{bpkg-repository-signing(1)} help
topic.
If we answer \i{yes}, we will see the basic repository information (its
\i{canonical name}, location, certificate subject and fingerprint) followed
by the list of available packages:
\
build2.org/hello/stable https://build2.org/pkg/1/hello/stable
CN=build2.org/O=Code Synthesis/admin@build2.org
FF:DF:7D:38:67:4E:C3:82:[...]:30:56:B9:77:B9:F2:01:94
hello/1.0.0
libhello/1.0.0
\
We can also use the repository's web interface (implemented by \c{brep}). Our
repository has one, check it out: \c{\l{https://build2.org/pkg/hello/}}.
Ok, back to the command line. If we want to use a repository as a source of
packages in our configuration, we have to first add it:
\
$ bpkg add https://build2.org/pkg/1/hello/stable
added repository build2.org/hello/stable
\
If we want to add several repositories, we just execute the \l{bpkg-rep-add(1)
\c{bpkg add}} command for each of them. Once this is done, we fetch the list of
available packages for all the added repositories:
\
$ bpkg fetch
fetching build2.org/hello/stable
2 package(s) in 1 repository(s)
\
Note that you would normally re-run the \l{bpkg-rep-fetch(1) \c{bpkg fetch}}
command after you've added another repository or to refresh the list of
available packages.
Now that \c{bpkg} knows where to get the packages, we can finally get down to
business:
\
$ bpkg build hello
build libhello/1.0.0 (required by hello)
build hello/1.0.0
continue? [Y/n]
\
Let's see what's going on here. We ran \l{bpkg-pkg-build(1) \c{bpkg build}} to
build the \c{hello} program which happens to depend on the \c{libhello}
library. So \c{bpkg} presents us with a \i{plan of action}, that is, the steps
it will have to perform in order to build us \c{hello} and then asks us to
confirm if that's what we want to do (you can add \c{--yes|-y} to skip the
confirmation). In the real-world usage the plan will be more complex, with
upgrades/downgrades, reconfigurations, etc.
Let's answer \i{yes} and see what happens:
\
libhello-1.0.0.tar.gz 100% of 2428 B 1364 kBps 00m01s
fetched libhello/1.0.0
unpacked libhello/1.0.0
hello-1.0.0.tar.gz 100% of 1057 B 20 MBps 00m01s
fetched hello/1.0.0
unpacked hello/1.0.0
configured libhello/1.0.0
configured hello/1.0.0
c++ hello-1.0.0/cxx{hello}
c++ libhello-1.0.0/hello/cxx{hello}
ld libhello-1.0.0/hello/libs{hello}
ld hello-1.0.0/exe{hello}
updated hello/1.0.0
\
While the output is mostly self-explanatory, in short, \c{bpkg} downloaded,
unpacked, and configured both packages and then proceeded to building the
\c{hello} executable which happens to require building the \c{libhello}
library. Note that the download progress may look differently on your machine
depending on which \i{fetch tool} (\c{wget}, \c{curl}, or \c{fetch}) is
used. If you ever considered giving that \c{-v} option a try, now would be a
good time. But let's first drop (\l{bpkg-pkg-drop(1) \c{bpkg drop}}) the
\c{hello} package so that we get the same build from scratch:
\
$ bpkg drop hello
following prerequisite packages were automatically built and will no longer be necessary:
libhello
drop prerequisite packages? [Y/n] y
drop hello
drop libhello
continue? [Y/n] y
disfigured hello
disfigured libhello
purged hello
purged libhello
\
Ok, ready for some \c{-v} details? Feel free to skip the following listing
if you are not interested.
\
$ bpkg build -v -y hello
fetching libhello-1.0.0.tar.gz from build2.org/hello/stable
curl ... https://build2.org/pkg/1/hello/stable/libhello-1.0.0.tar.gz
% Total % Received Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2428 100 2428 1121 0 0:00:01 0:00:01 --:--:-- 1122
fetched libhello/1.0.0
tar -xf libhello-1.0.0.tar.gz
unpacked libhello/1.0.0
fetching hello-1.0.0.tar.gz from build2.org/hello/stable
curl ... https://build2.org/pkg/1/hello/stable/hello-1.0.0.tar.gz
% Total % Received Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1057 100 1057 773 0 0:00:01 0:00:01 --:--:-- 772
fetched hello/1.0.0
tar -xf hello-1.0.0.tar.gz
unpacked hello/1.0.0
b -v configure(./libhello-1.0.0/)
cat >libhello-1.0.0/build/config.build
configured libhello/1.0.0
b -v configure(./hello-1.0.0/)
cat >hello-1.0.0/build/config.build
configured hello/1.0.0
hold package hello
b -v update(./hello-1.0.0/)
g++-5 -I libhello-1.0.0 -O3 -std=c++11 -o hello-1.0.0/hello.o -c hello-1.0.0/hello.cxx
g++-5 -I libhello-1.0.0 -O3 -std=c++11 -fPIC -o libhello-1.0.0/hello/hello.so.o -c libhello-1.0.0/hello/hello.cxx
g++-5 -O3 -std=c++11 -shared -o libhello-1.0.0/hello/libhello-1.0.so libhello-1.0.0/hello/hello.so.o
g++-5 -O3 -std=c++11 -o hello-1.0.0/hello hello-1.0.0/hello.o libhello-1.0.0/hello/libhello-1.0.so
updated hello/1.0.0
\
Another handy command is \l{bpkg-pkg-status(1) \c{bpkg status}}. It can be
used to examine the state of a package in the configuration. Here are a few
examples (if you absolutely must know what \c{hold_package} and \c{sys:?}
mean, check \l{bpkg-pkg-status(1)}):
\
$ bpkg status libhello
configured 1.0.0; available sys:?
$ bpkg status hello
configured 1.0.0 hold_package; available sys:?
$ bpkg drop -y hello
disfigured hello
disfigured libhello
purged hello
purged libhello
$ bpkg status hello
available 1.0.0 sys:?
$ bpkg status libfoobar
unknown
\
Let's say we got wind of a new development: the \c{libhello} author released a
new version of the library. It is such an advance in the art of \i{\"Hello,
World!\"}, it's only currently available from \c{testing}. Of course, we must
check it out.
Now, what exactly is \c{testing}? You must have noticed that the repository
location that we've been using so far ended with \c{/stable}. Quite often it is
useful to split our repository into sub-repositories or \i{sections}. For
example, to reflect the maturity of packages (say, \c{stable} and \c{testing},
as in our case) or to divide them into sub-categories (\c{misc} and \c{math})
or even some combination (\c{math/testing}). Note, however, that to \c{bpkg}
these sub-repositories or \i{sections} are just normal repositories and there
is nothing special about them.
We are impatient to try the new version so we will skip interrogating the
repository with \c{rep-info} and just add it to our configuration. After all,
we can always check with \c{status} if any upgrades are available for packages
we are interested in. Here we assume the configuration has \c{hello} built (run
\c{bpkg build -y hello} to get to that state).
\
$ bpkg add https://build2.org/pkg/1/hello/testing
added repository build2.org/hello/testing
$ bpkg fetch
fetching build2.org/hello/stable
fetching build2.org/hello/testing
5 package(s) in 2 repository(s)
\
Notice that this time we don't see any authentication-related messages or
prompts since \c{bpkg} remembered (in this configuration) that we trust the
certificate (\c{testing} naturally uses the same one as \c{stable}).
Let's see what's new:
\
$ bpkg status libhello
configured 1.0.0; available 1.1.0 sys:?
\
Ok, \c{libhello/1.1.0} is now available. How do we upgrade? We can try to
build \c{hello} again:
\
$ bpkg build -y hello
info: dir{hello-1.0.0/} is up to date
updated hello/1.0.0
\
Why did nothing happen? Because \c{bpkg} will only upgrade (or downgrade)
to a new version if we explicitly ask it to. As things stand, all dependencies
for \c{hello} are satisfied and \c{bpkg} is happy to twiddle its thumbs. Let's
tell \c{bpkg} to build us \c{libhello} instead:
\
$ bpkg build libhello
build libformat/1.0.0 (required by libhello)
build libprint/1.0.0 (required by libhello)
upgrade libhello/1.1.0
reconfigure hello (dependent of libhello)
continue? [Y/n]
\
Ok, now we are getting somewhere. It looks like the new version of \c{libhello}
went really enterprise-grade (or is it called web-scale these days?). There are
now two new dependencies (\c{libformat} and \c{libprint}) that we will have to
build in order to upgrade. Maybe we should answer \i{no} here?
Notice also that \c{reconfigure hello} line. If you think about this, it makes
sense: we are getting a new version of \c{libhello} and \c{hello} depends on it
so it might need a chance to make some adjustments to its configuration.
Let's answer \i{yes} if only to see what happens:
\
update dependent packages? [Y/n]
\
Another question. This one has to do with that \c{reconfigure hello} line we
just talked about. If you were wondering why we were only offered to
reconfigure and not actually update the dependent package, you should know
that \c{bpkg} is a very lazy package manager, it only does what it must do,
not what might be nice to do. It must reconfigure but it doesn't really have
to update. And this could be a good thing if, for example, you have a hundred
dependents in your configuration but right now you only want to build just
those specific packages. However, quite often, you do want to keep all the
packages in your configuration up to date and \c{bpkg} graciously offers to
take care of this task. Ok, let's answer \i{yes} again:
\
...
update dependent packages? [Y/n] y
disfigured hello/1.0.0
disfigured libhello/1.0.0
libformat-1.0.0.tar.gz 100% of 1064 B 11 MBps 00m01s
fetched libformat/1.0.0
unpacked libformat/1.0.0
libprint-1.0.0.tar.gz 100% of 1040 B 9 MBps 00m01s
fetched libprint/1.0.0
unpacked libprint/1.0.0
libhello-1.1.0.tar.gz 100% of 1564 B 4672 kBps 00m01s
fetched libhello/1.1.0
unpacked libhello/1.1.0
configured libformat/1.0.0
configured libprint/1.0.0
configured libhello/1.1.0
configured hello/1.0.0
c++ libhello-1.1.0/hello/cxx{hello}
c++ libformat-1.0.0/format/cxx{format}
ld libformat-1.0.0/format/liba{format}
c++ libprint-1.0.0/print/cxx{print}
ld libprint-1.0.0/print/liba{print}
ld libhello-1.1.0/hello/liba{hello}
c++ libhello-1.1.0/hello/cxx{hello}
c++ libformat-1.0.0/format/cxx{format}
ld libformat-1.0.0/format/libs{format}
c++ libprint-1.0.0/print/cxx{print}
ld libprint-1.0.0/print/libs{print}
ld libhello-1.1.0/hello/libs{hello}
c++ libhello-1.1.0/tests/test/cxx{driver}
ld libhello-1.1.0/tests/test/exe{driver}
c++ hello-1.0.0/cxx{hello}
ld hello-1.0.0/exe{hello}
updated libhello/1.1.0
updated hello/1.0.0
\
A lot of output but nothing really new. If you were to answer \i{no} to the
\"update dependent packages?\" question above, it is easy to make sure a
package is up-to-date at a later time with the \l{bpkg-pkg-update(1) \c{bpkg
update}} command (there is also \l{bpkg-pkg-clean(1) \c{bpkg clean}}), for
example:
\
$ bpkg clean hello
rm hello-1.0.0/exe{hello}
rm hello-1.0.0/obje{hello}
cleaned hello/1.0.0
$ bpkg update hello
c++ hello-1.0.0/cxx{hello.cxx}
ld hello-1.0.0/exe{hello}
updated hello/1.0.0
\
Let's say we really don't like the direction \c{libhello} is going and would
rather stick to version \c{1.0.0}. Just like upgrades, downgrades are explicit
plus, in this case, we need to specify the version (you can also specify
the desired version for upgrades).
\
$ bpkg build libhello/1.0.0
downgrade libhello/1.0.0
reconfigure hello (dependent of libhello)
continue? [Y/n] y
update dependent packages? [Y/n] y
disfigured hello/1.0.0
disfigured libhello/1.1.0
libhello-1.0.0.tar.gz 100% of 2428 B 983 kBps 00m01s
fetched libhello/1.0.0
unpacked libhello/1.0.0
configured libhello/1.0.0
configured hello/1.0.0
following prerequisite packages were automatically built and will no longer be necessary:
libprint
libformat
drop prerequisite packages? [Y/n] y
disfigured libprint
disfigured libformat
purged libprint
purged libformat
c++ libhello-1.0.0/hello/cxx{hello}
ld libhello-1.0.0/hello/liba{hello}
c++ libhello-1.0.0/hello/cxx{hello}
ld libhello-1.0.0/hello/libs{hello}
c++ libhello-1.0.0/tests/test/cxx{driver}
ld libhello-1.0.0/tests/test/exe{driver}
c++ hello-1.0.0/cxx{hello}
ld hello-1.0.0/exe{hello}
updated libhello/1.0.0
updated hello/1.0.0
\
Notice how \c{bpkg} helpfully offered to get rid of \c{libprint} and
\c{libformat} which we won't be needing anymore. Note also that while we
can use \c{--yes|y} as an answer to all the numerous prompts, there are
also more granular options. For example, this is how we can instruct
\c{bpkg} to drop prerequisites (\c{--drop-prerequisite|-D}) but leave
dependents just reconfigured (\c{--leave-dependent|-L}):
\
$ bpkg build -D -L libhello/1.0.0
\
Ok, so all this might look nice and all, but we haven't actually seen anything
of what we've presumably built; it can all be a charade, for all we know. Can
we see some libraries and run the \c{hello} program?
There are several ways we can do this. If the package provides tests (as all
good packages should), we can run them with the \l{bpkg-pkg-test(1) \c{bpkg
test}} command:
\
$ bpkg test libhello hello
test libhello-1.0.0/tests/test/exe{driver}
test hello-1.0.0/exe{hello}
tested libhello/1.0.0
tested hello/1.0.0
\
But that doesn't quite count for seeing libraries and running programs. Well,
if you insist, let's see what's inside \c{hello-gcc5-release/}. The \c{bpkg}
configuration (this \c{hello-gcc5-release/} directory) is, in the \c{build2}
build system terms, an \i{amalgamation} \- a project that contains
\i{subprojects}. Not surprisingly, the subprojects in this amalgamation are the
packages that we've built:
\
$ ls -1F
build/
hello-1.0.0/
libhello-1.0.0/
buildfile
hello-1.0.0.tar.gz
libhello-1.0.0.tar.gz
\
And if we look inside \c{hello-1.0.0/} we will see what looks like the
\c{hello} program:
\
$ ls -1F hello-1.0.0/
build/
buildfile
hello*
hello.d
hello.cxx
hello.o
hello.o.d
manifest
test.out
version
$ hello-1.0.0/hello
usage: hello <name>...
$ hello-1.0.0/hello World
Hello, World!
\
The important point here is this: the \c{bpkg} configuration is not some black
box that you should never look inside of. On the contrary, it is a normal and
predictable concept of the build system and as long as you understand what you
are doing, feel free to muck around.
Another way to get hold of a package's goodies is to install it with
\l{bpkg-pkg-install(1) \c{bpkg install}}. Let's try that:
\
$ bpkg install \
config.install.root=/opt/hello \
config.install.sudo=sudo \
hello
install /opt/hello/
install /opt/hello/include/
install /opt/hello/include/hello/
install libhello-1.0.0/hello/hxx{hello}
install libhello-1.0.0/hello/hxx{export}
install /opt/hello/lib/
install libhello-1.0.0/hello/libs{hello}
install /opt/hello/bin/
install hello-1.0.0/exe{hello}
install /opt/hello/share/
install /opt/hello/share/doc/
install /opt/hello/share/doc/hello/
install hello-1.0.0/doc{version}
installed hello/1.0.0
\
The \c{config.install.sudo} value is the optional \i{sudo}-like program
that should be used to run the \c{install} program. For those feeling queasy
running \c{sudo make install}, here is your answer. If you are wondering
whether you could have specified those \c{config.install.*} values during the
configuration creation, the answer is yes, indeed!
Let's see what we've got:
\
$ tree -F /opt/hello/
/opt/hello/
├── bin/
│ └── hello*
├── include/
│ └── libhello/
│ ├── export
│ └── hello
├── lib/
│ ├── libhello-1.0.so*
│ └── libhello.so -> libhello-1.0.so*
└── share/
└── doc/
└── hello/
└── version
\
We can also try to run the installed program:
\
$ /opt/hello/bin/hello World
/opt/hello/bin/hello: error while loading shared libraries: libhello-1.0.so: cannot open shared object file: No such file or directory
\
Not what we hoped to see. Note to the Windows users: this will actually work
since \c{hello-1.0.dll} will be installed into \c{bin\\}, next to the
executable; for once things are working better on Windows.
The problem is with our installation location: the runtime linker won't look
for \c{libhello-1.0.so} in \c{/opt/hello/lib} unless we somehow tell it to
(for example, using \c{LD_LIBRARY_PATH} or equivalent). There are several
ways we can resolve this. We could give up on shared libraries and link our
prerequisite libraries statically (\c{config.bin.exe.lib=static}). Or we could
use the \i{rpath} mechanism:
\
$ bpkg install \
config.install.root=/opt/hello \
config.install.sudo=sudo \
config.bin.rpath=/opt/hello/lib \
hello
ld hello-1.0.0/exe{hello}
install /opt/hello/
install /opt/hello/include/
install /opt/hello/include/hello/
install libhello-1.0.0/hello/hxx{hello}
install libhello-1.0.0/hello/hxx{export}
install /opt/hello/lib/
install libhello-1.0.0/hello/libs{hello}
install /opt/hello/bin/
install hello-1.0.0/exe{hello}
install /opt/hello/share/
install /opt/hello/share/doc/
install /opt/hello/share/doc/hello/
install hello-1.0.0/doc{version}
installed hello/1.0.0
$ /opt/hello/bin/hello World
Hello, World!
\
Notice that \c{ld} line above \- this is where our executable is re-linked
with the \c{-rpath} option.
We can also uninstall what we have installed with \l{bpkg-pkg-uninstall(1)
\c{bpkg uninstall}}:
\
$ bpkg uninstall \
config.install.root=/opt/hello \
config.install.sudo=sudo \
hello
uninstall hello-1.0.0/doc{version}
uninstall /opt/hello/share/doc/hello/
uninstall /opt/hello/share/doc/
uninstall /opt/hello/share/
uninstall hello-1.0.0/exe{hello}
uninstall /opt/hello/bin/
uninstall libhello-1.0.0/hello/libs{hello}
uninstall /opt/hello/lib/
uninstall libhello-1.0.0/hello/hxx{export}
uninstall libhello-1.0.0/hello/hxx{hello}
uninstall /opt/hello/include/hello/
uninstall /opt/hello/include/
uninstall /opt/hello/
uninstalled hello/1.0.0
$ ls /opt/hello
ls: cannot access /opt/hello: No such file or directory
\
What if we wanted to use \c{libhello} in our own project? While installing it
is always an option, this may not be convenient when we develop our code. We
may have multiple builds per project, for example, with GCC and Clang to catch
all the warnings. We may also want to make sure our application works well
with several versions of \c{libhello} (and maybe even with that heinous
\c{1.1.X}). While we can install different configurations into different
directories, it's hard to deny things are getting a bit hairy: multiple
configurations, multiple installations... I guess we will have to get our
hands into that cookie jar, I mean, configuration, again.
In fact, let's just start writing our own version of the \c{hello} program
and see how it goes:
\
$ mkdir hello2
$ cd hello2
$ cat >hello.cpp
#include <libhello/hello>
int main ()
{
hello::say (\"World\");
}
\
What build system shall we use? I can't believe you are even asking this
question...
\
$ mkdir build
$ cat >build/bootstrap.build
project = hello2 # project name
using config # config module (those config.*)
$ cat >build/root.build
cxx.std = 11 # C++ standard
using cxx # C++ module
cxx{*}: extension = cpp # C++ source file extension
$ cat >buildfile
import libs = libhello%lib{hello}
exe{hello}: cxx{hello} $libs
\
While some of this might not be crystal clear (like why do we have
\c{bootstrap.build} \i{and} \c{root.build}), I am sure you at least have a
fuzzy idea of what's going on. And that's enough for what we are after here.
Completely explaining what's going on here and, more importantly, \i{why} it's
going this way is for another time and place (the \c{build2} build system
manual).
To recap, these are the contents of our project so far:
\
$ tree -F
.
├── build/
│ ├── bootstrap.build
│ └── root.build
├── buildfile
└── hello.cpp
\
Let's try to build it and see what happens \- maybe it will magically work
(\l{b(1)} is the \c{build2} build system driver).
\
$ b config.cxx=g++-5
error: unable to import target libhello%lib{hello}
info: use config.import.libhello command line variable to specify its project out_root
info: while applying rule cxx.link to update exe{hello}
info: while applying rule alias to update dir{./}
\
No magic, unfortunately (or fortunately). But we got a hint: looks like we
need to tell \c{build2} where \c{libhello} is using
\c{config.import.libhello}. Without fretting too much about what exactly
\c{out_root} means, let's point \c{build2} to our \c{bpkg} configuration and
see what happens. After all, that's where, more or less, our \i{out}-put for
\c{libhello} is.
\
$ b config.cxx=g++-5 \
config.import.libhello=/tmp/hello-gcc5-release
c++ cxx{hello}
ld exe{hello}
\
Almost magic. Let's see what we've got:
\
$ tree -F
.
├── build/
│ ├── bootstrap.build
│ └── root.build
├── buildfile
├── hello*
├── hello.d
├── hello.cpp
├── hello.o
└── hello.o.d
$ ./hello
Hello, World!
\
Let's change something in our source code and try to update:
\
$ touch hello.cpp
$ b
error: unable to import target libhello%lib{hello}
info: use config.import.libhello command line variable to specify its project out_root
info: while applying rule cxx.link to update exe{hello}
info: while applying rule alias to update dir{./}
\
Looks like we have to keep repeating those \c{config.*} values and who wants
that? To get rid of this annoyance we have to make our configuration
\i{permanent}. Also, seeing that we plan to have several of them (GCC/Clang,
different version of \c{libhello}), it makes sense to create them \i{out of
source tree}. Let's get to it:
\
$ cd ..
$ mkdir hello2-gcc5-release
$ ls -1F
hello2/
hello2-gcc5-release/
$ b config.cxx=g++-5 \
config.cc.coptions=-O3 \
config.import.libhello=/tmp/hello-gcc5-release \
'configure(hello2/@hello2-gcc5-release/)'
mkdir -p hello2-gcc5-release/build/
save hello2-gcc5-release/build/config.build
\
Translated, \c{configure(hello2/@hello2-gcc5-release/)} means \i{\"configure
the \c{hello2/} source directory in the \c{hello2-gcc5-release/} output
directory\"}. In \c{build2} this \i{source directory} is called \c{src_root}
and \i{output directory} \- \c{out_root}. Hm, we've already heard \c{out_root}
mentioned somewhere before...
Once the configuration is saved, we can develop our project without any
annoyance:
\
$ b hello2-gcc5-release/
c++ hello2/cxx{hello}
ld hello2-gcc5-release/exe{hello}
$ cd hello2-gcc5-release/
$ b
info: dir{./} is up to date
$ b clean
rm exe{hello}
rm obje{hello}
$ b -v
g++-5 -I/tmp/hello-gcc5-release/libhello-1.0.0 -O3 -std=c++11 -o hello.o -c ../hello2/hello.cpp
g++-5 -O3 -std=c++11 -o hello hello.o /tmp/hello-gcc5-release/libhello-1.0.0/hello/libhello-1.0.so
\
Some of you might have noticed that \c{hello2-gcc5-release/} and
\c{/tmp/hello-gcc5-release/} look awfully similar and are now wondering if we
could instead build \c{hello2} \i{inside} \c{/tmp/hello-gcc5-release/}? I am
glad you've asked. In fact, we can just do:
\
$ cd ..
$ ls -1F
hello2/
hello2-gcc5-release/
$ b 'configure(hello2/@/tmp/hello-gcc5-release/hello2/)'
mkdir -p /tmp/hello-gcc5-release/hello2/build/
save /tmp/hello-gcc5-release/hello2/build/config.build
$ b /tmp/hello-gcc5-release/hello2/
c++ hello2/cxx{hello}@/tmp/hello-gcc5-release/hello2/
ld /tmp/hello-gcc5-release/hello2/exe{hello}
\
Now that might seem like magic, but it's actually pretty logical. Why don't we
need to specify any of the \c{config.c*} values this time? Because they are
inherited from those specified for \c{/tmp/hello-gcc5-release} when we created
the configuration with \c{bpkg create}. What about \c{config.import.libhello},
don't we need at least that? Not really \- \c{libhello} will be found
automatically since it is part of the same amalgamation.
Of course, \c{bpkg} has no idea \c{hello2} is now part of its configuration:
\
$ bpkg status -d /tmp/hello-gcc5-release/ hello2
unknown
\
This is what I meant when I said you can muck around in \c{bpkg}'s back yard as
long as you understand the implications.
But is there a way to make \c{bpkg} aware of our little project? You seem to
really have all the right questions today. Actually, there is a very good
reason why we would want that: if we upgrade \c{libhello} we would want
\c{bpkg} to automatically reconfigure our project. As it is now, we will have
to remember and do it ourselves.
The only way to make \c{bpkg} aware of \c{hello2} is to turn it from merely a
\c{build2} \i{project} into a \c{build2} \i{package}. While the topic of
packaging is also for another time and place (the \c{build2} package manager
manual), we can get away with something as simple as this:
\
$ cat >hello2/manifest
: 1
name: hello2
version: 1.0.0
summary: Improved \"Hello World\" program
license: proprietary
url: http://example.org/hello2
email: hello2@example.org
depends: libhello >= 1.0.0
\
For our purposes, the only really important value in this manifest is
\c{depends} since it tells \c{bpkg} which package(s) we need. Let's give it a
try. But first we will clean up our previous attempt at building \c{hello2}
inside \c{/tmp/hello-gcc5-release/}:
\
$ b '{clean disfigure}(/tmp/hello-gcc5-release/hello2/)'
rm /tmp/hello-gcc5-release/hello2/exe{hello}
rm /tmp/hello-gcc5-release/hello2/obje{hello}
rm /tmp/hello-gcc5-release/hello2/build/config.build
rmdir /tmp/hello-gcc5-release/hello2/
\
Next, we use the \l{bpkg-pkg-build(1) \c{bpkg build}} command but instead of
giving it a package name like we did before, we will point it to our \c{hello2}
package directory (\c{bpkg} can fetch packages or it can build local package
archives or package directories):
\
$ bpkg build -d /tmp/hello-gcc5-release/ ./hello2/
build hello2/1.0.0
continue? [Y/n] y
unpacked hello2/1.0.0
configured hello2/1.0.0
c++ hello2/cxx{hello}@/tmp/hello-gcc5-release/hello2-1.0.0/
ld /tmp/hello-gcc5-release/hello2-1.0.0/exe{hello}
updated hello2/1.0.0
\
Let's upgrade \c{libhello} and see what happens:
\
$ bpkg build -d /tmp/hello-gcc5-release/ -L libhello
build libformat/1.0.0 (required by libhello)
build libprint/1.0.0 (required by libhello)
upgrade libhello/1.1.0
reconfigure hello2 (dependent of libhello)
continue? [Y/n] y
disfigured hello2/1.0.0
disfigured libhello/1.0.0
[ ... fetching & unpacking ... ]
configured libformat/1.0.0
configured libprint/1.0.0
configured libhello/1.1.0
configured hello2/1.0.0
[ ... updating libprint, libformat, and libhello ... ]
updated libhello/1.1.0
\
As promised, \c{hello2} got reconfigured (it didn't get updated because of the
\c{-L} option). We can now update it and give it a try:
\
$ bpkg update -d /tmp/hello-gcc5-release/ hello2
c++ hello2/cxx{hello}@/tmp/hello-gcc5-release/hello2-1.0.0/
ld /tmp/hello-gcc5-release/hello2-1.0.0/exe{hello}
updated hello2/1.0.0
$ /tmp/hello-gcc5-release/hello2-1.0.0/hello
Hello, World!
\
To finish off, let's see how hard it will be to get a Clang build going:
\
$ cd /tmp
$ mkdir hello-clang36-release
$ cd hello-clang36-release
$ bpkg create cc config.cxx=clang++-3.6 config.cc.coptions=-O3
created new configuration in /tmp/hello-clang36-release/
$ bpkg add https://build2.org/pkg/1/hello/testing
added repository build2.org/hello/testing
$ bpkg fetch
fetching build2.org/hello/testing
[... certificate authentication ...]
fetching build2.org/hello/stable (complements build2.org/hello/testing)
5 package(s) in 2 repository(s)
$ bpkg build libhello/1.0.0 path/to/hello2/
build libhello/1.0.0
build hello2/1.0.0
continue? [Y/n] y
libhello-1.0.0.tar.gz 100% of 2428 B 983 kBps 00m01s
fetched libhello/1.0.0
unpacked libhello/1.0.0
unpacked hello2/1.0.0
configured libhello/1.0.0
configured hello2/1.0.0
c++ libhello-1.0.0/hello/cxx{hello}
ld libhello-1.0.0/hello/liba{hello}
c++ libhello-1.0.0/hello/cxx{hello}
ld libhello-1.0.0/hello/libs{hello}
c++ libhello-1.0.0/tests/test/cxx{driver}
ld libhello-1.0.0/tests/test/exe{driver}
c++ /path/to/hello2/cxx{hello}@hello2-1.0.0/
ld hello2-1.0.0/exe{hello}
updated libhello/1.0.0
updated hello2/1.0.0
\
Are you still there? Ok, one last example. Let's see how hard it is to
cross-compile.
\
$ mkdir hello-mingw64
$ cd hello-mingw64
$ bpkg create cc config.cxx=x86_64-w64-mingw32-g++
created new configuration in /tmp/hello-mingw64/
$ bpkg add https://build2.org/pkg/1/hello/stable
added repository build2.org/hello/stable
$ bpkg fetch
fetching build2.org/hello/stable
[... certificate authentication ...]
2 package(s) in 1 repository(s)
$ bpkg build -y hello
libhello-1.0.0.tar.gz 100% of 2428 B 983 kBps 00m01s
fetched libhello/1.0.0
unpacked libhello/1.0.0
hello-1.0.0.tar.gz 100% of 1057 B 6882 kBps 00m01s
fetched hello/1.0.0
unpacked hello/1.0.0
configured libhello/1.0.0
configured hello/1.0.0
c++ hello-1.0.0/cxx{hello}
c++ libhello-1.0.0/hello/cxx{hello}
ld libhello-1.0.0/hello/libs{hello}
ld hello-1.0.0/exe{hello}
updated hello/1.0.0
$ wine hello-1.0.0/hello.exe Windows
Hello, Windows!
\
In fact, on a properly setup GNU/Linux machine (that automatically uses
\c{wine} as an \c{.exe} interpreter) we can even run tests:
\
$ bpkg test libhello hello
c++ libhello-1.0.0/tests/test/cxx{driver}
ld libhello-1.0.0/tests/test/exe{driver}
test libhello-1.0.0/tests/test/exe{driver}
test hello-1.0.0/exe{hello}
tested libhello/1.0.0
tested hello/1.0.0
\
"
|